feat: 添加If语句及块语句解析支持
This commit is contained in:
@@ -108,7 +108,7 @@ BreakConstructorInitializers: AfterColon
|
|||||||
BreakStringLiterals: false
|
BreakStringLiterals: false
|
||||||
|
|
||||||
# 每行字符的限制,0表示没有限制
|
# 每行字符的限制,0表示没有限制
|
||||||
ColumnLimit: 120
|
ColumnLimit: 100
|
||||||
CompactNamespaces: true
|
CompactNamespaces: true
|
||||||
|
|
||||||
# 构造函数的初始化列表要么都在同一行,要么都各自一行
|
# 构造函数的初始化列表要么都在同一行,要么都各自一行
|
||||||
|
|||||||
@@ -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>
|
||||||
@@ -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
69
src/Ast/Stmt/IfStmt.hpp
Normal 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
|
||||||
@@ -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:
|
||||||
|
|||||||
@@ -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
|
||||||
Reference in New Issue
Block a user