forked from PuqiAR/Fig-TreeWalker
[Feat] 详细区分左值(LvObject)与右值(RvObject -> ObjectPtr)
[Impl] 重构evaluator.cpp + hpp 全部 [Feat] 增加对于IndexExpr的解析 [Fix][Impl] 现在点运算符不由BinaryExpr负责,增加MemberExpr,单独实现解析 [Impl] 项目目录全部翻修, src/目录下单独文件夹放置每一个模块
This commit is contained in:
937
src/Parser/parser.cpp
Normal file
937
src/Parser/parser.cpp
Normal file
@@ -0,0 +1,937 @@
|
||||
#include <Parser/parser.hpp>
|
||||
|
||||
namespace Fig
|
||||
{
|
||||
// Operator : pair<LeftBindingPower, RightBindingPower>
|
||||
|
||||
const std::unordered_map<Ast::Operator, std::pair<Parser::Precedence, Parser::Precedence>> Parser::opPrecedence = {
|
||||
// 算术
|
||||
{Ast::Operator::Add, {10, 11}},
|
||||
{Ast::Operator::Subtract, {10, 11}},
|
||||
{Ast::Operator::Multiply, {20, 21}},
|
||||
{Ast::Operator::Divide, {20, 21}},
|
||||
{Ast::Operator::Modulo, {20, 21}},
|
||||
{Ast::Operator::Power, {30, 29}},
|
||||
|
||||
// 逻辑
|
||||
{Ast::Operator::And, {5, 6}},
|
||||
{Ast::Operator::Or, {4, 5}},
|
||||
{Ast::Operator::Not, {30, 31}}, // 一元
|
||||
|
||||
// 比较
|
||||
{Ast::Operator::Equal, {7, 8}},
|
||||
{Ast::Operator::NotEqual, {7, 8}},
|
||||
{Ast::Operator::Less, {8, 9}},
|
||||
{Ast::Operator::LessEqual, {8, 9}},
|
||||
{Ast::Operator::Greater, {8, 9}},
|
||||
{Ast::Operator::GreaterEqual, {8, 9}},
|
||||
|
||||
// 位运算
|
||||
{Ast::Operator::BitAnd, {6, 7}},
|
||||
{Ast::Operator::BitOr, {4, 5}},
|
||||
{Ast::Operator::BitXor, {5, 6}},
|
||||
{Ast::Operator::BitNot, {30, 31}}, // 一元
|
||||
{Ast::Operator::ShiftLeft, {15, 16}},
|
||||
{Ast::Operator::ShiftRight, {15, 16}},
|
||||
|
||||
{Ast::Operator::Assign, {2, 1}}, // 右结合
|
||||
|
||||
// 海象运算符
|
||||
// {Ast::Operator::Walrus, {2, 1}}, // 右结合
|
||||
|
||||
// // 点运算符
|
||||
// {Ast::Operator::Dot, {40, 41}},
|
||||
};
|
||||
|
||||
Ast::VarDef Parser::__parseVarDef(bool isPublic)
|
||||
{
|
||||
// entry: current is keyword `var` or `const`
|
||||
bool isConst = (currentToken().getType() == TokenType::Const ? true : false);
|
||||
next();
|
||||
expect(TokenType::Identifier);
|
||||
FString name = currentToken().getValue();
|
||||
next();
|
||||
FString tiName = ValueType::Any.name;
|
||||
bool hasSpecificType = false;
|
||||
if (isThis(TokenType::Colon)) // :
|
||||
{
|
||||
expectPeek(TokenType::Identifier, FString(u8"Type name"));
|
||||
next();
|
||||
tiName = currentToken().getValue();
|
||||
next();
|
||||
hasSpecificType = true;
|
||||
}
|
||||
if (isThis(TokenType::Semicolon))
|
||||
{
|
||||
next(); // consume `;`, no using expectConsume here cause we don't need to check again
|
||||
return makeAst<Ast::VarDefAst>(isPublic, isConst, name, tiName, nullptr);
|
||||
}
|
||||
if (!isThis(TokenType::Assign) and !isThis(TokenType::Walrus)) expect(TokenType::Assign, u8"assign or walrus");
|
||||
if (isThis(TokenType::Walrus))
|
||||
{
|
||||
if (hasSpecificType) throwAddressableError<SyntaxError>(FStringView(u8""));
|
||||
tiName = Parser::varDefTypeFollowed;
|
||||
}
|
||||
next();
|
||||
Ast::Expression exp = parseExpression(0);
|
||||
expectSemicolon();
|
||||
return makeAst<Ast::VarDefAst>(isPublic, isConst, name, tiName, exp);
|
||||
}
|
||||
|
||||
ObjectPtr Parser::__parseValue()
|
||||
{
|
||||
FString _val = currentToken().getValue();
|
||||
if (currentToken().getType() == TokenType::LiteralNumber)
|
||||
{
|
||||
if (_val.contains(u8'.') || _val.contains(u8'e'))
|
||||
{
|
||||
// 非整数
|
||||
ValueType::DoubleClass d;
|
||||
try
|
||||
{
|
||||
d = std::stod(_val.toBasicString());
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
throwAddressableError<SyntaxError>(FStringView(u8"Illegal number literal"));
|
||||
}
|
||||
return std::make_shared<Object>(d);
|
||||
}
|
||||
else
|
||||
{
|
||||
// 整数
|
||||
ValueType::IntClass i;
|
||||
try
|
||||
{
|
||||
i = std::stoi(_val.toBasicString());
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
throwAddressableError<SyntaxError>(FStringView(u8"Illegal number literal"));
|
||||
}
|
||||
return std::make_shared<Object>(i);
|
||||
}
|
||||
}
|
||||
else if (currentToken().getType() == TokenType::LiteralString)
|
||||
{
|
||||
return std::make_shared<Object>(_val);
|
||||
}
|
||||
else if (currentToken().getType() == TokenType::LiteralBool)
|
||||
{
|
||||
return std::make_shared<Object>((_val == u8"true" ? true : false));
|
||||
}
|
||||
else if (currentToken().getType() == TokenType::LiteralNull)
|
||||
{
|
||||
return Object::getNullInstance();
|
||||
}
|
||||
else
|
||||
{
|
||||
throw std::runtime_error(std::string("Internal Error at: ") + std::string(__func__));
|
||||
}
|
||||
}
|
||||
|
||||
Ast::ValueExpr Parser::__parseValueExpr()
|
||||
{
|
||||
return makeAst<Ast::ValueExprAst> (__parseValue());
|
||||
}
|
||||
Ast::FunctionParameters Parser::__parseFunctionParameters()
|
||||
{
|
||||
// entry: current is Token::LeftParen
|
||||
// stop: current is `)` next one
|
||||
// *note: must called when parsing function
|
||||
|
||||
next(); // skip `(`
|
||||
|
||||
Ast::FunctionParameters::PosParasType pp;
|
||||
Ast::FunctionParameters::DefParasType dp;
|
||||
while (true)
|
||||
{
|
||||
if (isThis(TokenType::RightParen))
|
||||
{
|
||||
next();
|
||||
return Ast::FunctionParameters(pp, dp);
|
||||
}
|
||||
expect(TokenType::Identifier, FString(u8"Identifier or `)`")); // check current
|
||||
FString pname = currentToken().getValue();
|
||||
next(); // skip pname
|
||||
if (isThis(TokenType::Assign)) // =
|
||||
{
|
||||
next();
|
||||
dp.push_back({pname, {ValueType::Any.name, parseExpression(0, TokenType::Comma)}});
|
||||
if (isThis(TokenType::Comma))
|
||||
{
|
||||
next(); // only skip `,` when it's there
|
||||
}
|
||||
}
|
||||
else if (isThis(TokenType::Colon)) // :
|
||||
{
|
||||
next(); // skip `:`
|
||||
expect(TokenType::Identifier, FString(u8"Type name"));
|
||||
FString ti(currentToken().getValue());
|
||||
next(); // skip type name
|
||||
if (isThis(TokenType::Assign)) // =
|
||||
{
|
||||
next(); // skip `=`
|
||||
dp.push_back({pname, {ti, parseExpression(0, TokenType::Comma)}});
|
||||
if (isThis(TokenType::Comma))
|
||||
{
|
||||
next(); // only skip `,` when it's there
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
pp.push_back({pname, ti});
|
||||
if (isThis(TokenType::Comma))
|
||||
{
|
||||
next(); // only skip `,` when it's there
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
pp.push_back({pname, ValueType::Any.name});
|
||||
if (isThis(TokenType::Comma))
|
||||
{
|
||||
next(); // only skip `,` when it's there
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
Ast::FunctionDef Parser::__parseFunctionDef(bool isPublic)
|
||||
{
|
||||
FString funcName = currentToken().getValue();
|
||||
next();
|
||||
expect(TokenType::LeftParen);
|
||||
Ast::FunctionParameters params = __parseFunctionParameters();
|
||||
FString retTiName = ValueType::Any.name;
|
||||
if (isThis(TokenType::RightArrow)) // ->
|
||||
{
|
||||
next(); // skip `->`
|
||||
expect(TokenType::Identifier);
|
||||
retTiName = currentToken().getValue();
|
||||
next(); // skip return type
|
||||
}
|
||||
expect(TokenType::LeftBrace);
|
||||
Ast::BlockStatement body = __parseBlockStatement();
|
||||
return makeAst<Ast::FunctionDefSt>(funcName, params, isPublic, retTiName, body);
|
||||
}
|
||||
Ast::StructDef Parser::__parseStructDef(bool isPublic)
|
||||
{
|
||||
// entry: current is struct name
|
||||
FString structName = currentToken().getValue();
|
||||
next();
|
||||
expect(TokenType::LeftBrace, u8"struct body");
|
||||
next();
|
||||
bool braceClosed = false;
|
||||
|
||||
/*
|
||||
public name
|
||||
public const name
|
||||
public final name
|
||||
|
||||
const name
|
||||
final name
|
||||
|
||||
name
|
||||
*/
|
||||
|
||||
auto __parseStructField = [this](bool isPublic) -> Ast::StructDefField {
|
||||
AccessModifier am = AccessModifier::Normal;
|
||||
FString fieldName;
|
||||
if (isThis(TokenType::Identifier))
|
||||
{
|
||||
fieldName = currentToken().getValue();
|
||||
next();
|
||||
am = (isPublic ? AccessModifier::Public : AccessModifier::Normal);
|
||||
}
|
||||
else if (isThis(TokenType::Const))
|
||||
{
|
||||
next();
|
||||
expect(TokenType::Identifier, u8"field name");
|
||||
fieldName = currentToken().getValue();
|
||||
am = (isPublic ? AccessModifier::PublicConst : AccessModifier::Const);
|
||||
}
|
||||
else
|
||||
{
|
||||
throwAddressableError<SyntaxError>(FStringView(std::format("expect field name or field attribute")));
|
||||
}
|
||||
FString tiName = ValueType::Any.name;
|
||||
if (isThis(TokenType::Colon))
|
||||
{
|
||||
next();
|
||||
expect(TokenType::Identifier, u8"type name");
|
||||
tiName = currentToken().getValue();
|
||||
next();
|
||||
}
|
||||
Ast::Expression initExpr = nullptr;
|
||||
if (isThis(TokenType::Assign))
|
||||
{
|
||||
next();
|
||||
if (isEOF()) throwAddressableError<SyntaxError>(FStringView(u8"expect an expression"));
|
||||
initExpr = parseExpression(0);
|
||||
}
|
||||
expectSemicolon();
|
||||
return Ast::StructDefField(am, fieldName, tiName, initExpr);
|
||||
};
|
||||
std::vector<Ast::Statement> stmts;
|
||||
std::vector<Ast::StructDefField> fields;
|
||||
|
||||
while (!isEOF())
|
||||
{
|
||||
if (isThis(TokenType::RightBrace))
|
||||
{
|
||||
braceClosed = true;
|
||||
next(); // consume `}`
|
||||
break;
|
||||
}
|
||||
if (isThis(TokenType::Identifier))
|
||||
{
|
||||
fields.push_back(__parseStructField(false));
|
||||
}
|
||||
else if (isThis(TokenType::Public))
|
||||
{
|
||||
if (isNext(TokenType::Const))
|
||||
{
|
||||
next();
|
||||
fields.push_back(__parseStructField(true));
|
||||
}
|
||||
else if (isNext(TokenType::Function))
|
||||
{
|
||||
next(); // consume `public`
|
||||
next(); // consume `function`
|
||||
stmts.push_back(__parseFunctionDef(true));
|
||||
}
|
||||
else if (isNext(TokenType::Struct))
|
||||
{
|
||||
next(); // consume `public`
|
||||
next(); // consume `struct`
|
||||
stmts.push_back(__parseStructDef(true));
|
||||
}
|
||||
else if (isNext(TokenType::Identifier))
|
||||
{
|
||||
next(); // consume `public`
|
||||
fields.push_back(__parseStructField(true));
|
||||
}
|
||||
else
|
||||
{
|
||||
throwAddressableError<SyntaxError>(FStringView("Invalid syntax"));
|
||||
}
|
||||
}
|
||||
else if (isThis(TokenType::Function))
|
||||
{
|
||||
next();
|
||||
stmts.push_back(__parseFunctionDef(false));
|
||||
}
|
||||
else if (isThis(TokenType::Struct))
|
||||
{
|
||||
next(); // consume `struct`
|
||||
stmts.push_back(__parseStructDef(false));
|
||||
}
|
||||
else if (isThis(TokenType::Const))
|
||||
{
|
||||
fields.push_back(__parseStructField(false));
|
||||
}
|
||||
else if (isThis(TokenType::Variable))
|
||||
{
|
||||
throwAddressableError<SyntaxError>(FStringView("Variables are not allowed to be defined within a structure."));
|
||||
}
|
||||
else
|
||||
{
|
||||
throwAddressableError<SyntaxError>(FStringView("Invalid syntax"));
|
||||
}
|
||||
}
|
||||
if (!braceClosed)
|
||||
{
|
||||
throwAddressableError<SyntaxError>(FStringView("braces are not closed"));
|
||||
}
|
||||
return makeAst<Ast::StructDefSt>(isPublic, structName, fields, makeAst<Ast::BlockStatementAst>(stmts));
|
||||
}
|
||||
Ast::Statement Parser::__parseStatement()
|
||||
{
|
||||
Ast::Statement stmt;
|
||||
if (isThis(TokenType::EndOfFile)) { return makeAst<Ast::EofStmt>(); }
|
||||
if (isThis(TokenType::Public))
|
||||
{
|
||||
next(); // consume `public`
|
||||
if (isThis(TokenType::Variable) || isThis(TokenType::Const))
|
||||
{
|
||||
stmt = __parseVarDef(true);
|
||||
}
|
||||
else if (isThis(TokenType::Function) and isNext(TokenType::Identifier))
|
||||
{
|
||||
next();
|
||||
stmt = __parseFunctionDef(true);
|
||||
}
|
||||
else if (isThis(TokenType::Struct))
|
||||
{
|
||||
stmt = __parseStructDef(true);
|
||||
}
|
||||
else
|
||||
{
|
||||
throwAddressableError<SyntaxError>(FStringView(u8"Expected `var`, `const`, `function` or `struct` after `public`"));
|
||||
}
|
||||
}
|
||||
else if (isThis(TokenType::Variable) || isThis(TokenType::Const))
|
||||
{
|
||||
stmt = __parseVarDef(false);
|
||||
}
|
||||
else if (isThis(TokenType::Function) and isNext(TokenType::Identifier))
|
||||
{
|
||||
next();
|
||||
stmt = __parseFunctionDef(false);
|
||||
}
|
||||
else if (isThis(TokenType::Struct))
|
||||
{
|
||||
expectPeek(TokenType::Identifier, u8"struct name");
|
||||
next();
|
||||
stmt = __parseStructDef(false);
|
||||
}
|
||||
else if (isThis(TokenType::If))
|
||||
{
|
||||
stmt = __parseIf();
|
||||
}
|
||||
else if (isThis(TokenType::Else))
|
||||
{
|
||||
throwAddressableError<SyntaxError>(FStringView(u8"`else` without matching `if`"));
|
||||
}
|
||||
else if (isThis(TokenType::LeftBrace))
|
||||
{
|
||||
stmt = __parseBlockStatement();
|
||||
}
|
||||
else if (isThis(TokenType::While))
|
||||
{
|
||||
stmt = __parseWhile();
|
||||
}
|
||||
else if (isThis(TokenType::For))
|
||||
{
|
||||
stmt = __parseFor();
|
||||
}
|
||||
else if (isThis(TokenType::Return))
|
||||
{
|
||||
stmt = __parseReturn();
|
||||
}
|
||||
else if (isThis(TokenType::Break))
|
||||
{
|
||||
stmt = __parseBreak();
|
||||
}
|
||||
else if (isThis(TokenType::Continue))
|
||||
{
|
||||
stmt = __parseContinue();
|
||||
}
|
||||
else
|
||||
{
|
||||
// expression statement
|
||||
Ast::Expression exp = parseExpression(0);
|
||||
expectSemicolon();
|
||||
stmt = makeAst<Ast::ExpressionStmtAst>(exp);
|
||||
}
|
||||
return stmt;
|
||||
}
|
||||
Ast::BlockStatement Parser::__parseBlockStatement()
|
||||
{
|
||||
// entry: current is `{`
|
||||
// stop: current is `}` next one
|
||||
next(); // consume `{`
|
||||
std::vector<Ast::Statement> stmts;
|
||||
while (true)
|
||||
{
|
||||
if (isThis(TokenType::RightBrace))
|
||||
{
|
||||
next();
|
||||
return makeAst<Ast::BlockStatementAst>(stmts);
|
||||
}
|
||||
stmts.push_back(__parseStatement());
|
||||
}
|
||||
}
|
||||
Ast::If Parser::__parseIf()
|
||||
{
|
||||
// entry: current is `if`
|
||||
next(); // consume `if`
|
||||
Ast::Expression condition;
|
||||
if (isThis(TokenType::LeftParen))
|
||||
{
|
||||
next(); // consume `(`
|
||||
condition = parseExpression(0, TokenType::RightParen);
|
||||
expect(TokenType::RightParen);
|
||||
next(); // consume `)`
|
||||
}
|
||||
else
|
||||
{
|
||||
condition = parseExpression(0);
|
||||
}
|
||||
// parenthesis is not required
|
||||
expect(TokenType::LeftBrace); // {
|
||||
Ast::BlockStatement body = __parseBlockStatement();
|
||||
std::vector<Ast::ElseIf> elifs;
|
||||
Ast::Else els = nullptr;
|
||||
while (isThis(TokenType::Else))
|
||||
{
|
||||
next(); // consume `else`
|
||||
if (isThis(TokenType::If))
|
||||
{
|
||||
// else if
|
||||
next(); // consume `if`
|
||||
Ast::Expression elifCondition = parseExpression(0);
|
||||
expect(TokenType::LeftBrace); // {
|
||||
Ast::BlockStatement elifBody = __parseBlockStatement();
|
||||
elifs.push_back(makeAst<Ast::ElseIfSt>(elifCondition, elifBody));
|
||||
}
|
||||
else
|
||||
{
|
||||
expect(TokenType::LeftBrace); // {
|
||||
Ast::BlockStatement elseBody = __parseBlockStatement();
|
||||
els = makeAst<Ast::ElseSt>(elseBody);
|
||||
break;
|
||||
}
|
||||
}
|
||||
return makeAst<Ast::IfSt>(condition, body, elifs, els);
|
||||
}
|
||||
Ast::While Parser::__parseWhile()
|
||||
{
|
||||
// entry: current is `while`
|
||||
next(); // consume `while`
|
||||
Ast::Expression condition = parseExpression(0);
|
||||
expect(TokenType::LeftBrace); // {
|
||||
Ast::BlockStatement body = __parseBlockStatement();
|
||||
return makeAst<Ast::WhileSt>(condition, body);
|
||||
}
|
||||
Ast::Statement Parser::__parseIncrementStatement()
|
||||
{
|
||||
// allowed:
|
||||
// 1. assignment:i = 1, i += 1
|
||||
// 2. expression stmt:i++, foo()
|
||||
// ❌ not allowed:if/while/for/block stmt
|
||||
|
||||
if (isThis(TokenType::LeftBrace))
|
||||
{
|
||||
throwAddressableError<SyntaxError>(u8"BlockStatement cannot be used as for loop increment");
|
||||
}
|
||||
|
||||
if (isThis(TokenType::If) || isThis(TokenType::While) || isThis(TokenType::For) || isThis(TokenType::Return) || isThis(TokenType::Break) || isThis(TokenType::Continue))
|
||||
{
|
||||
throwAddressableError<SyntaxError>(u8"Control flow statements cannot be used as for loop increment");
|
||||
}
|
||||
|
||||
return __parseStatement();
|
||||
}
|
||||
Ast::For Parser::__parseFor()
|
||||
{
|
||||
// entry: current is `for`
|
||||
// TODO: support enumeration
|
||||
next(); // consume `for`
|
||||
bool paren = isThis(TokenType::LeftParen);
|
||||
if (paren)
|
||||
next(); // consume `(`
|
||||
// support 3-part for loop
|
||||
// for init; condition; increment {}
|
||||
Ast::Statement initStmt = __parseStatement(); // auto check ``
|
||||
Ast::Expression condition = parseExpression(0);
|
||||
expectSemicolon(); // auto consume `;`
|
||||
|
||||
Ast::Statement incrementStmt = nullptr;
|
||||
if (!isThis(paren ? TokenType::RightParen : TokenType::LeftBrace)) // need parse increment?
|
||||
{
|
||||
auto guard = disableSemicolon();
|
||||
incrementStmt = __parseIncrementStatement();
|
||||
} // after parse increment, semicolon check state restored
|
||||
if (paren)
|
||||
expectConsume(TokenType::RightParen); // consume `)` if has `(`
|
||||
expect(TokenType::LeftBrace); // {
|
||||
Ast::BlockStatement body = __parseBlockStatement(); // auto consume `}`
|
||||
return makeAst<Ast::ForSt>(initStmt, condition, incrementStmt, body);
|
||||
}
|
||||
Ast::Return Parser::__parseReturn()
|
||||
{
|
||||
// entry: current is `return`
|
||||
next(); // consume `return`
|
||||
Ast::Expression retValue = parseExpression(0);
|
||||
expectSemicolon();
|
||||
return makeAst<Ast::ReturnSt>(retValue);
|
||||
}
|
||||
Ast::Continue Parser::__parseContinue()
|
||||
{
|
||||
// entry: current is `continue`
|
||||
next(); // consume `continue`
|
||||
expectSemicolon();
|
||||
return makeAst<Ast::ContinueSt>();
|
||||
}
|
||||
Ast::Break Parser::__parseBreak()
|
||||
{
|
||||
// entry: current is `break`
|
||||
next(); // consume `break`
|
||||
expectSemicolon();
|
||||
return makeAst<Ast::BreakSt>();
|
||||
}
|
||||
|
||||
Ast::VarExpr Parser::__parseVarExpr(FString name)
|
||||
{
|
||||
return makeAst<Ast::VarExprAst>(name);
|
||||
}
|
||||
|
||||
Ast::UnaryExpr Parser::__parsePrefix(Ast::Operator op, Precedence bp)
|
||||
{
|
||||
return makeAst<Ast::UnaryExprAst>(op, parseExpression(bp));
|
||||
}
|
||||
Ast::BinaryExpr Parser::__parseInfix(Ast::Expression lhs, Ast::Operator op, Precedence bp)
|
||||
{
|
||||
return makeAst<Ast::BinaryExprAst>(lhs, op, parseExpression(bp));
|
||||
}
|
||||
|
||||
Ast::Expression Parser::__parseCall(Ast::Expression callee)
|
||||
{
|
||||
next(); // consume '('
|
||||
std::vector<Ast::Expression> args;
|
||||
|
||||
if (!isThis(TokenType::RightParen))
|
||||
{
|
||||
while (true)
|
||||
{
|
||||
args.push_back(parseExpression(0, TokenType::Comma, TokenType::RightParen));
|
||||
|
||||
if (isThis(TokenType::Comma))
|
||||
{
|
||||
next();
|
||||
continue;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
expect(TokenType::RightParen);
|
||||
next(); // consume ')'
|
||||
|
||||
return makeAst<Ast::FunctionCallExpr>(callee, Ast::FunctionArguments(args));
|
||||
}
|
||||
|
||||
Ast::ListExpr Parser::__parseListExpr()
|
||||
{
|
||||
// entry: current is `[`
|
||||
next(); // consume `[`
|
||||
std::vector<Ast::Expression> val;
|
||||
while (!isThis(TokenType::RightBracket))
|
||||
{
|
||||
val.push_back(parseExpression(0, TokenType::RightBracket, TokenType::Comma));
|
||||
if (isThis(TokenType::Comma))
|
||||
{
|
||||
next(); // consume `,`
|
||||
}
|
||||
}
|
||||
expect(TokenType::RightBracket);
|
||||
next(); // consume `]`
|
||||
return makeAst<Ast::ListExprAst>(val);
|
||||
}
|
||||
|
||||
Ast::MapExpr Parser::__parseMapExpr()
|
||||
{
|
||||
// entry: current is `{`
|
||||
next(); // consume `{`
|
||||
std::map<FString, Ast::Expression> val;
|
||||
while (!isThis(TokenType::RightBrace))
|
||||
{
|
||||
expect(TokenType::Identifier, FString(u8"key (identifier)"));
|
||||
FString key = currentToken().getValue();
|
||||
if (val.contains(key)) throwAddressableError<SyntaxError>(FStringView(std::format(
|
||||
"Redefinition of immutable key {} in mapping literal",
|
||||
key.toBasicString())));
|
||||
next(); // consume key
|
||||
expect(TokenType::Colon);
|
||||
next(); // consume `:`
|
||||
val[key] = parseExpression(0, TokenType::RightBrace, TokenType::Comma);
|
||||
if (isThis(TokenType::Comma))
|
||||
{
|
||||
next(); // consume `,`
|
||||
}
|
||||
}
|
||||
expect(TokenType::RightBrace);
|
||||
next(); // consume `}`
|
||||
return makeAst<Ast::MapExprAst>(val);
|
||||
}
|
||||
|
||||
Ast::InitExpr Parser::__parseInitExpr(FString structName)
|
||||
{
|
||||
// entry: current is `{`
|
||||
next(); // consume `{`
|
||||
std::vector<std::pair<FString, Ast::Expression>> args;
|
||||
/*
|
||||
3 ways of calling constructor
|
||||
.1 Person {"Fig", 1, "IDK"};
|
||||
.2 Person {name: "Fig", age: 1, sex: "IDK"}; // can be unordered
|
||||
.3 Person {name, age, sex};
|
||||
*/
|
||||
uint8_t mode; // 0=undetermined, 1=positional, 2=named, 3=shorthand
|
||||
|
||||
while (!isThis(TokenType::RightBrace))
|
||||
{
|
||||
if (mode == 0)
|
||||
{
|
||||
if (isThis(TokenType::Identifier) && isNext(TokenType::Colon))
|
||||
{
|
||||
mode = 2;
|
||||
}
|
||||
else if (isThis(TokenType::Identifier) && (isNext(TokenType::Comma) || isNext(TokenType::RightBrace)))
|
||||
{
|
||||
mode = 3;
|
||||
}
|
||||
else
|
||||
{
|
||||
mode = 1;
|
||||
}
|
||||
}
|
||||
|
||||
if (mode == 1)
|
||||
{
|
||||
// 1 Person {"Fig", 1, "IDK"};
|
||||
Ast::Expression expr = parseExpression(0, TokenType::Comma, TokenType::RightBrace);
|
||||
args.push_back({FString(), std::move(expr)});
|
||||
}
|
||||
else if (mode == 2)
|
||||
{
|
||||
// 2 Person {name: "Fig", age: 1, sex: "IDK"};
|
||||
expect(TokenType::Identifier);
|
||||
FString fieldName = currentToken().getValue();
|
||||
next(); // consume identifier
|
||||
expect(TokenType::Colon);
|
||||
next(); // consume colon
|
||||
Ast::Expression expr = parseExpression(0, TokenType::Comma, TokenType::RightBrace);
|
||||
args.push_back({fieldName, std::move(expr)});
|
||||
}
|
||||
else if (mode == 3)
|
||||
{
|
||||
// 3 Person {name, age, sex};
|
||||
expect(TokenType::Identifier);
|
||||
FString fieldName = currentToken().getValue();
|
||||
Ast::Expression expr = makeAst<Ast::VarExprAst>(fieldName);
|
||||
args.push_back({fieldName, std::move(expr)});
|
||||
next(); // consume identifier
|
||||
}
|
||||
|
||||
if (isThis(TokenType::Comma))
|
||||
{
|
||||
next(); // consume comma
|
||||
}
|
||||
else if (!isThis(TokenType::RightBrace))
|
||||
{
|
||||
throwAddressableError<SyntaxError>(FStringView(
|
||||
std::format("Expect `,` or `}}` in struct initialization expression, got {}",
|
||||
currentToken().toString().toBasicString())
|
||||
));
|
||||
}
|
||||
}
|
||||
expect(TokenType::RightBrace);
|
||||
next(); // consume `}`
|
||||
return makeAst<Ast::InitExprAst>(structName, args,
|
||||
(mode == 1 ? Ast::InitExprAst::InitMode::Positional :
|
||||
(mode == 2 ? Ast::InitExprAst::InitMode::Named : Ast::InitExprAst::InitMode::Shorthand)));
|
||||
}
|
||||
Ast::Expression Parser::__parseTupleOrParenExpr()
|
||||
{
|
||||
next();
|
||||
|
||||
if (currentToken().getType() == TokenType::RightParen)
|
||||
{
|
||||
next(); // consume ')'
|
||||
return makeAst<Ast::TupleExprAst>();
|
||||
}
|
||||
|
||||
Ast::Expression firstExpr = parseExpression(0);
|
||||
|
||||
if (currentToken().getType() == TokenType::Comma)
|
||||
{
|
||||
std::vector<Ast::Expression> elements;
|
||||
elements.push_back(firstExpr);
|
||||
|
||||
while (currentToken().getType() == TokenType::Comma)
|
||||
{
|
||||
next(); // consume ','
|
||||
|
||||
if (currentToken().getType() == TokenType::RightParen)
|
||||
break;
|
||||
|
||||
elements.push_back(parseExpression(0));
|
||||
}
|
||||
|
||||
expect(TokenType::RightParen);
|
||||
next(); // consume ')'
|
||||
|
||||
return makeAst<Ast::TupleExprAst>(std::move(elements));
|
||||
}
|
||||
else if (currentToken().getType() == TokenType::RightParen)
|
||||
{
|
||||
next(); // consume ')'
|
||||
return firstExpr;
|
||||
}
|
||||
else
|
||||
{
|
||||
throwAddressableError<SyntaxError>(FStringView(u8"Expect ')' or ',' after expression in parentheses"));
|
||||
}
|
||||
return nullptr; // to suppress compiler warning
|
||||
}
|
||||
|
||||
Ast::FunctionLiteralExpr Parser::__parseFunctionLiteralExpr()
|
||||
{
|
||||
// entry: current is Token::LeftParen and last is Token::Function
|
||||
/*
|
||||
Function literal:
|
||||
func (params){...}
|
||||
or
|
||||
func (params) => <expression>
|
||||
*/
|
||||
Ast::FunctionParameters params = __parseFunctionParameters();
|
||||
if (isThis(TokenType::DoubleArrow)) // =>
|
||||
{
|
||||
next();
|
||||
Ast::Expression bodyExpr = parseExpression(0);
|
||||
return makeAst<Ast::FunctionLiteralExprAst>(params, bodyExpr);
|
||||
}
|
||||
expect(TokenType::LeftBrace); // `{`
|
||||
return makeAst<Ast::FunctionLiteralExprAst>(params, __parseBlockStatement());
|
||||
}
|
||||
|
||||
Ast::Expression Parser::parseExpression(Precedence bp, TokenType stop, TokenType stop2)
|
||||
{
|
||||
Ast::Expression lhs;
|
||||
Ast::Operator op;
|
||||
|
||||
Token tok = currentToken();
|
||||
if (tok == EOFTok)
|
||||
throwAddressableError<SyntaxError>(FStringView(u8"Unexpected end of expression"));
|
||||
if (tok.getType() == stop || tok.getType() == stop2)
|
||||
{
|
||||
if (lhs == nullptr) throwAddressableError<SyntaxError>(FStringView(u8"Expected expression"));
|
||||
return lhs;
|
||||
}
|
||||
if (tok.getType() == TokenType::LeftBracket)
|
||||
{
|
||||
lhs = __parseListExpr(); // auto consume
|
||||
}
|
||||
else if (tok.getType() == TokenType::LeftParen)
|
||||
{
|
||||
lhs = __parseTupleOrParenExpr(); // auto consume
|
||||
}
|
||||
else if (tok.getType() == TokenType::LeftBrace)
|
||||
{
|
||||
lhs = __parseMapExpr(); // auto consume
|
||||
}
|
||||
else if (tok.getType() == TokenType::Function)
|
||||
{
|
||||
next(); // consume `function`
|
||||
if (currentToken().getType() == TokenType::Identifier)
|
||||
{
|
||||
// err
|
||||
throwAddressableError<SyntaxError>(FStringView(u8"Function literal should not have a name"));
|
||||
}
|
||||
expect(TokenType::LeftParen);
|
||||
lhs = __parseFunctionLiteralExpr();
|
||||
}
|
||||
else if (tok.isLiteral())
|
||||
{
|
||||
lhs = __parseValueExpr();
|
||||
next();
|
||||
}
|
||||
else if (tok.isIdentifier())
|
||||
{
|
||||
FString id = tok.getValue();
|
||||
next();
|
||||
if (currentToken().getType() == TokenType::LeftBrace)
|
||||
{
|
||||
lhs = __parseInitExpr(id); // a_struct{init...}
|
||||
}
|
||||
else
|
||||
{
|
||||
lhs = __parseVarExpr(id);
|
||||
}
|
||||
}
|
||||
else if (isTokenOp(tok) && isOpUnary((op = Ast::TokenToOp.at(tok.getType()))))
|
||||
{
|
||||
// prefix
|
||||
next();
|
||||
lhs = __parsePrefix(op, getRightBindingPower(op));
|
||||
}
|
||||
else
|
||||
{
|
||||
throwAddressableError<SyntaxError>(FStringView(u8"Unexpected token in expression"));
|
||||
}
|
||||
|
||||
// infix / (postfix) ?
|
||||
while (true)
|
||||
{
|
||||
tok = currentToken();
|
||||
if (tok.getType() == TokenType::Semicolon || tok == EOFTok) break;
|
||||
|
||||
/* Postfix */
|
||||
|
||||
if (tok.getType() == TokenType::LeftParen)
|
||||
{
|
||||
lhs = __parseCall(lhs);
|
||||
continue;
|
||||
}
|
||||
|
||||
// member access: a.b
|
||||
if (tok.getType() == TokenType::Dot)
|
||||
{
|
||||
next(); // consume '.'
|
||||
Token idTok = currentToken();
|
||||
if (!idTok.isIdentifier())
|
||||
throwAddressableError<SyntaxError>(FStringView(u8"Expected identifier after '.'"));
|
||||
|
||||
FString member = idTok.getValue();
|
||||
next(); // consume identifier
|
||||
|
||||
lhs = makeAst<Ast::MemberExprAst>(lhs, member);
|
||||
continue;
|
||||
}
|
||||
// index: x[expr]
|
||||
if (tok.getType() == TokenType::LeftBracket)
|
||||
{
|
||||
next(); // consume '['
|
||||
auto indexExpr = parseExpression(0, TokenType::RightBracket);
|
||||
expect(TokenType::RightBracket);
|
||||
next(); // consume ']'
|
||||
|
||||
lhs = makeAst<Ast::IndexExprAst>(lhs, indexExpr);
|
||||
continue;
|
||||
}
|
||||
|
||||
// ternary
|
||||
if (tok.getType() == TokenType::Question)
|
||||
{
|
||||
next(); // consume ?
|
||||
Ast::Expression trueExpr = parseExpression(0, TokenType::Colon);
|
||||
expect(TokenType::Colon);
|
||||
next(); // consume :
|
||||
Ast::Expression falseExpr = parseExpression(0, TokenType::Semicolon, stop2);
|
||||
lhs = makeAst<Ast::TernaryExprAst>(lhs, trueExpr, falseExpr);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!isTokenOp(tok)) break;
|
||||
|
||||
op = Ast::TokenToOp.at(tok.getType());
|
||||
Precedence lbp = getLeftBindingPower(op);
|
||||
if (bp >= lbp) break;
|
||||
|
||||
next(); // consume op
|
||||
lhs = __parseInfix(lhs, op, getRightBindingPower(op));
|
||||
}
|
||||
|
||||
return lhs;
|
||||
}
|
||||
|
||||
std::vector<Ast::AstBase> Parser::parseAll()
|
||||
{
|
||||
output.clear();
|
||||
Token tok = currentToken();
|
||||
if (tok == EOFTok)
|
||||
{
|
||||
return output;
|
||||
}
|
||||
|
||||
// TODO: Package/Module Import Support
|
||||
while (!isEOF())
|
||||
{
|
||||
pushNode(__parseStatement());
|
||||
}
|
||||
return output;
|
||||
}
|
||||
|
||||
} // namespace Fig
|
||||
333
src/Parser/parser.hpp
Normal file
333
src/Parser/parser.hpp
Normal file
@@ -0,0 +1,333 @@
|
||||
#pragma once
|
||||
|
||||
#include <Ast/ast.hpp>
|
||||
#include <Lexer/lexer.hpp>
|
||||
#include <Core/fig_string.hpp>
|
||||
#include <Error/error.hpp>
|
||||
|
||||
#include <print>
|
||||
#include <unordered_map>
|
||||
|
||||
#include <stack>
|
||||
|
||||
namespace Fig
|
||||
{
|
||||
|
||||
class Parser
|
||||
{
|
||||
private:
|
||||
Lexer lexer;
|
||||
std::vector<Ast::AstBase> output;
|
||||
std::vector<Token> previousTokens;
|
||||
|
||||
size_t tokenPruduced = 0;
|
||||
size_t currentTokenIndex = 0;
|
||||
|
||||
std::unique_ptr<AddressableError> error;
|
||||
|
||||
Ast::AstAddressInfo currentAAI;
|
||||
|
||||
std::stack<Ast::Expression> exprStack;
|
||||
|
||||
bool needSemicolon = true;
|
||||
|
||||
class SemicolonDisabler
|
||||
{
|
||||
Parser *p;
|
||||
bool original;
|
||||
|
||||
public:
|
||||
SemicolonDisabler(Parser *parser) :
|
||||
p(parser), original(p->needSemicolon)
|
||||
{
|
||||
p->needSemicolon = false;
|
||||
}
|
||||
~SemicolonDisabler()
|
||||
{
|
||||
p->needSemicolon = original;
|
||||
}
|
||||
// disable copy and assign
|
||||
SemicolonDisabler(const SemicolonDisabler &) = delete;
|
||||
SemicolonDisabler &operator=(const SemicolonDisabler &) = delete;
|
||||
};
|
||||
|
||||
void pushNode(const Ast::AstBase &_node)
|
||||
{
|
||||
Ast::AstBase node = _node;
|
||||
node->setAAI(currentAAI);
|
||||
output.push_back(std::move(node));
|
||||
}
|
||||
void pushNode(const Ast::AstBase &_node, Ast::AstAddressInfo _aai)
|
||||
{
|
||||
Ast::AstBase node = _node;
|
||||
node->setAAI(_aai);
|
||||
output.push_back(node);
|
||||
}
|
||||
|
||||
bool isTokenSymbol(Token tok)
|
||||
{
|
||||
return Lexer::symbol_map.contains(tok.getValue());
|
||||
}
|
||||
bool isTokenOp(Token tok)
|
||||
{
|
||||
return Ast::TokenToOp.contains(tok.getType());
|
||||
}
|
||||
bool isEOF()
|
||||
{
|
||||
if (tokenPruduced == 0) return false;
|
||||
return currentToken() == EOFTok;
|
||||
}
|
||||
|
||||
public:
|
||||
using Precedence = uint32_t;
|
||||
static const std::unordered_map<Ast::Operator, std::pair<Precedence, Precedence>> opPrecedence;
|
||||
Parser(const Lexer &_lexer) :
|
||||
lexer(_lexer)
|
||||
{
|
||||
}
|
||||
|
||||
AddressableError* getError() const
|
||||
{
|
||||
return error.get();
|
||||
}
|
||||
|
||||
template <class _ErrT, typename = AddressableError>
|
||||
void throwAddressableError(FStringView msg, size_t line, size_t column, std::source_location loc = std::source_location::current())
|
||||
{
|
||||
static_assert(std::is_base_of_v<AddressableError, _ErrT>,
|
||||
"_ErrT must derive from AddressableError");
|
||||
_ErrT spError(msg, line, column, loc);
|
||||
error = std::make_unique<_ErrT>(spError);
|
||||
throw spError;
|
||||
}
|
||||
template <class _ErrT, typename = AddressableError>
|
||||
void throwAddressableError(FStringView msg, std::source_location loc = std::source_location::current())
|
||||
{
|
||||
static_assert(std::is_base_of_v<AddressableError, _ErrT>,
|
||||
"_ErrT must derive from AddressableError");
|
||||
// line, column provide by `currentAAI`
|
||||
_ErrT spError(msg, currentAAI.line, currentAAI.column, loc);
|
||||
error = std::make_unique<_ErrT>(spError);
|
||||
throw spError;
|
||||
}
|
||||
|
||||
template <class _ErrT, typename = UnaddressableError>
|
||||
void throwUnaddressableError(FStringView msg, std::source_location loc = std::source_location::current())
|
||||
{
|
||||
static_assert(std::is_base_of_v<AddressableError, _ErrT>,
|
||||
"_ErrT must derive from AddressableError");
|
||||
_ErrT spError(msg, loc);
|
||||
error = std::make_unique<_ErrT>(spError);
|
||||
throw spError;
|
||||
}
|
||||
|
||||
void setCurrentAAI(Ast::AstAddressInfo _aai)
|
||||
{
|
||||
currentAAI = std::move(_aai);
|
||||
}
|
||||
|
||||
Ast::AstAddressInfo getCurrentAAI() const
|
||||
{
|
||||
return currentAAI;
|
||||
}
|
||||
|
||||
inline const Token &nextToken()
|
||||
{
|
||||
// 没有Rollback时, 存在 currentTokenIndex = tokenPruduced - 1
|
||||
next();
|
||||
return currentToken();
|
||||
}
|
||||
inline void rollback()
|
||||
{
|
||||
if (int64_t(currentTokenIndex - 1) < int64_t(0))
|
||||
// 同下 next注释
|
||||
{
|
||||
throw std::runtime_error("Internal Error in Parser::rollbackToken, trying to rollback but it's already on the begin");
|
||||
}
|
||||
currentTokenIndex--;
|
||||
}
|
||||
inline void next()
|
||||
{
|
||||
if (int64_t(currentTokenIndex) < (int64_t(tokenPruduced) - 1))
|
||||
{
|
||||
/*
|
||||
必须两个都显示转换为int64_t.否则,负数时会超出范围,变成int64_t max, 并且 CTI也需要显示转换,否则转换完的pruduced又会被转回去,变为 int64_t max
|
||||
*/
|
||||
currentTokenIndex++;
|
||||
setCurrentAAI(Ast::AstAddressInfo{.line = currentToken().line, .column = currentToken().column});
|
||||
return;
|
||||
}
|
||||
if (isEOF()) return;
|
||||
const Token &tok = lexer.nextToken();
|
||||
tokenPruduced++;
|
||||
if (tok == IllegalTok) throw lexer.getError();
|
||||
currentTokenIndex = tokenPruduced - 1;
|
||||
setCurrentAAI(Ast::AstAddressInfo{.line = tok.line, .column = tok.column});
|
||||
previousTokens.push_back(tok);
|
||||
}
|
||||
inline const Token ¤tToken()
|
||||
{
|
||||
if (tokenPruduced == 0) return nextToken();
|
||||
return previousTokens.at(currentTokenIndex);
|
||||
}
|
||||
inline Token rollbackToken()
|
||||
{
|
||||
rollback();
|
||||
return previousTokens.at(currentTokenIndex);
|
||||
}
|
||||
|
||||
inline Token peekToken()
|
||||
{
|
||||
Token tok = nextToken();
|
||||
rollback();
|
||||
return tok;
|
||||
}
|
||||
|
||||
std::pair<Precedence, Precedence> getBindingPower(Ast::Operator op)
|
||||
{
|
||||
return opPrecedence.at(op);
|
||||
}
|
||||
Precedence getLeftBindingPower(Ast::Operator op)
|
||||
{
|
||||
return getBindingPower(op).first;
|
||||
}
|
||||
Precedence getRightBindingPower(Ast::Operator op)
|
||||
{
|
||||
return getBindingPower(op).second;
|
||||
}
|
||||
|
||||
// template <class _Tp, class... Args>
|
||||
// std::shared_ptr<_Tp> makeAst(Args &&...args)
|
||||
// {
|
||||
// _Tp node(std::forward<Args>(args)...);
|
||||
// node.setAAI(currentAAI);
|
||||
// return std::shared_ptr<_Tp>(new _Tp(node));
|
||||
// }
|
||||
template <class _Tp, class... Args>
|
||||
std::shared_ptr<_Tp> makeAst(Args &&...args)
|
||||
{
|
||||
std::shared_ptr<_Tp> ptr = std::make_shared<_Tp>(std::forward<Args>(args)...);
|
||||
ptr->setAAI(currentAAI);
|
||||
return ptr;
|
||||
}
|
||||
|
||||
void expectPeek(TokenType type)
|
||||
{
|
||||
if (peekToken().getType() != type)
|
||||
{
|
||||
throwAddressableError<SyntaxError>(FStringView(std::format("Expected `{}`, but got `{}`",
|
||||
magic_enum::enum_name(type),
|
||||
magic_enum::enum_name(peekToken().getType()))));
|
||||
}
|
||||
}
|
||||
|
||||
void expect(TokenType type)
|
||||
{
|
||||
if (currentToken().getType() != type)
|
||||
{
|
||||
throwAddressableError<SyntaxError>(FStringView(std::format("Expected `{}`, but got `{}`",
|
||||
magic_enum::enum_name(type),
|
||||
magic_enum::enum_name(currentToken().getType()))));
|
||||
}
|
||||
}
|
||||
|
||||
void expectPeek(TokenType type, FString expected)
|
||||
{
|
||||
if (peekToken().getType() != type)
|
||||
{
|
||||
throwAddressableError<SyntaxError>(FStringView(std::format("Expected `{}`, but got `{}`",
|
||||
expected.toBasicString(),
|
||||
magic_enum::enum_name(peekToken().getType()))));
|
||||
}
|
||||
}
|
||||
|
||||
void expect(TokenType type, FString expected)
|
||||
{
|
||||
if (currentToken().getType() != type)
|
||||
{
|
||||
throwAddressableError<SyntaxError>(FStringView(std::format("Expected `{}`, but got `{}`",
|
||||
expected.toBasicString(),
|
||||
magic_enum::enum_name(currentToken().getType()))));
|
||||
}
|
||||
}
|
||||
|
||||
[[nodiscard]] SemicolonDisabler disableSemicolon()
|
||||
{
|
||||
return SemicolonDisabler(this);
|
||||
}
|
||||
|
||||
void expectSemicolon()
|
||||
{
|
||||
// if need semicolon and stream has `;`, consume it. if not need semicolon, do nothing
|
||||
|
||||
if (!needSemicolon)
|
||||
{
|
||||
// disabled semicolon check
|
||||
if (currentToken().getType() == TokenType::Semicolon)
|
||||
{
|
||||
next(); // consume `;`
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
// normal semicolon check
|
||||
expectConsume(TokenType::Semicolon);
|
||||
}
|
||||
|
||||
void expectConsume(TokenType type, FString expected)
|
||||
{
|
||||
expect(type, expected);
|
||||
next();
|
||||
}
|
||||
|
||||
void expectConsume(TokenType type)
|
||||
{
|
||||
expect(type);
|
||||
next();
|
||||
}
|
||||
|
||||
bool isNext(TokenType type)
|
||||
{
|
||||
return peekToken().getType() == type;
|
||||
}
|
||||
bool isThis(TokenType type)
|
||||
{
|
||||
return currentToken().getType() == type;
|
||||
}
|
||||
|
||||
static constexpr FString varDefTypeFollowed = u8"(Followed)";
|
||||
|
||||
Ast::VarDef __parseVarDef(bool); // entry: current is keyword `var` or `const` (isConst: Bool)
|
||||
ObjectPtr __parseValue();
|
||||
Ast::ValueExpr __parseValueExpr();
|
||||
Ast::FunctionParameters __parseFunctionParameters(); // entry: current is Token::LeftParen
|
||||
Ast::BlockStatement __parseBlockStatement(); // entry: current is Token::LeftBrace
|
||||
Ast::If __parseIf(); // entry: current is Token::If
|
||||
Ast::While __parseWhile(); // entry: current is Token::While
|
||||
Ast::Statement __parseIncrementStatement(); // only allowed in __parseFor function
|
||||
Ast::For __parseFor(); // entry: current is Token::For
|
||||
Ast::Return __parseReturn(); // entry: current is Token::Return
|
||||
Ast::Break __parseBreak(); // entry: current is Token::Break
|
||||
Ast::Continue __parseContinue(); // entry: current is Token::Continue
|
||||
|
||||
Ast::VarExpr __parseVarExpr(FString);
|
||||
Ast::FunctionDef __parseFunctionDef(bool); // entry: current is Token::Identifier (isPublic: Bool)
|
||||
Ast::StructDef __parseStructDef(bool); // entry: current is Token::Identifier (struct name) arg(isPublic: bool)
|
||||
|
||||
Ast::BinaryExpr __parseInfix(Ast::Expression, Ast::Operator, Precedence);
|
||||
Ast::UnaryExpr __parsePrefix(Ast::Operator, Precedence);
|
||||
Ast::Expression __parseCall(Ast::Expression);
|
||||
|
||||
Ast::ListExpr __parseListExpr(); // entry: current is `[`
|
||||
|
||||
Ast::MapExpr __parseMapExpr(); // entry: current is `{`
|
||||
Ast::InitExpr __parseInitExpr(FString); // entry: current is `{`, ahead is struct name. arg (struct name : FString)
|
||||
Ast::Expression __parseTupleOrParenExpr(); // entry: current is `(`
|
||||
|
||||
Ast::FunctionLiteralExpr __parseFunctionLiteralExpr(); // entry: current is Token::LParen after Token::Function
|
||||
|
||||
Ast::Statement __parseStatement(); // entry: (idk)
|
||||
Ast::Expression parseExpression(Precedence, TokenType = TokenType::Semicolon, TokenType = TokenType::Semicolon);
|
||||
std::vector<Ast::AstBase> parseAll();
|
||||
};
|
||||
}; // namespace Fig
|
||||
Reference in New Issue
Block a user