feat: 在解析器中实现 Lambda 和 new 表达式

- 增加了对 Lambda 表达式的初步解析支持,包括参数处理和返回类型。Lambda闭包尚未支持。
- 引入了用于对象初始化的新的表达式,支持可选的命名参数。
- 改进了表达式语法错误的错误报告。
- 更新了解析器和分析器以处理新的表达式类型并验证其语义。
- 修改了现有测试以涵盖新功能并确保其正确性。
- 改进了各种解析和语义错误的诊断。
This commit is contained in:
2026-04-12 10:07:51 +08:00
parent 570a87c3cd
commit fafa2b4946
24 changed files with 925 additions and 140 deletions

View File

@@ -14,7 +14,8 @@ namespace Fig
StateProtector p(this, {State::ParsingLiteralExpr});
const Token &literal_token = consumeToken();
LiteralExpr *node = arena.Allocate<LiteralExpr>(literal_token, makeSourceLocation(literal_token));
LiteralExpr *node =
arena.Allocate<LiteralExpr>(literal_token, makeSourceLocation(literal_token));
return node;
}
Result<Expr *, Error> Parser::parseIdentiExpr() // 当前token为Identifier调用
@@ -65,8 +66,8 @@ namespace Fig
return node;
}
Result<Expr *, Error> Parser::parseIndexExpr(
Expr *base) // 由 parseExpression调用, 当前token为 `[`
Result<Expr *, Error>
Parser::parseIndexExpr(Expr *base) // 由 parseExpression调用, 当前token为 `[`
{
StateProtector p(this, {State::ParsingIndexExpr});
@@ -80,7 +81,8 @@ namespace Fig
if (currentToken().type != TokenType::RightBracket) // `]`
{
return std::unexpected(Error(ErrorType::SyntaxError,
return std::unexpected(Error(
ErrorType::SyntaxError,
"unclosed brackets",
"insert `]`",
makeSourceLocation(lbracket_token)));
@@ -91,12 +93,13 @@ namespace Fig
return indexExpr;
}
Result<Expr *, Error> Parser::parseCallExpr(
Expr *callee) // 由 parseExpression调用, 当前token为 `(`
Result<Expr *, Error>
Parser::parseCallExpr(Expr *callee) // 由 parseExpression调用, 当前token为 `(`
{
StateProtector p(this, {State::ParsingCallExpr});
const Token &lparen_token = consumeToken(); // consume `(`
const SourceLocation &location = makeSourceLocation(lparen_token);
FnCallArgs callArgs;
@@ -104,14 +107,15 @@ namespace Fig
if (currentToken().type == TokenType::RightParen)
{
consumeToken(); // consume `)`
return arena.Allocate<CallExpr>(callee, callArgs);
return arena.Allocate<CallExpr>(callee, callArgs, location);
}
while (true)
{
if (currentToken().type == TokenType::EndOfFile)
{
return std::unexpected(Error(ErrorType::SyntaxError,
return std::unexpected(Error(
ErrorType::SyntaxError,
"fn call has unclosed parenthese",
"insert `)`",
makeSourceLocation(lparen_token)));
@@ -131,7 +135,8 @@ namespace Fig
if (currentToken().type != TokenType::Comma)
{
return std::unexpected(Error(ErrorType::SyntaxError,
return std::unexpected(Error(
ErrorType::SyntaxError,
"expected `,` or `)` in argument list",
"insert `,`",
makeSourceLocation(currentToken())));
@@ -140,7 +145,186 @@ namespace Fig
consumeToken(); // consume `,`
}
return arena.Allocate<CallExpr>(callee, callArgs);
return arena.Allocate<CallExpr>(callee, callArgs, location);
}
Result<Expr *, Error> Parser::parseNewExpr()
{
// new type{...}
StateProtector p(this, {State::ParsingNewExpr});
SourceLocation location = makeSourceLocation(consumeToken()); // consume `new`
SET_STOP_AT(TokenType::LeftBrace); // {
auto type_result = parseTypeExpr();
if (!type_result)
{
return std::unexpected(type_result.error());
}
TypeExpr *type = *type_result;
if (!match(TokenType::LeftBrace))
{
return std::unexpected(makeUnexpectTokenError("NewExpr", "lbrace {", currentToken()));
}
const Token &lb_token = prevToken();
/*
Positional:
new Point{1, 2}
Named:
new Point{x = 1, y = 2}
*/
DynArray<NewExpr::Arg> args;
while (true)
{
if (isEOF)
{
return std::unexpected(Error(
ErrorType::SyntaxError,
"unclosed `{` in new expr",
"insert '}'",
makeSourceLocation(lb_token)
));
}
if (args.empty() && match(TokenType::RightBrace)) // 空参
{
break;
}
if (currentToken().isIdentifier() && peekToken().type == TokenType::Assign)
{
const Token &name_token = consumeToken();
const String &name = srcManager.GetSub(name_token.index, name_token.length);
consumeToken(); // consume `=`
SET_STOP_AT(TokenType::Comma, TokenType::RightBrace); // , / }
auto result = parseExpression();
if (!result)
{
return result;
}
args.push_back(NewExpr::Arg{
name,
*result
});
}
else
{
SET_STOP_AT(TokenType::Comma, TokenType::RightBrace); // , / }
auto result = parseExpression();
if (!result)
{
return result;
}
args.push_back(NewExpr::Arg{
.value = *result
});
}
if (match(TokenType::Comma))
{
continue;
}
if (match(TokenType::RightBrace))
{
break;
}
}
NewExpr *newExpr = arena.Allocate<NewExpr>(type, args, location);
return newExpr;
}
Result<Expr *, Error> Parser::parseLambdaExpr()
{
StateProtector p(this, {State::ParsingLambdaExpr});
SourceLocation location = makeSourceLocation(consumeToken()); // consume `func`
if (currentToken().isIdentifier())
{
return std::unexpected(Error(
ErrorType::SyntaxError,
"lambda expression should not have a name",
"remove the name",
makeSourceLocation(currentToken())));
}
if (currentToken().type != TokenType::LeftParen)
{
return std::unexpected(
makeUnexpectTokenError("fn def stmt", "lparen '('", currentToken()));
}
DynArray<Param *> params;
auto paraResult = parseFnParams();
if (!paraResult)
{
return std::unexpected(paraResult.error());
}
params = *paraResult;
TypeExpr *returnType = nullptr;
Token rightArrowToken;
if (match(TokenType::RightArrow)) // ->
{
rightArrowToken = consumeToken();
auto result = parseTypeExpr();
if (!result)
{
return std::unexpected(result.error());
}
returnType = *result;
}
if (match(TokenType::DoubleArrow)) // =>
{
if (returnType)
{
return std::unexpected(Error(
ErrorType::SyntaxError,
"use of expr body but specified return type in lambda expr",
"remove `-> ...`",
makeSourceLocation(rightArrowToken)));
}
auto result = parseExpression();
if (!result)
{
return result;
}
Expr *expr = *result;
LambdaExpr *lambda =
arena.Allocate<LambdaExpr>(params, returnType, expr, true, location);
return lambda;
}
else if (currentToken().type == TokenType::LeftBrace)
{
auto result = parseBlockStmt();
if (!result)
{
return std::unexpected(result.error());
}
LambdaExpr *lambda =
arena.Allocate<LambdaExpr>(params, returnType, *result, false, location);
return lambda;
}
else
{
return std::unexpected(
makeUnexpectTokenError("LambdaExpr", "darrow => / lbrace {", currentToken()));
}
}
Result<Expr *, Error> Parser::parseExpression(BindingPower rbp)
@@ -186,17 +370,39 @@ namespace Fig
const Token &rparen_token = consumeToken(); // consume `)`
if (rparen_token.type != TokenType::RightParen)
{
return std::unexpected(Error(ErrorType::SyntaxError,
return std::unexpected(Error(
ErrorType::SyntaxError,
"unclosed parenthese",
"insert `)`",
makeSourceLocation(lparen_token)));
}
lhs = *expr_result;
}
else if (token.type == TokenType::Function)
{
auto result = parseLambdaExpr();
if (!result)
{
return result;
}
lhs = *result;
}
else if (token.type == TokenType::New)
{
auto result = parseNewExpr();
if (!result)
{
return result;
}
lhs = *result;
}
if (!lhs)
{
return std::unexpected(Error(ErrorType::ExpectedExpression,
return std::unexpected(Error(
ErrorType::ExpectedExpression,
"expected expression",
"insert expressions",
makeSourceLocation(prevToken())));
@@ -253,10 +459,11 @@ namespace Fig
}
else
{
return std::unexpected(Error(ErrorType::ExpectedExpression,
"expression unexpectedly ended",
"insert expressions",
makeSourceLocation(token)));
// return std::unexpected(Error(ErrorType::ExpectedExpression,
// "expression unexpectedly ended",
// "insert expressions",
// makeSourceLocation(token)));
return lhs;
}
}
return lhs;