feat: 添加If语句及块语句解析支持

This commit is contained in:
2026-02-20 15:46:33 +08:00
parent 2631f76da1
commit eb20993e27
6 changed files with 288 additions and 23 deletions

View File

@@ -108,7 +108,7 @@ BreakConstructorInitializers: AfterColon
BreakStringLiterals: false BreakStringLiterals: false
# 每行字符的限制0表示没有限制 # 每行字符的限制0表示没有限制
ColumnLimit: 120 ColumnLimit: 100
CompactNamespaces: true CompactNamespaces: true
# 构造函数的初始化列表要么都在同一行,要么都各自一行 # 构造函数的初始化列表要么都在同一行,要么都各自一行

View File

@@ -15,4 +15,5 @@
#include <Ast/Expr/PrefixExpr.hpp> #include <Ast/Expr/PrefixExpr.hpp>
#include <Ast/Stmt/ExprStmt.hpp> #include <Ast/Stmt/ExprStmt.hpp>
#include <Ast/Stmt/IfStmt.hpp>
#include <Ast/Stmt/VarDecl.hpp> #include <Ast/Stmt/VarDecl.hpp>

View File

@@ -19,6 +19,7 @@ namespace Fig
Program, // 程序 Program, // 程序
Expr, // 表达式 Expr, // 表达式
Stmt, // 语句 Stmt, // 语句
BlockStmt, // 块语句
/* Expressions */ /* Expressions */
IdentiExpr, // 标识符表达式 IdentiExpr, // 标识符表达式
@@ -32,6 +33,8 @@ namespace Fig
/* Statements */ /* Statements */
ExprStmt, // 表达式语句,如 println(1) ExprStmt, // 表达式语句,如 println(1)
VarDecl, // 变量声明 VarDecl, // 变量声明
IfStmt, // If语句
ElseIfStmt, // ElseIf语句不准悬空
}; };
struct AstNode struct AstNode
{ {
@@ -81,7 +84,29 @@ namespace Fig
virtual String toString() const override virtual String toString() const override
{ {
return "Program"; return "<Program>";
}
};
struct BlockStmt final : public Stmt
{
DynArray<Stmt *> nodes;
BlockStmt()
{
type = AstType::BlockStmt;
}
BlockStmt(DynArray<Stmt *> _nodes)
{
type = AstType::BlockStmt;
nodes = std::move(_nodes);
if (!_nodes.empty())
{
location = std::move(_nodes.back()->location);
}
}
virtual String toString() const override
{
return "<BlockStmt>";
} }
}; };
}; // namespace Fig }; // namespace Fig

69
src/Ast/Stmt/IfStmt.hpp Normal file
View File

@@ -0,0 +1,69 @@
/*!
@file src/Ast/Stmt/IfStmt.hpp
@brief IfStmt定义
@author PuqiAR (im@puqiar.top)
@date 2026-02-20
*/
#pragma once
#include <Ast/Base.hpp>
namespace Fig
{
struct ElseIfStmt final : public Stmt
{
Expr *cond;
BlockStmt *consequent;
ElseIfStmt()
{
type = AstType::ElseIfStmt;
}
ElseIfStmt(Expr *_cond, BlockStmt *_consequent, SourceLocation _location) :
cond(_cond), consequent(_consequent)
{
type = AstType::ElseIfStmt;
location = std::move(_location);
}
virtual String toString() const override
{
return std::format("<ElseIf ({}) then {}>", cond->toString(), consequent->toString());
}
};
struct IfStmt final : public Stmt
{
Expr *cond;
BlockStmt *consequent;
DynArray<ElseIfStmt *> elifs;
BlockStmt *alternate;
IfStmt()
{
type = AstType::IfStmt;
}
IfStmt(Expr *_cond,
BlockStmt *_consequent,
DynArray<ElseIfStmt *> _elifs,
BlockStmt *_alternate,
SourceLocation _location) :
cond(_cond), consequent(_consequent), elifs(std::move(_elifs)), alternate(_alternate)
{
type = AstType::IfStmt;
location = std::move(_location);
}
virtual String toString() const override
{
return std::format("<If ({}) then {}, else if * {}, else {}>",
cond->toString(),
consequent->toString(),
elifs.size(),
alternate->toString());
}
};
}; // namespace Fig

View File

@@ -158,6 +158,7 @@ namespace Fig
ParsingCallExpr, ParsingCallExpr,
ParsingVarDecl, ParsingVarDecl,
ParsingIf,
} state; } state;
@@ -193,8 +194,9 @@ namespace Fig
Result<Expr *, Error> parseExpression(BindingPower = 0, TokenType stop = TokenType::Semicolon, TokenType stop2 = TokenType::Semicolon); Result<Expr *, Error> parseExpression(BindingPower = 0, TokenType stop = TokenType::Semicolon, TokenType stop2 = TokenType::Semicolon);
/* Statements */ /* Statements */
Result<BlockStmt *, Error> parseBlockStmt(); // 当前token为 {
Result<VarDecl *, Error> parseVarDecl(bool); // 由 parseStatement调用, 当前token为 var Result<VarDecl *, Error> parseVarDecl(bool); // 由 parseStatement调用, 当前token为 var
Result<IfStmt *, Error> parseIfStmt(); // 由 parseStatement调用, 当前token is if
Result<Stmt *, Error> parseStatement(); Result<Stmt *, Error> parseStatement();
public: public:

View File

@@ -9,7 +9,34 @@
namespace Fig namespace Fig
{ {
Result<VarDecl *, Error> Parser::parseVarDecl(bool isPublic) // 由 parseStatement调用, 当前token为 var Result<BlockStmt *, Error> Parser::parseBlockStmt() // 当前token为 {
{
SourceLocation location = makeSourceLocation(consumeToken()); // consume `{`
BlockStmt *stmt = new BlockStmt();
while (true)
{
if (isEOF)
{
return std::unexpected(Error(ErrorType::SyntaxError,
"unclosed braces in block stmt",
"insert `}`",
location));
}
if (match(TokenType::RightBrace))
{
break;
}
const auto &result = parseStatement();
if (!result)
{
return std::unexpected(result.error());
}
stmt->nodes.push_back(*result);
}
return stmt;
}
Result<VarDecl *, Error> Parser::parseVarDecl(
bool isPublic) // 由 parseStatement调用, 当前token为 var
{ {
state = State::ParsingVarDecl; state = State::ParsingVarDecl;
@@ -50,8 +77,147 @@ namespace Fig
VarDecl *varDecl = new VarDecl(isPublic, name, typeSpeicifer, initExpr, location); VarDecl *varDecl = new VarDecl(isPublic, name, typeSpeicifer, initExpr, location);
return varDecl; return varDecl;
} }
Result<IfStmt *, Error> Parser::parseIfStmt() // 由 parseStatement调用, 当前token is if
{
state = State::ParsingIf;
SourceLocation location = makeSourceLocation(consumeToken()); // consume `if`
Expr *cond = nullptr;
if (match(TokenType::LeftParen)) // match and consume `(`
{
const Token &lpToken = prevToken();
const auto &result = parseExpression(0, TokenType::RightParen, TokenType::LeftBrace);
if (!result)
{
return std::unexpected(result.error());
}
if (!match(TokenType::RightParen))
{
return std::unexpected(Error(ErrorType::SyntaxError,
"unclosed parenthese in if condition",
"insert `)`",
makeSourceLocation(lpToken)));
}
cond = *result;
}
else
{
const auto &result = parseExpression(0, TokenType::LeftBrace);
if (!result)
{
return std::unexpected(result.error());
}
cond = *result;
}
state = State::ParsingIf;
if (currentToken().type != TokenType::LeftBrace)
{
return std::unexpected(
makeUnexpectTokenError("IfStmt", "LeftBrace `{`", currentToken()));
}
const auto &result = parseBlockStmt();
if (!result)
{
return std::unexpected(result.error());
}
BlockStmt *consequent = *result;
DynArray<ElseIfStmt *> elifs;
BlockStmt *alternate = nullptr;
while (match(TokenType::Else))
{
SourceLocation elseLocation = makeSourceLocation(prevToken());
if (match(TokenType::If))
{
// else if
if (alternate)
{
return std::unexpected(Error(ErrorType::SyntaxError,
"else if after else",
"remove else if",
elseLocation));
}
Expr *cond = nullptr;
if (match(TokenType::LeftParen)) // `(`
{
const Token &lpToken = prevToken();
const auto &result =
parseExpression(0, TokenType::RightParen, TokenType::LeftBrace);
if (!result)
{
return std::unexpected(result.error());
}
state = State::ParsingIf;
if (!match(TokenType::RightParen))
{
return std::unexpected(Error(ErrorType::SyntaxError,
"unclosed parenthese in if condition",
"insert `)`",
makeSourceLocation(lpToken)));
}
cond = *result;
}
else
{
const auto &result = parseExpression(0, TokenType::LeftBrace);
if (!result)
{
return std::unexpected(result.error());
}
state = State::ParsingIf;
cond = *result;
}
if (currentToken().type != TokenType::LeftBrace)
{
return std::unexpected(
makeUnexpectTokenError("ElseIfStmt", "LeftBrace `{`", currentToken()));
}
const auto &result = parseBlockStmt();
if (!result)
{
return std::unexpected(result.error());
}
state = State::ParsingIf;
BlockStmt *consequent = *result;
ElseIfStmt *elif = new ElseIfStmt(cond, consequent, elseLocation);
elifs.push_back(elif);
}
else
{
// else
if (alternate)
{
return std::unexpected(Error(ErrorType::SyntaxError,
"duplicate else in if stmt",
"remove it",
elseLocation));
}
if (currentToken().type != TokenType::LeftBrace)
{
return std::unexpected(
makeUnexpectTokenError("ElseStmt", "LeftBrace `{`", currentToken()));
}
const auto &result = parseBlockStmt();
if (!result)
{
return std::unexpected(result.error());
}
state = State::ParsingIf;
alternate = *result;
}
}
IfStmt *ifStmt = new IfStmt(cond, consequent, elifs, alternate, location);
return ifStmt;
}
Result<Stmt *, Error> Parser::parseStatement() Result<Stmt *, Error> Parser::parseStatement()
{ {
state = State::Standby;
if (currentToken().type == TokenType::Public) if (currentToken().type == TokenType::Public)
{ {
consumeToken(); // consume `public` consumeToken(); // consume `public`
@@ -60,12 +226,15 @@ namespace Fig
return parseVarDecl(true); return parseVarDecl(true);
} }
} }
else if (currentToken().type == TokenType::Variable) if (currentToken().type == TokenType::Variable)
{ {
return parseVarDecl(false); return parseVarDecl(false);
} }
else if (currentToken().type == TokenType::If)
{ {
return parseIfStmt();
}
const auto &expr_result = parseExpression(0); const auto &expr_result = parseExpression(0);
if (!expr_result) if (!expr_result)
{ {
@@ -78,5 +247,4 @@ namespace Fig
} }
return exprStmt; return exprStmt;
} }
}
}; // namespace Fig }; // namespace Fig