Files
Fig/src/Parser/parser.cpp
2026-02-02 16:11:08 +08:00

1189 lines
41 KiB
C++
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

#include "Ast/Expressions/VarExpr.hpp"
#include <Ast/Statements/ErrorFlow.hpp>
#include <Ast/Statements/ImplementSt.hpp>
#include <Ast/astBase.hpp>
#include <Ast/functionParameters.hpp>
#include <Error/error.hpp>
#include <Token/token.hpp>
#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::Assign, {20, 10}},
{Ast::Operator::PlusAssign, {20, 10}},
{Ast::Operator::MinusAssign, {20, 10}},
{Ast::Operator::SlashAssign, {20, 10}},
{Ast::Operator::AsteriskAssign, {20, 10}},
{Ast::Operator::PercentAssign, {20, 10}},
{Ast::Operator::CaretAssign, {20, 10}},
// 三元条件 - 特殊处理,通常是右结合
{Ast::Operator::TernaryCond, {30, 20}},
// 逻辑或
{Ast::Operator::Or, {40, 41}}, // leftBP < rightBP左结合
// 逻辑与
{Ast::Operator::And, {50, 51}}, // 比 Or 高
// 位或
{Ast::Operator::BitOr, {60, 61}},
// 位异或
{Ast::Operator::BitXor, {70, 71}},
// 位与
{Ast::Operator::BitAnd, {80, 81}},
// 相等比较
{Ast::Operator::Equal, {90, 91}},
{Ast::Operator::NotEqual, {90, 91}},
// 关系比较
{Ast::Operator::Less, {100, 101}},
{Ast::Operator::LessEqual, {100, 101}},
{Ast::Operator::Greater, {100, 101}},
{Ast::Operator::GreaterEqual, {100, 101}},
{Ast::Operator::Is, {100, 101}},
// 位移
{Ast::Operator::ShiftLeft, {110, 111}},
{Ast::Operator::ShiftRight, {110, 111}},
// 加减
{Ast::Operator::Add, {120, 121}},
{Ast::Operator::Subtract, {120, 121}},
// 乘除模
{Ast::Operator::Multiply, {130, 131}},
{Ast::Operator::Divide, {130, 131}},
{Ast::Operator::Modulo, {130, 131}},
// 幂运算 - 右结合
{Ast::Operator::Power, {140, 139}}, // leftBP > rightBP
};
// 赋值 < 三元 < 逻辑或 < 逻辑与 < 位运算 < 比较 < 位移 < 加减 < 乘除 < 幂 < 一元
// 一元运算符的优先级比所有二元运算符都高
const std::unordered_map<Ast::Operator, Parser::Precedence> Parser::unaryOpPrecedence = {
{Ast::Operator::Subtract, 150}, // -
{Ast::Operator::BitNot, 150}, // ~
{Ast::Operator::Not, 150}, // !
{Ast::Operator::BitAnd, 150}, // &(取地址)
};
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();
Ast::Expression declaredType = nullptr;
bool hasSpecificType = false;
if (isThis(TokenType::Colon)) // :
{
next(); // consume `:`
declaredType = parseExpression(0, TokenType::Assign, TokenType::Semicolon);
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, declaredType, nullptr, false);
}
if (!isThis(TokenType::Assign) and !isThis(TokenType::Walrus)) expect(TokenType::Assign, u8"assign or walrus");
bool followupType = false;
if (isThis(TokenType::Walrus))
{
if (hasSpecificType) throwAddressableError<SyntaxError>(FString(u8""));
followupType = true;
}
next();
Ast::Expression exp = parseExpression(0);
expectSemicolon();
return makeAst<Ast::VarDefAst>(isPublic, isConst, name, declaredType, exp, followupType);
}
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>(FString(u8"Illegal number literal"));
}
return std::make_shared<Object>(d);
}
else
{
// 整数
ValueType::IntClass i;
try
{
i = std::stoi(_val.toBasicString());
}
catch (...)
{
throwAddressableError<SyntaxError>(FString(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;
FString variaPara;
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, {makeAst<Ast::VarExprAst>(u8"Any"), parseExpression(0, TokenType::Comma)}});
if (isThis(TokenType::Comma))
{
next(); // only skip `,` when it's there
}
}
else if (isThis(TokenType::Colon)) // :
{
next(); // skip `:`
Ast::Expression type_exp = parseExpression(0, TokenType::Comma, TokenType::RightParen, TokenType::Assign);
if (isThis(TokenType::Assign)) // =
{
next(); // skip `=`
dp.push_back({pname, {type_exp, parseExpression(0, TokenType::Comma)}});
if (isThis(TokenType::Comma))
{
next(); // only skip `,` when it's there
}
}
else
{
pp.push_back({pname, type_exp});
if (isThis(TokenType::Comma))
{
next(); // only skip `,` when it's there
}
}
}
else if (isThis(TokenType::TripleDot))
{
variaPara = pname;
next(); // skip `...`
if (!isThis(TokenType::RightParen))
throwAddressableError<SyntaxError>(
u8"Expects right paren, variable parameter function can only have one parameter",
currentAAI.line,
currentAAI.column);
next(); // skip `)`
return Ast::FunctionParameters(variaPara);
}
else
{
pp.push_back({pname, makeAst<Ast::VarExprAst>(u8"Any")});
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();
Ast::Expression returnType;
if (isThis(TokenType::RightArrow)) // ->
{
next(); // skip `->`
returnType = parseExpression(0, TokenType::LeftBrace, TokenType::Semicolon);
}
expect(TokenType::LeftBrace);
Ast::BlockStatement body = __parseBlockStatement();
return makeAst<Ast::FunctionDefSt>(funcName, params, isPublic, returnType, 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>(FString(std::format("expect field name or field attribute")));
}
Ast::Expression fieldType = nullptr;
if (isThis(TokenType::Colon))
{
next(); // consume `:`
fieldType = parseExpression(0, TokenType::Assign, TokenType::Semicolon);
}
Ast::Expression initExpr = nullptr;
if (isThis(TokenType::Assign))
{
next();
if (isEOF()) throwAddressableError<SyntaxError>(FString(u8"expect an expression"));
initExpr = parseExpression(0);
}
expectSemicolon();
return Ast::StructDefField(am, fieldName, fieldType, 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>(FString("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>(
FString("Variables are not allowed to be defined within a structure."));
}
else
{
throwAddressableError<SyntaxError>(FString("Invalid syntax"));
}
}
if (!braceClosed) { throwAddressableError<SyntaxError>(FString("braces are not closed")); }
return makeAst<Ast::StructDefSt>(isPublic, structName, fields, makeAst<Ast::BlockStatementAst>(stmts));
}
Ast::InterfaceDef Parser::__parseInterfaceDef(bool isPublic)
{
// entry: current is interface name
FString interfaceName = currentToken().getValue();
next(); // consume name
expect(TokenType::LeftBrace); // `{
next(); // consume `{`
std::vector<Ast::InterfaceMethod> methods;
while (true)
{
if (isThis(TokenType::RightBrace))
{
next(); // consume `}`
break;
}
if (isThis(TokenType::Identifier))
{
FString funcName = currentToken().getValue();
next(); // consume func name
expect(TokenType::LeftParen);
Ast::FunctionParameters paras = __parseFunctionParameters();
expect(TokenType::RightArrow); // ->
next(); // consume `->`
Ast::Expression returnType = parseExpression(0, TokenType::LeftBrace, TokenType::Semicolon);
if (isThis(TokenType::LeftBrace))
{
Ast::BlockStatement block = __parseBlockStatement();
methods.push_back(Ast::InterfaceMethod(funcName, paras, returnType, block));
continue;
}
expectSemicolon();
methods.push_back(Ast::InterfaceMethod(funcName, paras, returnType));
}
else
{
throwAddressableError<SyntaxError>(FString(u8"Invalid syntax"), currentAAI.line, currentAAI.column);
}
}
return makeAst<Ast::InterfaceDefAst>(interfaceName, methods, isPublic);
}
Ast::Implement Parser::__parseImplement()
{
// entry: current is `impl`
next(); // consume `impl`
expect(TokenType::Identifier, u8"interface name");
FString interfaceName = currentToken().getValue();
next(); // consume interface name
expect(TokenType::For);
next(); // consume `for`
expect(TokenType::Identifier, u8"struct name");
FString structName = currentToken().getValue();
next(); // consume name
expect(TokenType::LeftBrace); // {
next(); // consume `{`
std::vector<Ast::ImplementMethod> methods;
while (true)
{
if (isThis(TokenType::RightBrace))
{
next(); // consume `}`
break;
}
if (isThis(TokenType::Identifier))
{
FString funcName = currentToken().getValue();
next(); // consume func name
expect(TokenType::LeftParen);
Ast::FunctionParameters paras = __parseFunctionParameters();
expect(TokenType::LeftBrace);
Ast::BlockStatement body = __parseBlockStatement();
methods.push_back(Ast::ImplementMethod(funcName, paras, body));
}
else
{
throwAddressableError<SyntaxError>(FString(u8"Invalid syntax"), currentAAI.line, currentAAI.column);
}
}
return makeAst<Ast::ImplementAst>(interfaceName, structName, methods);
}
Ast::Throw Parser::__parseThrow()
{
// entry: current is `throw`
next(); // consume `throw`
Ast::Expression exp = parseExpression(0);
expect(TokenType::Semicolon);
next(); // consume `;`
return makeAst<Ast::ThrowSt>(exp);
}
Ast::Try Parser::__parseTry()
{
// entry: current is `try`
next(); // consume `try`
/*
try
{
...
}
catch(e: IOError)
{
}
catch(e: TimeOutError)
{
}
*/
expect(TokenType::LeftBrace);
Ast::BlockStatement body = __parseBlockStatement();
std::vector<Ast::Catch> catches;
Ast::BlockStatement finallyBlock = nullptr;
while (true)
{
if (isThis(TokenType::Catch))
{
next(); // consume `catch`
expect(TokenType::LeftParen);
next(); // consume `(`
expect(TokenType::Identifier, u8"error receive var name");
FString errVarName = currentToken().getValue();
next(); // consume name
bool hasType = false;
FString errVarType;
if (isThis(TokenType::Colon)) // :
{
next();
expect(TokenType::Identifier, u8"error type");
errVarType = currentToken().getValue();
next(); // consume var type
hasType = true;
}
expect(TokenType::RightParen); //
next(); // consume `)`
expect(TokenType::LeftBrace); // {
Ast::BlockStatement catchBody = __parseBlockStatement();
if (hasType) { catches.push_back(Ast::Catch(errVarName, errVarType, catchBody)); }
else
{
catches.push_back(Ast::Catch(errVarName, catchBody));
}
}
else if (isThis(TokenType::Finally))
{
if (finallyBlock != nullptr)
{
throwAddressableError<SyntaxError>(
u8"Duplicate try finally-block", currentAAI.line, currentAAI.column);
}
next(); // consume `finally`
expect(TokenType::LeftBrace);
finallyBlock = __parseBlockStatement();
}
else
{
break;
}
}
return makeAst<Ast::TrySt>(body, catches, finallyBlock);
}
Ast::Statement Parser::__parseStatement(bool allowExp)
{
Ast::Statement stmt;
if (isThis(TokenType::EndOfFile)) { return makeAst<Ast::EofStmt>(); }
else if (isThis(TokenType::Import)) { stmt = __parseImport(); }
else 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))
{
next();
stmt = __parseStructDef(true);
}
else if (isThis(TokenType::Interface)) { stmt = __parseInterfaceDef(true); }
else
{
throwAddressableError<SyntaxError>(
FString(u8"Expected `var`, `const`, `function`, `struct` or `interface` 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::Interface))
{
expectPeek(TokenType::Identifier, u8"interface name");
next();
stmt = __parseInterfaceDef(false);
}
else if (isThis(TokenType::Implement)) { stmt = __parseImplement(); }
else if (isThis(TokenType::If)) { stmt = __parseIf(); }
else if (isThis(TokenType::Else))
{
throwAddressableError<SyntaxError>(FString(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 if (isThis(TokenType::Throw)) { stmt = __parseThrow(); }
else if (isThis(TokenType::Try)) { stmt = __parseTry(); }
else if (allowExp)
{
// expression statement
Ast::Expression exp = parseExpression(0);
expectSemicolon();
stmt = makeAst<Ast::ExpressionStmtAst>(exp);
}
else
{
throwAddressableError<SyntaxError>(u8"invalid syntax", currentAAI.line, currentAAI.column);
}
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, TokenType::LeftBrace);
}
// 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;
if (isThis(TokenType::LeftParen))
{
elifCondition = parseExpression(0, TokenType::RightParen);
expect(TokenType::RightParen);
next(); // consume `)`
}
else
{
elifCondition = parseExpression(0, TokenType::LeftBrace);
}
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;
if (isThis(TokenType::LeftParen))
{
next(); // consume `(`
condition = parseExpression(0, TokenType::RightParen);
expect(TokenType::RightParen);
next(); // consume `)`
}
else
{
condition = parseExpression(0, TokenType::LeftBrace);
}
expect(TokenType::LeftBrace); // {
Ast::BlockStatement body = __parseBlockStatement();
return makeAst<Ast::WhileSt>(condition, body);
}
Ast::Statement Parser::__parseIncrementStatement()
{
// allowed
// 1. assignmenti = 1, i += 1
// 2. expression stmti++, foo()
// ❌ not allowedif/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");
}
Ast::Expression exp = parseExpression(0, TokenType::LeftBrace);
// expectSemicolon(); we dont check the semicolon
return makeAst<Ast::ExpressionStmtAst>(exp);
}
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(false); // 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<Ast::Expression, Ast::Expression> val;
while (!isThis(TokenType::RightBrace))
{
Ast::Expression key = parseExpression(0, TokenType::Colon);
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(Ast::Expression structe)
{
// 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; // 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>(
FString(std::format("Expect `,` or `}}` in struct initialization expression, got {}",
currentToken().toString().toBasicString())));
}
}
expect(TokenType::RightBrace);
next(); // consume `}`
return makeAst<Ast::InitExprAst>(
structe,
args,
static_cast<Ast::InitExprAst::InitMode>(mode));
}
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>(FString(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::Import Parser::__parseImport()
{
next(); // consume `import`
std::vector<FString> path;
while (true)
{
expect(TokenType::Identifier, u8"package name");
path.push_back(currentToken().getValue());
next(); // consume package name
if (isThis(TokenType::Semicolon)) { break; }
else if (isThis(TokenType::Dot))
{
next(); // consume `.`
}
else
{
throw SyntaxError();
}
}
expectSemicolon();
return makeAst<Ast::ImportSt>(path);
}
Ast::Expression Parser::parseExpression(Precedence bp, TokenType stop, TokenType stop2, TokenType stop3)
{
Ast::Expression lhs;
Ast::Operator op;
Token tok = currentToken();
if (tok == EOFTok) throwAddressableError<SyntaxError>(FString(u8"Unexpected end of expression"));
if (tok.getType() == stop || tok.getType() == stop2 || tok.getType() == stop3)
{
if (lhs == nullptr) throwAddressableError<SyntaxError>(FString(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>(FString(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();
lhs = __parseVarExpr(id);
}
else if (isTokenOp(tok) && isOpUnary((op = Ast::TokenToOp.at(tok.getType()))))
{
// prefix
next();
lhs = makeAst<Ast::UnaryExprAst>(op, parseExpression(bp, stop, stop2));
}
else if (tok.getType() == TokenType::New)
{
// `new` now is an independent syntax
next();
Ast::Expression operand = parseExpression(bp, TokenType::LeftBrace);
expect(TokenType::LeftBrace);
lhs = __parseInitExpr(operand);
}
else
{
throwAddressableError<SyntaxError>(FString(u8"Unexpected token in expression:") + tok.toString());
}
// infix / (postfix) ?
while (true)
{
tok = currentToken();
if (tok.getType() == stop || tok.getType() == stop2 || tok.getType() == stop3 || tok == EOFTok) break;
/* Postfix */
if (tok.getType() == TokenType::LeftBrace)
{
throwAddressableError<SyntaxError>(
FString(u8"Since Fig v0.4.2, please use new struct{} to avoid syntax ambiguity"));
}
if (tok.getType() == TokenType::LeftParen)
{
lhs = __parseCall(lhs);
continue;
}
// else if (tok.getType() == TokenType::LeftBrace) { lhs = __parseInitExpr(lhs); }
/*
since Fig v0.4.2, use new struct{};
if a == A{}
is A{} struct init?
or A a variable, {} is the body?
fuck.
*/
// member access: a.b
if (tok.getType() == TokenType::Dot)
{
next(); // consume '.'
Token idTok = currentToken();
if (!idTok.isIdentifier())
throwAddressableError<SyntaxError>(FString(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, stop2);
expect(TokenType::RightBracket);
next(); // consume ']'
lhs = makeAst<Ast::IndexExprAst>(lhs, indexExpr);
continue;
}
// ternary
if (tok.getType() == TokenType::Question)
{
auto [lbp, rbp] = getBindingPower(Ast::Operator::TernaryCond);
if (bp >= lbp) break;
next(); // consume ?
Ast::Expression trueExpr = parseExpression(0, TokenType::Colon);
expectConsume(TokenType::Colon);
Ast::Expression falseExpr = parseExpression(0);
lhs = makeAst<Ast::TernaryExprAst>(lhs, trueExpr, falseExpr);
continue;
}
if (!isTokenOp(tok)) break;
op = Ast::TokenToOp.at(tok.getType());
auto [lbp, rbp] = getBindingPower(op);
if (bp >= lbp) break;
next(); // consume op
lhs = makeAst<Ast::BinaryExprAst>(lhs, op, parseExpression(rbp, stop, stop2));
}
return lhs;
}
std::vector<Ast::AstBase> Parser::parseAll()
{
output.clear();
Token tok = currentToken();
if (tok == EOFTok) { return output; }
while (!isEOF())
{
auto stmt = __parseStatement();
if (!output.empty() && stmt->getType() == Ast::AstType::PackageSt)
{
throwAddressableError<SyntaxError>(
u8"Package must be at the beginning of the file", currentAAI.line, currentAAI.column);
}
pushNode(stmt);
}
return output;
}
} // namespace Fig