Refactor: 重构Parser和AST结构,以支持新的语言特性

- 更新了 ParserTest,以改进文件路径处理和输出格式。
- 在 StmtParser 中新增了 parseConstDecl 和 parseForStmt 方法,用于处理常量声明和 for 循环。
- TypeExpr现归类为Expr。TypeExpr属于Expr,语义阶段视为Expr
- 添加了新的 AST 节点:PostfixExpr、TernaryExpr、ForStmt 和 ImportStmt,用于表示新的语法结构。
This commit is contained in:
2026-06-06 22:12:04 +08:00
parent 4f87078a87
commit 680197aafe
27 changed files with 1299 additions and 225 deletions

View File

@@ -16,6 +16,8 @@
#include <Ast/Expr/MemberExpr.hpp>
#include <Ast/Expr/NewExpr.hpp>
#include <Ast/Expr/PrefixExpr.hpp>
#include <Ast/Expr/TernaryExpr.hpp>
#include <Ast/Expr/PostfixExpr.hpp>
#include <Ast/Stmt/ControlFlowStmts.hpp>
#include <Ast/Stmt/ExprStmt.hpp>
@@ -24,6 +26,8 @@
#include <Ast/Stmt/ImplStmt.hpp>
#include <Ast/Stmt/InterfaceDefStmt.hpp>
#include <Ast/Stmt/StructDefStmt.hpp>
#include <Ast/Stmt/ForStmt.hpp>
#include <Ast/Stmt/ImportStmt.hpp>
#include <Ast/Stmt/VarDecl.hpp>
#include <Ast/Stmt/WhileStmt.hpp>
#include <Ast/TypeExpr.hpp>

View File

@@ -31,6 +31,8 @@ namespace Fig
MemberExpr, // obj.prop
NewExpr, // new Point{}
LambdaExpr,
TernaryExpr, // cond ? then : else
PostfixExpr, // expr++ / expr--
/* Statements */
ExprStmt,
@@ -45,12 +47,16 @@ namespace Fig
ReturnStmt,
BreakStmt,
ContinueStmt,
ForStmt, // for loop
ImportStmt, // import
/* Type Expressions */
TypeExpr,
NamedTypeExpr,
NullableTypeExpr,
NamedTypeExpr, // 废弃,用 IdentiExpr/MemberExpr/ApplyExpr 替代
NullableTypeExpr, // 废弃,用 NullableExpr 替代
FnTypeExpr,
ApplyExpr, // 泛型实例化: List<Int>
NullableExpr, // 可空后缀: Int?
};
struct AstNode
@@ -62,15 +68,6 @@ namespace Fig
virtual ~AstNode() {};
};
struct TypeExpr : public AstNode
{
TypeExpr()
{
type = AstType::TypeExpr;
}
virtual ~TypeExpr() = default;
};
struct Expr : public AstNode
{
// 语义分析后填充
@@ -116,4 +113,55 @@ namespace Fig
return "<BlockStmt>";
}
};
// --- Type Expressions (inherit Expr — 类型即值) ---
struct TypeExpr : public Expr
{
TypeExpr() { type = AstType::TypeExpr; }
virtual ~TypeExpr() = default;
};
// ApplyExpr: 泛型实例化List<Int> → ApplyExpr(base, [Int])
struct ApplyExpr final : public Expr
{
Expr *base; // 基础类型表达式
DynArray<Expr *> args; // 泛型参数
ApplyExpr() { type = AstType::ApplyExpr; }
ApplyExpr(Expr *_base, DynArray<Expr *> _args, SourceLocation _loc) :
base(_base), args(std::move(_args))
{
type = AstType::ApplyExpr;
location = std::move(_loc);
}
virtual String toString() const override
{
String s = base->toString() + "<";
for (size_t i = 0; i < args.size(); ++i)
{
if (i) s += ", ";
s += args[i]->toString();
}
s += ">";
return s;
}
};
// NullableExpr: 可空后缀 Int? → NullableExpr(Int)
struct NullableExpr final : public Expr
{
Expr *inner;
NullableExpr() { type = AstType::NullableExpr; }
NullableExpr(Expr *_inner, SourceLocation _loc) : inner(_inner)
{
type = AstType::NullableExpr;
location = std::move(_loc);
}
virtual String toString() const override
{
return inner->toString() + "?";
}
};
} // namespace Fig

View File

@@ -15,7 +15,7 @@ namespace Fig
// func (params) [-> return type] ([=> expr] / [ {stmt} ])
DynArray<Param *> params;
TypeExpr *returnType;
Expr *returnType;
AstNode *body; // expr/blockstmt
bool isExprBody;
@@ -28,7 +28,7 @@ namespace Fig
LambdaExpr(
DynArray<Param *> _params,
TypeExpr *_returnType,
Expr *_returnType,
AstNode *_body,
bool _isExprBody,
SourceLocation _location) :

View File

@@ -18,14 +18,14 @@ namespace Fig
String name;
Expr *value;
};
TypeExpr *typeExpr;
Expr *typeExpr;
DynArray<Arg> args;
NewExpr()
{
type = AstType::NewExpr;
}
NewExpr(TypeExpr *_te, DynArray<Arg> _args, SourceLocation _loc) :
NewExpr(Expr *_te, DynArray<Arg> _args, SourceLocation _loc) :
typeExpr(_te), args(std::move(_args))
{
type = AstType::NewExpr;

View File

@@ -0,0 +1,35 @@
/*!
@file src/Ast/Expr/PostfixExpr.hpp
@brief expr++ / expr--
@author PuqiAR (im@puqiar.top)
@date 2026-06-06
*/
#pragma once
#include <Ast/Base.hpp>
#include <Ast/Operator.hpp>
namespace Fig
{
struct PostfixExpr final : public Expr
{
UnaryOperator op;
Expr *operand;
PostfixExpr() { type = AstType::PostfixExpr; }
PostfixExpr(UnaryOperator _op, Expr *_operand) :
op(_op), operand(_operand)
{
type = AstType::PostfixExpr;
location = _operand->location;
}
virtual String toString() const override
{
return std::format("<PostfixExpr: {} '{}'>",
operand->toString(), magic_enum::enum_name(op));
}
};
} // namespace Fig

View File

@@ -0,0 +1,35 @@
/*!
@file src/Ast/Expr/TernaryExpr.hpp
@brief cond ? then : else
@author PuqiAR (im@puqiar.top)
@date 2026-06-06
*/
#pragma once
#include <Ast/Base.hpp>
namespace Fig
{
struct TernaryExpr final : public Expr
{
Expr *cond;
Expr *thenExpr;
Expr *elseExpr;
TernaryExpr() { type = AstType::TernaryExpr; }
TernaryExpr(Expr *_cond, Expr *_then, Expr *_else, SourceLocation _loc) :
cond(_cond), thenExpr(_then), elseExpr(_else)
{
type = AstType::TernaryExpr;
location = std::move(_loc);
}
virtual String toString() const override
{
return std::format("<TernaryExpr: {} ? {} : {}>",
cond->toString(), thenExpr->toString(), elseExpr->toString());
}
};
} // namespace Fig

View File

@@ -16,6 +16,8 @@ namespace Fig
{TokenType::Minus, UnaryOperator::Negate},
{TokenType::Not, UnaryOperator::Not},
{TokenType::Ampersand, UnaryOperator::AddressOf},
{TokenType::DoublePlus, UnaryOperator::Increment},
{TokenType::DoubleMinus, UnaryOperator::Decrement},
};
return unaryOpMap;
}
@@ -40,6 +42,8 @@ namespace Fig
{TokenType::And, BinaryOperator::LogicalAnd},
{TokenType::Or, BinaryOperator::LogicalOr},
{TokenType::DoubleAmpersand, BinaryOperator::LogicalAnd},
{TokenType::DoublePipe, BinaryOperator::LogicalOr},
{TokenType::Power, BinaryOperator::Power},
@@ -49,6 +53,7 @@ namespace Fig
{TokenType::AsteriskEqual, BinaryOperator::MultiplyAssign},
{TokenType::SlashEqual, BinaryOperator::DivideAssign},
{TokenType::PercentEqual, BinaryOperator::ModuloAssign},
{TokenType::Caret, BinaryOperator::BitXor},
{TokenType::CaretEqual, BinaryOperator::BitXorAssign},
{TokenType::Pipe, BinaryOperator::BitOr},
@@ -56,7 +61,7 @@ namespace Fig
{TokenType::ShiftLeft, BinaryOperator::ShiftLeft},
{TokenType::ShiftRight, BinaryOperator::ShiftRight},
{TokenType::Dot, BinaryOperator::MemberAccess},
{TokenType::As, BinaryOperator::As},
};
return binaryOpMap;
}
@@ -78,6 +83,8 @@ namespace Fig
{UnaryOperator::Negate, 20001},
{UnaryOperator::Not, 20001},
{UnaryOperator::AddressOf, 20001},
{UnaryOperator::Increment, 20001},
{UnaryOperator::Decrement, 20001},
};
return unbpm;
}
@@ -109,6 +116,7 @@ namespace Fig
{BinaryOperator::GreaterEqual, 2100},
{BinaryOperator::Is, 2100},
{BinaryOperator::As, 2100},
{BinaryOperator::ShiftLeft, 3000},
{BinaryOperator::ShiftRight, 3000},
@@ -117,10 +125,9 @@ namespace Fig
{BinaryOperator::Subtract, 4000},
{BinaryOperator::Multiply, 4500},
{BinaryOperator::Divide, 4500},
{BinaryOperator::Modulo, 4500},
{BinaryOperator::Power, 5000},
{BinaryOperator::MemberAccess, 40001},
};
return bnbpm;
}
@@ -153,6 +160,8 @@ namespace Fig
case BinaryOperator::BitXorAssign:
case BinaryOperator::Power: return GetBinaryOpLBp(op) - 1;
case BinaryOperator::As: return GetBinaryOpLBp(op) + 1;
default:
/*
左结合, 左绑定力 < 右

View File

@@ -20,6 +20,8 @@ namespace Fig
Negate, // 取反 -
Not, // 逻辑非 ! / not
AddressOf, // 取引用 &
Increment, // ++
Decrement, // --
Count // 哨兵,(int) Count 获得运算符数量注意enum必须从 0 开始且不中断)
};
@@ -60,6 +62,8 @@ namespace Fig
ShiftLeft, // 左移
ShiftRight, // 右移
As, // as
// 成员访问
MemberAccess, // .

View File

@@ -11,34 +11,34 @@
namespace Fig
{
struct Param : public AstNode {
String name;
TypeExpr *typeSpecifier;
Expr *defaultValue;
Type resolvedType;
String name;
Expr *typeSpecifier;
Expr *defaultValue;
Type resolvedType;
Param() { type = AstType::AstNode; }
virtual ~Param() = default;
};
struct PosParam final : public Param {
PosParam(String _n, TypeExpr *_ts, Expr *_dv, SourceLocation _loc) {
PosParam(String _n, Expr *_ts, Expr *_dv, SourceLocation _loc) {
name = std::move(_n); typeSpecifier = _ts; defaultValue = _dv; location = std::move(_loc);
}
virtual String toString() const override { return name; }
};
struct FnDefStmt final : public Stmt {
String name;
String name;
DynArray<Param *> params;
TypeExpr *returnTypeSpecifier;
BlockStmt *body;
Type resolvedReturnType;
Symbol *resolvedSymbol = nullptr; // 连接物理符号
Expr *returnTypeSpecifier;
BlockStmt *body;
Type resolvedReturnType;
Symbol *resolvedSymbol = nullptr; // 连接物理符号
int protoIndex = -1; // 在CompiledModule扁平化protos的下标
DynArray<UpvalueInfo> upvalues;
FnDefStmt() { type = AstType::FnDefStmt; }
FnDefStmt(bool _p, String _n, DynArray<Param *> _pa, TypeExpr *_rt, BlockStmt *_b, SourceLocation _loc)
FnDefStmt(bool _p, String _n, DynArray<Param *> _pa, Expr *_rt, BlockStmt *_b, SourceLocation _loc)
: name(std::move(_n)), params(std::move(_pa)), returnTypeSpecifier(_rt), body(_b)
{
type = AstType::FnDefStmt; isPublic = _p; location = std::move(_loc);

32
src/Ast/Stmt/ForStmt.hpp Normal file
View File

@@ -0,0 +1,32 @@
/*!
@file src/Ast/Stmt/ForStmt.hpp
@brief for loop
@author PuqiAR (im@puqiar.top)
@date 2026-06-06
*/
#pragma once
#include <Ast/Base.hpp>
namespace Fig
{
struct ForStmt final : public Stmt
{
Stmt *init;
Expr *cond;
Expr *step;
BlockStmt *body;
ForStmt() { type = AstType::ForStmt; }
ForStmt(Stmt *_init, Expr *_cond, Expr *_step, BlockStmt *_body, SourceLocation _loc) :
init(_init), cond(_cond), step(_step), body(_body)
{
type = AstType::ForStmt;
location = std::move(_loc);
}
virtual String toString() const override { return "<ForStmt>"; }
};
} // namespace Fig

View File

@@ -11,11 +11,11 @@ namespace Fig
{
struct ImplStmt final : public Stmt
{
TypeExpr *interfaceType;
TypeExpr *structType;
Expr *interfaceType;
Expr *structType;
DynArray<FnDefStmt *> methods;
ImplStmt(TypeExpr *_it, TypeExpr *_st, DynArray<FnDefStmt *> _m, SourceLocation _loc) :
ImplStmt(Expr *_it, Expr *_st, DynArray<FnDefStmt *> _m, SourceLocation _loc) :
interfaceType(_it), structType(_st), methods(std::move(_m))
{
type = AstType::ImplStmt;

View File

@@ -0,0 +1,33 @@
/*!
@file src/Ast/Stmt/ImportStmt.hpp
@brief import
@author PuqiAR (im@puqiar.top)
@date 2026-06-06
*/
#pragma once
#include <Ast/Base.hpp>
namespace Fig
{
struct ImportStmt final : public Stmt
{
String path;
bool isFileImport;
ImportStmt() { type = AstType::ImportStmt; }
ImportStmt(String _path, bool _isFileImport, SourceLocation _loc) :
path(std::move(_path)), isFileImport(_isFileImport)
{
type = AstType::ImportStmt;
location = std::move(_loc);
}
virtual String toString() const override
{
return std::format("<ImportStmt '{}'{}>", path, isFileImport ? " [file]" : "");
}
};
} // namespace Fig

View File

@@ -16,8 +16,8 @@ namespace Fig
struct Method
{
String name;
DynArray<TypeExpr*> params;
TypeExpr *retType;
DynArray<Expr*> params;
Expr *retType;
SourceLocation location;
};

View File

@@ -17,7 +17,7 @@ namespace Fig
bool typeInfer;
String name;
TypeExpr *type;
Expr *type;
Expr *initExpr;
};
bool isPublic;

View File

@@ -15,7 +15,7 @@ namespace Fig
struct VarDecl final : public Stmt
{
String name;
TypeExpr *typeSpecifier;
Expr *typeSpecifier;
bool isInfer; // 是否用了 := 类型推断
Expr *initExpr;
@@ -26,7 +26,7 @@ namespace Fig
type = AstType::VarDecl;
}
VarDecl(bool _isPublic, String _name, TypeExpr *_typeSpecifier, bool _isInfer, Expr *_initExpr, SourceLocation _location) :
VarDecl(bool _isPublic, String _name, Expr *_typeSpecifier, bool _isInfer, Expr *_initExpr, SourceLocation _location) :
name(std::move(_name)),
typeSpecifier(_typeSpecifier),
isInfer(_isInfer),

View File

@@ -12,13 +12,13 @@ namespace Fig
struct NamedTypeExpr final : public TypeExpr
{
DynArray<String> path;
DynArray<TypeExpr *> arguments;
DynArray<Expr *> arguments;
NamedTypeExpr()
{
type = AstType::NamedTypeExpr;
}
NamedTypeExpr(DynArray<String> _p, DynArray<TypeExpr *> _args, SourceLocation _loc) :
NamedTypeExpr(DynArray<String> _p, DynArray<Expr *> _args, SourceLocation _loc) :
path(std::move(_p)), arguments(std::move(_args))
{
type = AstType::NamedTypeExpr;
@@ -51,9 +51,9 @@ namespace Fig
struct NullableTypeExpr final : public TypeExpr
{
TypeExpr *inner;
Expr *inner;
NullableTypeExpr(TypeExpr *_inner, SourceLocation _loc) : inner(_inner)
NullableTypeExpr(Expr *_inner, SourceLocation _loc) : inner(_inner)
{
type = AstType::NullableTypeExpr;
location = std::move(_loc);
@@ -69,10 +69,10 @@ namespace Fig
{
// func (paratypes...) -> return_type
DynArray<TypeExpr *> paraTypes;
TypeExpr *returnType;
DynArray<Expr *> paraTypes;
Expr *returnType;
FnTypeExpr(DynArray<TypeExpr *> _paraTypes, TypeExpr *_returnType) :
FnTypeExpr(DynArray<Expr *> _paraTypes, Expr *_returnType) :
paraTypes(std::move(_paraTypes)), returnType(_returnType)
{
type = AstType::FnTypeExpr;

View File

@@ -1,6 +1,6 @@
/*!
@file src/Compiler/ExprCompiler.cpp
@brief 表达式编译器实现水位线控制Register与零拷贝复用机制
@brief 表达式编译
*/
#include <Ast/Expr/CallExpr.hpp>
@@ -167,7 +167,7 @@ namespace Fig
if (sym->location == SymbolLocation::Local)
{
// 零拷贝直读:如果是临时求值,直接返回变量的物理槽位,禁止产生副本
// no-copy for temp eval
if (target == NO_REG)
return static_cast<Register>(sym->index);
@@ -253,7 +253,7 @@ namespace Fig
&c->location);
}
// 回滚水位线, 释放传参时的临时占用
// free arg temps
current->freereg = mark;
// 目若 target 未指定allocateReg 将复用 baseReg实现零开销回写
@@ -317,7 +317,7 @@ namespace Fig
return r_val;
}
Register mark = current->freereg; // 记录水位线
Register mark = current->freereg; // mark
auto r_l = compileExpr(in->left);
if (!r_l)

View File

@@ -1,6 +1,6 @@
/*!
@file src/Compiler/StmtCompiler.cpp
@brief 语句编译器实现:实装水位线机制,彻底消灭硬编码寄存器释放
@brief 语句编译
*/
#include <Ast/Stmt/FnDefStmt.hpp>
@@ -35,7 +35,7 @@ namespace Fig
auto *v = static_cast<VarDecl *>(stmt);
if (current->enclosing == nullptr) // 处理全局变量
{
Register mark = current->freereg; // 记录水位线
Register mark = current->freereg; // mark
auto regRes = compileExpr(v->initExpr);
if (!regRes)
return std::unexpected(regRes.error());
@@ -74,7 +74,7 @@ namespace Fig
Proto *newProto = new Proto();
newProto->name = f->name;
newProto->numParams = static_cast<uint8_t>(f->params.size());
newProto->maxRegisters = newProto->numParams; // 同步水位线
newProto->maxRegisters = newProto->numParams; // sync
f->protoIndex = static_cast<int>(module->protos.size());
module->protos.push_back(newProto);
@@ -141,7 +141,7 @@ namespace Fig
auto *i = static_cast<IfStmt *>(stmt);
DynArray<int> exitJumps;
Register mark = current->freereg; // 记录水位线
Register mark = current->freereg; // mark
auto r_cond = compileExpr(i->cond);
if (!r_cond)
return std::unexpected(r_cond.error());
@@ -204,7 +204,7 @@ namespace Fig
auto *w = static_cast<WhileStmt *>(stmt);
int startIdx = static_cast<int>(current->proto->code.size());
Register mark = current->freereg; // 记录水位线
Register mark = current->freereg; // mark
auto r_cond = compileExpr(w->cond);
if (!r_cond)
return std::unexpected(r_cond.error());
@@ -228,7 +228,7 @@ namespace Fig
case AstType::ReturnStmt: {
auto *rs = static_cast<ReturnStmt *>(stmt);
Register mark = current->freereg; // 记录水位线
Register mark = current->freereg; // mark
Register retReg;
if (rs->value)
@@ -253,7 +253,7 @@ namespace Fig
}
case AstType::ExprStmt: {
Register mark = current->freereg; // 记录水位线
Register mark = current->freereg; // mark
auto reg = compileExpr(static_cast<ExprStmt *>(stmt)->expr);
if (!reg)
return std::unexpected(reg.error());

View File

@@ -161,7 +161,7 @@ namespace Fig
{
return std::unexpected(type_result.error());
}
TypeExpr *type = *type_result;
Expr *type = *type_result;
if (!match(TokenType::LeftBrace))
{
@@ -175,6 +175,8 @@ namespace Fig
new Point{1, 2}
Named:
new Point{x = 1, y = 2}
Shorthand:
new Point{y, x}
*/
DynArray<NewExpr::Arg> args;
@@ -195,11 +197,12 @@ namespace Fig
break;
}
if (currentToken().isIdentifier() && peekToken().type == TokenType::Assign)
// named arg
if (currentToken().isIdentifier() && peekToken().type == TokenType::Colon)
{
const Token &name_token = consumeToken();
const String &name = srcManager.GetSub(name_token.index, name_token.length);
consumeToken(); // consume `=`
consumeToken(); // consume `:`
SET_STOP_AT(TokenType::Comma, TokenType::RightBrace); // , / }
auto result = parseExpression();
@@ -213,7 +216,20 @@ namespace Fig
*result
});
}
else
// shorthand
else if (currentToken().isIdentifier()
&& (peekToken().type == TokenType::Comma || peekToken().type == TokenType::RightBrace))
{
const Token &name_token = consumeToken();
const String &name = srcManager.GetSub(name_token.index, name_token.length);
IdentiExpr *ident =
arena.Allocate<IdentiExpr>(name, makeSourceLocation(name_token));
args.push_back(NewExpr::Arg{name, ident});
}
else
{
SET_STOP_AT(TokenType::Comma, TokenType::RightBrace); // , / }
auto result = parseExpression();
@@ -226,7 +242,7 @@ namespace Fig
.value = *result
});
}
if (match(TokenType::Comma))
{
@@ -273,7 +289,7 @@ namespace Fig
}
params = *paraResult;
TypeExpr *returnType = nullptr;
Expr *returnType = nullptr;
Token rightArrowToken;
if (match(TokenType::RightArrow)) // ->
{
@@ -332,6 +348,7 @@ namespace Fig
Expr *lhs = nullptr;
Token token = currentToken();
// NUD
if (token.isIdentifier())
{
const auto &lhs_result = parseIdentiExpr();
@@ -350,7 +367,7 @@ namespace Fig
}
lhs = *lhs_result;
}
else if (IsTokenOp(token.type, false)) // 是否是一元运算符
else if (IsTokenOp(token.type, false)) // 是否是一元前缀运算符
{
const auto &lhs_result = parsePrefixExpr();
if (!lhs_result)
@@ -408,6 +425,7 @@ namespace Fig
makeSourceLocation(prevToken())));
}
// LED
while (true)
{
token = currentToken();
@@ -416,57 +434,116 @@ namespace Fig
break;
}
if (IsTokenOp(token.type /* isBinary = true */)) // 是否为二元运算符
// is / as
if (token.type == TokenType::Is || token.type == TokenType::As)
{
BinaryOperator op = TokenToBinaryOp(token);
BindingPower lbp = GetBinaryOpLBp(op);
if (rbp >= lbp)
{
break;
}
consumeToken(); // consume `is` or `as`
auto typeRes = parseTypeExpr();
if (!typeRes)
{
return std::unexpected(typeRes.error());
}
lhs = arena.Allocate<InfixExpr>(lhs, op, *typeRes);
}
// binary
else if (IsTokenOp(token.type /* isBinary = true */))
{
BinaryOperator op = TokenToBinaryOp(token);
BindingPower lbp = GetBinaryOpLBp(op);
if (rbp >= lbp)
{
// 前操作数的右绑定力比当前操作数的左绑定力大
// lhs被吸走
break;
}
auto result = parseInfixExpr(lhs);
if (!result)
{
resetTermintors();
return result;
}
lhs = *result;
}
// 后缀运算符优先级非常大,几乎永远跟在操作数后面,因此我们可以直接结合
// 而不用走正常路径
else if (token.type == TokenType::LeftBracket) // `[`
// [index]
else if (token.type == TokenType::LeftBracket)
{
const auto &expr_result = parseIndexExpr(lhs);
if (!expr_result)
{
resetTermintors();
return expr_result;
}
lhs = *expr_result;
}
else if (token.type == TokenType::LeftParen) // `(`
// call
else if (token.type == TokenType::LeftParen)
{
const auto &expr_result = parseCallExpr(lhs);
if (!expr_result)
{
resetTermintors();
return expr_result;
}
lhs = *expr_result;
}
// .member
else if (token.type == TokenType::Dot)
{
consumeToken(); // consume `.`
if (!currentToken().isIdentifier())
{
return std::unexpected(
makeUnexpectTokenError("MemberExpr", "identifier after `.`", currentToken()));
}
const Token &nameToken = consumeToken();
const String &name =
srcManager.GetSub(nameToken.index, nameToken.length);
SourceLocation loc = makeSourceLocation(nameToken);
lhs = arena.Allocate<MemberExpr>(lhs, name, loc);
}
// x++ x--
else if (token.type == TokenType::DoublePlus || token.type == TokenType::DoubleMinus)
{
UnaryOperator op = TokenToUnaryOp(consumeToken());
lhs = arena.Allocate<PostfixExpr>(op, lhs);
}
// ?:
else if (token.type == TokenType::Question)
{
// ?: 最低优先
// 赋值 rbp = 101所以只有当 rbp < 100 时才可能进到三元
// 实际上三元是最低优先级的非赋值运算符,我们给一个很小的 lbp
constexpr BindingPower TERNARY_LBP = 150;
if (rbp >= TERNARY_LBP)
{
break;
}
consumeToken(); // consume `?`
auto thenRes = parseExpression(0); // 重置绑定力,右结合
if (!thenRes)
{
return std::unexpected(thenRes.error());
}
if (!match(TokenType::Colon))
{
return std::unexpected(
makeUnexpectTokenError("TernaryExpr", "`:` for else branch", currentToken()));
}
auto elseRes = parseExpression(TERNARY_LBP - 1); // 右结合
if (!elseRes)
{
return std::unexpected(elseRes.error());
}
lhs = arena.Allocate<TernaryExpr>(lhs, *thenRes, *elseRes, lhs->location);
}
else
{
// return std::unexpected(Error(ErrorType::ExpectedExpression,
// "expression unexpectedly ended",
// "insert expressions",
// makeSourceLocation(token)));
return lhs;
}
}
return lhs;
}
}; // namespace Fig
}; // namespace Fig

View File

@@ -15,12 +15,16 @@ namespace Fig
while (currentToken().type != TokenType::EndOfFile)
{
if (lexerError)
{
return std::unexpected(*lexerError);
}
auto result = parseStatement();
if (!result)
{
return std::unexpected(result.error());
}
Stmt *stmt = *result;
if (stmt)
{

View File

@@ -35,6 +35,7 @@ namespace Fig
bool isEOF = false;
Diagnostics &diagnostics;
std::optional<Error> lexerError; // 词法错误缓存,避免 exit/abort
// 惰性获取下一个 Token跳过注释
Token nextToken()
@@ -49,8 +50,12 @@ namespace Fig
auto result = lexer.NextToken();
if (!result)
{
ReportError(result.error(), srcManager);
std::exit(-1);
lexerError = result.error();
isEOF = true;
Token eof = {0, 0, TokenType::EndOfFile};
buffer.push_back(eof);
index = buffer.size() - 1;
return buffer[index];
}
const Token &token = result.value();
if (token.type == TokenType::Comments)
@@ -84,8 +89,12 @@ namespace Fig
auto result = lexer.NextToken();
if (!result)
{
ReportError(result.error(), srcManager);
std::abort();
lexerError = result.error();
isEOF = true;
Token eof = {0, 0, TokenType::EndOfFile};
buffer.push_back(eof);
index = buffer.size() - 1;
return buffer.back();
}
if (result->type == TokenType::Comments)
continue;
@@ -158,20 +167,10 @@ namespace Fig
return baseTerminators;
}
std::unordered_set<TokenType> &getTerminators()
{
static std::unordered_set<TokenType> terminators(getBaseTerminators());
return terminators;
}
void resetTermintors()
{
getTerminators() = getBaseTerminators();
}
bool shouldTerminate()
{
const Token &token = currentToken();
if (getTerminators().contains(token.type))
if (getBaseTerminators().contains(token.type))
return true;
for (auto it = stateStack.rbegin(); it < stateStack.rend(); ++it)
{
@@ -261,9 +260,9 @@ namespace Fig
Result<decltype(StructDefStmt::typeParameters), Error> parseTypeParameters();
Result<TypeExpr *, Error> parseTypeExpr();
Result<TypeExpr *, Error> parseNamedTypeExpr();
Result<TypeExpr *, Error> parseFnTypeExpr();
Result<Expr *, Error> parseTypeExpr();
Result<Expr *, Error> parseNamedTypeExpr();
Result<Expr *, Error> parseFnTypeExpr();
Result<Expr *, Error> parseExpression(BindingPower = 0);
Result<Expr *, Error> parseLiteralExpr();
@@ -277,6 +276,7 @@ namespace Fig
Result<BlockStmt *, Error> parseBlockStmt();
Result<VarDecl *, Error> parseVarDecl(bool);
Result<VarDecl *, Error> parseConstDecl(bool);
Result<IfStmt *, Error> parseIfStmt();
Result<WhileStmt *, Error> parseWhileStmt();
Result<DynArray<Param *>, Error> parseFnParams();
@@ -286,6 +286,8 @@ namespace Fig
Result<Stmt *, Error> parseStructDef(bool);
Result<Stmt *, Error> parseInterfaceDef(bool);
Result<Stmt *, Error> parseImpl();
Result<Stmt *, Error> parseForStmt();
Result<Stmt *, Error> parseImportStmt();
Result<Stmt *, Error> parseStatement();

View File

@@ -5,24 +5,25 @@ int main()
{
using namespace Fig;
String fileName = "test.fig";
String filePath = "T:/Files/Maker/Code/MyCodingLanguage/The Fig Project/Fig/test.fig";
String fileName = "test.fig";
String filePath =
"T:/Files/Maker/Code/MyCodingLanguage/The Fig Project/Fig/" + fileName;
SourceManager srcManager(filePath);
String source = srcManager.Read();
if (!srcManager.read)
{
std::cerr << "Couldn't read file";
std::cerr << "Couldn't read file: " << filePath << '\n';
return 1;
}
Lexer lexer(source, fileName);
Lexer lexer(source, fileName);
Diagnostics diagnostics;
Parser parser(lexer, srcManager, fileName, diagnostics);
auto result = parser.Parse();
auto result = parser.Parse();
if (!result)
{
ReportError(result.error(), srcManager);
@@ -32,8 +33,11 @@ int main()
diagnostics.EmitAll(srcManager);
Program *program = *result;
for (Stmt *stmt : program->nodes)
std::cout << "Parsed " << program->nodes.size() << " statements\n";
for (size_t i = 0; i < program->nodes.size(); ++i)
{
std::cout << stmt->toString() << '\n';
std::cout << '[' << i << "] " << program->nodes[i]->toString() << '\n';
}
}
return 0;
}

View File

@@ -50,7 +50,7 @@ namespace Fig
const String &name = srcManager.GetSub(currentToken().index, currentToken().length);
consumeToken();
TypeExpr *typeSpeicifer = nullptr;
Expr *typeSpeicifer = nullptr;
if (match(TokenType::Colon))
{
auto result = parseTypeExpr();
@@ -99,6 +99,79 @@ namespace Fig
return varDecl;
}
Result<VarDecl *, Error> Parser::parseConstDecl(bool isPublic)
{
// must init
StateProtector p(this, {State::ParsingVarDecl});
SourceLocation location = makeSourceLocation(consumeToken()); // consume `const`
if (currentToken().type != TokenType::Identifier)
{
return std::unexpected(makeUnexpectTokenError("ConstDecl", "const name", currentToken()));
}
const String &name = srcManager.GetSub(currentToken().index, currentToken().length);
consumeToken();
Expr *typeSpecifier = nullptr;
if (match(TokenType::Colon))
{
auto result = parseTypeExpr();
if (!result)
{
return std::unexpected(result.error());
}
typeSpecifier = *result;
}
Expr *initExpr = nullptr;
bool isInfer = false;
if (match(TokenType::Assign))
{
auto result = parseExpression();
if (!result)
{
return std::unexpected(result.error());
}
initExpr = *result;
}
else if (match(TokenType::Walrus))
{
if (typeSpecifier)
{
return std::unexpected(Error(
ErrorType::SyntaxError,
"used type infer but specifying the type",
"change `:=` to '='",
makeSourceLocation(prevToken())));
}
auto result = parseExpression();
if (!result)
{
return std::unexpected(result.error());
}
initExpr = *result;
isInfer = true;
}
else
{
return std::unexpected(Error(
ErrorType::SyntaxError,
"const must be initialized",
"add '=' and an initializer expression",
makeSourceLocation(prevToken())));
}
if (!match(TokenType::Semicolon))
{
return std::unexpected(makeExpectSemicolonError());
}
VarDecl *varDecl =
arena.Allocate<VarDecl>(isPublic, name, typeSpecifier, isInfer, initExpr, location);
return varDecl;
}
Result<IfStmt *, Error> Parser::parseIfStmt()
{
StateProtector p(this, {State::ParsingIf});
@@ -294,6 +367,123 @@ namespace Fig
return whileStmt;
}
Result<Stmt *, Error> Parser::parseForStmt()
{
SourceLocation location = makeSourceLocation(consumeToken()); // consume `for`
// 括号可选
bool hasParen = match(TokenType::LeftParen);
// init: var decl 或 表达式语句(或空)
Stmt *init = nullptr;
if (currentToken().type == TokenType::Variable)
{
auto result = parseVarDecl(false);
if (!result)
return std::unexpected(result.error());
init = *result;
}
else if (currentToken().type == TokenType::Semicolon)
{
// 空 init跳过
}
else if (!isEOF)
{
// 表达式作为 init
auto result = parseExpression();
if (!result)
return std::unexpected(result.error());
init = arena.Allocate<ExprStmt>(*result);
if (!match(TokenType::Semicolon))
return std::unexpected(makeExpectSemicolonError());
}
// 要求分号分隔
if (!init && currentToken().type != TokenType::Semicolon)
{
// 如果不是 var decl 且下一个不是分号,尝试作为表达式解析并消耗分号
// 实际上 init 为 nullptr 的情况就是空 init此时应该已经有分号了
}
if (init)
{
}
else
{
if (!match(TokenType::Semicolon))
{
return std::unexpected(makeExpectSemicolonError());
}
}
// cond: 表达式(或空)
Expr *cond = nullptr;
SET_STOP_AT(TokenType::Semicolon);
if (currentToken().type != TokenType::Semicolon)
{
auto result = parseExpression();
if (!result)
return std::unexpected(result.error());
cond = *result;
}
// 确保下一个是分号
if (currentToken().type == TokenType::Semicolon)
{
// continue
}
if (!match(TokenType::Semicolon))
{
return std::unexpected(makeExpectSemicolonError());
}
// step: 表达式(或空)
Expr *step = nullptr;
if (hasParen)
{
SET_STOP_AT(TokenType::RightParen);
}
else
{
SET_STOP_AT(TokenType::LeftBrace);
}
if (hasParen && currentToken().type == TokenType::RightParen)
{
// 空 step
}
else if (!hasParen && currentToken().type == TokenType::LeftBrace)
{
// 空 step直接进入 body
}
else if (!isEOF)
{
auto result = parseExpression();
if (!result)
return std::unexpected(result.error());
step = *result;
}
if (hasParen && !match(TokenType::RightParen))
{
return std::unexpected(
makeUnexpectTokenError("for stmt", "`)` to close", currentToken()));
}
if (currentToken().type != TokenType::LeftBrace)
{
return std::unexpected(
makeUnexpectTokenError("for stmt", "left brace `{`", currentToken()));
}
auto bodyRes = parseBlockStmt();
if (!bodyRes)
{
return std::unexpected(bodyRes.error());
}
ForStmt *forStmt = arena.Allocate<ForStmt>(init, cond, step, *bodyRes, location);
return forStmt;
}
Result<DynArray<Param *>, Error> Parser::parseFnParams()
{
const Token &lpToken = consumeToken();
@@ -318,7 +508,7 @@ namespace Fig
SourceLocation location = makeSourceLocation(nToken);
const String &name = srcManager.GetSub(nToken.index, nToken.length);
TypeExpr *type = nullptr;
Expr *type = nullptr;
if (match(TokenType::Colon))
{
auto result = parseTypeExpr();
@@ -345,8 +535,32 @@ namespace Fig
PosParam *posParam = arena.Allocate<PosParam>(name, type, defaultValue, location);
params.push_back(posParam);
// 可变参数: ... (跟在最后一个参数后面)
if (match(TokenType::TripleDot))
{
// 标记最后一个参数为可变参数
// 通过 VarParam 标记
// 当前用 VarParam 包装最后一个 param
// 简单方案:创建一个带 variadic 标记的 param
// TODO: 改用专门的 VarParam AST 节点
// 暂时用 flag 标记在 posParam 上
if (!match(TokenType::RightParen))
{
return std::unexpected(
makeUnexpectTokenError("fn params", "`)` after `...`", currentToken()));
}
// 直接返回,可变参数后面不能再有参数
break;
}
if (match(TokenType::Comma))
{
if (match(TokenType::RightParen))
{
// 尾部逗号允许,如 func(a, b,)
break;
}
if (!currentToken().isIdentifier())
{
return std::unexpected(
@@ -385,7 +599,7 @@ namespace Fig
}
params = *paraResult;
TypeExpr *returnType = nullptr;
Expr *returnType = nullptr;
if (match(TokenType::RightArrow))
{
auto result = parseTypeExpr();
@@ -405,11 +619,6 @@ namespace Fig
return std::unexpected(result.error());
}
// if (!match(TokenType::Semicolon)) // ;
// {
// return std::unexpected(makeExpectSemicolonError(prevToken()));
// }
if (match(TokenType::Semicolon))
{
diagnostics.Report(Error(
@@ -518,7 +727,7 @@ namespace Fig
// (public) field_name (: Type) (= expr) / (:= expr)
bool isPublic = match(TokenType::Public);
bool isPublicField = match(TokenType::Public);
if (currentToken().isIdentifier())
{
const Token &name_tok = consumeToken();
@@ -533,11 +742,11 @@ namespace Fig
}
stDef->fields.push_back(
StructDefStmt::Field{isPublic, true, field_name, nullptr, *result});
StructDefStmt::Field{isPublicField, true, field_name, nullptr, *result});
}
else
{
TypeExpr *type = nullptr;
Expr *type = nullptr;
Expr *initExpr = nullptr;
if (match(TokenType::Colon)) // :
@@ -560,7 +769,7 @@ namespace Fig
initExpr = *result;
}
stDef->fields.push_back(
StructDefStmt::Field{isPublic, false, field_name, type, initExpr});
StructDefStmt::Field{isPublicField, false, field_name, type, initExpr});
}
if (!match(TokenType::Semicolon))
{
@@ -569,7 +778,7 @@ namespace Fig
}
else if (currentToken().type == TokenType::Function)
{
auto result = parseFnDefStmt(isPublic);
auto result = parseFnDefStmt(isPublicField);
if (!result)
{
return result;
@@ -587,113 +796,444 @@ namespace Fig
return stDef;
}
Result<Stmt *, Error> Parser::parseStatement()
Result<Stmt *, Error> Parser::parseInterfaceDef(bool isPublic)
{
StateProtector p(this, {State::Standby});
SourceLocation location = makeSourceLocation(consumeToken()); // consume `interface`
if (currentToken().type == TokenType::Public)
if (!currentToken().isIdentifier())
{
consumeToken();
if (currentToken().type == TokenType::Variable)
{
return parseVarDecl(true);
}
if (currentToken().type == TokenType::Function)
{
return parseFnDefStmt(true);
}
if (currentToken().type == TokenType::Struct)
{
return parseStructDef(true);
}
return std::unexpected(
makeUnexpectTokenError("public", "var/const/func/struct", currentToken()));
makeUnexpectTokenError("InterfaceDef", "interface name", currentToken()));
}
if (currentToken().type == TokenType::LeftBrace)
const Token &nameToken = consumeToken();
const String &name = srcManager.GetSub(nameToken.index, nameToken.length);
if (!match(TokenType::LeftBrace))
{
return parseBlockStmt();
return std::unexpected(
makeUnexpectTokenError("InterfaceDef", "lbrace '{'", currentToken()));
}
if (currentToken().type == TokenType::Variable)
{
return parseVarDecl(false);
}
const Token &lbToken = prevToken();
if (currentToken().type == TokenType::If)
{
return parseIfStmt();
}
InterfaceDefStmt *ifaceDef = arena.Allocate<InterfaceDefStmt>();
ifaceDef->isPublic = isPublic;
ifaceDef->name = name;
ifaceDef->location = location;
if (currentToken().type == TokenType::While)
while (true)
{
return parseWhileStmt();
}
if (isEOF)
{
return std::unexpected(Error(
ErrorType::SyntaxError,
"unclosed braces in interface def",
"insert '}'",
makeSourceLocation(lbToken)));
}
if (match(TokenType::RightBrace))
{
break;
}
if (currentToken().type == TokenType::Function && peekToken().isIdentifier())
{
return parseFnDefStmt(false);
}
// interface 方法需要 `func` 关键字
if (currentToken().type != TokenType::Function)
{
return std::unexpected(
makeUnexpectTokenError("InterfaceDef", "`func` for method", currentToken()));
}
consumeToken(); // consume `func`
if (currentToken().type == TokenType::Struct)
{
return parseStructDef(false);
}
if (!currentToken().isIdentifier())
{
return std::unexpected(
makeUnexpectTokenError("InterfaceDef", "method name", currentToken()));
}
if (currentToken().type == TokenType::Return)
{
return parseReturnStmt();
}
const Token &methodNameToken = consumeToken();
const String &methodName =
srcManager.GetSub(methodNameToken.index, methodNameToken.length);
if (match(TokenType::Break))
{
SourceLocation location = makeSourceLocation(prevToken());
if (!match(TokenType::Semicolon))
// 参数列表
if (!match(TokenType::LeftParen))
{
return std::unexpected(
makeUnexpectTokenError("InterfaceDef", "`(` for method params", currentToken()));
}
// 解析参数类型(接口方法只声明类型,无参数名)
DynArray<InterfaceDefStmt::Method> methods; // placeholder
DynArray<Expr *> paramTypes;
while (true)
{
if (isEOF)
{
return std::unexpected(Error(
ErrorType::SyntaxError,
"unclosed parenthese in interface method",
"insert ')'",
makeSourceLocation(methodNameToken)));
}
if (match(TokenType::RightParen))
{
break;
}
// 参数: name : Type
if (!currentToken().isIdentifier())
{
return std::unexpected(
makeUnexpectTokenError("InterfaceDef", "param name", currentToken()));
}
consumeToken(); // consume param name (unused in interface)
Expr *paramType = nullptr;
if (match(TokenType::Colon))
{
auto res = parseTypeExpr();
if (!res)
return std::unexpected(res.error());
paramType = *res;
}
// 接口方法参数类型可选(如果没有标注则默认 Any
paramTypes.push_back(paramType);
if (match(TokenType::Comma))
{
if (match(TokenType::RightParen))
break; // 尾部逗号
}
}
// 返回类型(接口方法必须有返回类型)
Expr *returnType = nullptr;
if (match(TokenType::RightArrow))
{
auto res = parseTypeExpr();
if (!res)
return std::unexpected(res.error());
returnType = *res;
}
else
{
return std::unexpected(Error(
ErrorType::SyntaxError,
"interface method must specify return type with `->`",
"add `-> ReturnType`",
makeSourceLocation(methodNameToken)));
}
// 默认实现?(方法签名后直接跟 `{` 表示默认实现)
BlockStmt *defaultBody = nullptr;
if (currentToken().type == TokenType::LeftBrace)
{
auto bodyRes = parseBlockStmt();
if (!bodyRes)
return std::unexpected(bodyRes.error());
defaultBody = *bodyRes;
}
else if (!match(TokenType::Semicolon))
{
return std::unexpected(makeExpectSemicolonError());
}
BreakStmt *breakStmt = arena.Allocate<BreakStmt>(location);
return breakStmt;
// 构建方法签名
InterfaceDefStmt::Method method;
method.name = methodName;
method.params = paramTypes;
method.retType = returnType;
method.location = makeSourceLocation(methodNameToken);
ifaceDef->methods.push_back(std::move(method));
// TODO: 存储默认实现体的 AST
// 当前 InterfaceDefStmt::Method 没有 body 字段
// 如果需要默认实现,需要扩展 AST
(void) defaultBody;
}
if (match(TokenType::Continue))
return ifaceDef;
}
Result<Stmt *, Error> Parser::parseImpl()
{
SourceLocation location = makeSourceLocation(consumeToken()); // consume `impl`
// impl InterfaceName for StructName { methods... }
auto interfaceTypeRes = parseTypeExpr();
if (!interfaceTypeRes)
return std::unexpected(interfaceTypeRes.error());
Expr *interfaceType = *interfaceTypeRes;
if (!match(TokenType::For))
{
SourceLocation location = makeSourceLocation(prevToken());
if (!match(TokenType::Semicolon))
return std::unexpected(
makeUnexpectTokenError("ImplStmt", "`for` keyword", currentToken()));
}
auto structTypeRes = parseTypeExpr();
if (!structTypeRes)
return std::unexpected(structTypeRes.error());
Expr *structType = *structTypeRes;
if (!match(TokenType::LeftBrace))
{
return std::unexpected(
makeUnexpectTokenError("ImplStmt", "lbrace `{`", currentToken()));
}
const Token &lbToken = prevToken();
DynArray<FnDefStmt *> methods;
while (true)
{
if (isEOF)
{
return std::unexpected(makeExpectSemicolonError());
return std::unexpected(Error(
ErrorType::SyntaxError,
"unclosed braces in impl block",
"insert '}'",
makeSourceLocation(lbToken)));
}
ContinueStmt *continueStmt = arena.Allocate<ContinueStmt>(location);
return continueStmt;
if (match(TokenType::RightBrace))
{
break;
}
// impl 方法需要 `func` 关键字
if (currentToken().type != TokenType::Function)
{
return std::unexpected(
makeUnexpectTokenError("ImplStmt", "`func` for method", currentToken()));
}
consumeToken(); // consume `func`
if (!currentToken().isIdentifier())
{
return std::unexpected(
makeUnexpectTokenError("ImplStmt", "method name", currentToken()));
}
const Token &methodNameToken = consumeToken();
const String &methodName =
srcManager.GetSub(methodNameToken.index, methodNameToken.length);
// 参数列表
if (!match(TokenType::LeftParen))
{
return std::unexpected(
makeUnexpectTokenError("ImplStmt", "`(` for method params", currentToken()));
}
// 复用 FnDefStmt 来解析 impl 方法
// 但我们不使用 parseFnDefStmt因为 impl 方法:
// 1. 不写返回类型(由 interface 约束)
// 2. 必须有函数体({ }
DynArray<Param *> fnParams;
while (true)
{
if (isEOF)
{
return std::unexpected(Error(
ErrorType::SyntaxError,
"unclosed parenthese in impl method params",
"insert ')'",
makeSourceLocation(methodNameToken)));
}
if (match(TokenType::RightParen))
{
break;
}
if (!currentToken().isIdentifier())
{
return std::unexpected(
makeUnexpectTokenError("ImplStmt", "param name", currentToken()));
}
const Token &pToken = consumeToken();
const String &pName = srcManager.GetSub(pToken.index, pToken.length);
Expr *pType = nullptr;
if (match(TokenType::Colon))
{
auto res = parseTypeExpr();
if (!res)
return std::unexpected(res.error());
pType = *res;
}
PosParam *param = arena.Allocate<PosParam>(
pName, pType, nullptr, makeSourceLocation(pToken));
fnParams.push_back(param);
if (match(TokenType::Comma))
{
if (match(TokenType::RightParen))
break; // 尾部逗号
}
}
// impl 方法不写返回类型,必须有函数体
BlockStmt *methodBody = nullptr;
if (currentToken().type == TokenType::LeftBrace)
{
auto bodyRes = parseBlockStmt();
if (!bodyRes)
return std::unexpected(bodyRes.error());
methodBody = *bodyRes;
}
else
{
return std::unexpected(
makeUnexpectTokenError("ImplStmt", "`{` for method body", currentToken()));
}
FnDefStmt *fnDef = arena.Allocate<FnDefStmt>(
false, methodName, fnParams, nullptr /* no return type */, methodBody,
makeSourceLocation(methodNameToken));
methods.push_back(fnDef);
}
if (isEOF)
ImplStmt *implStmt = arena.Allocate<ImplStmt>(interfaceType, structType, methods, location);
return implStmt;
}
Result<Stmt *, Error> Parser::parseImportStmt()
{
SourceLocation location = makeSourceLocation(consumeToken()); // consume `import`
bool isFileImport = false;
String path;
if (currentToken().type == TokenType::LiteralString)
{
return nullptr;
// import "path/to/file.fig" — 文件导入
isFileImport = true;
const Token &strToken = consumeToken();
path = srcManager.GetSub(strToken.index, strToken.length);
}
else if (currentToken().isIdentifier())
{
// import std.io — Module 导入
isFileImport = false;
// 收集完整的路径: a.b.c
while (true)
{
const Token &tok = consumeToken();
path += srcManager.GetSub(tok.index, tok.length);
if (currentToken().type == TokenType::Dot)
{
path += ".";
consumeToken(); // consume `.`
}
else
{
break;
}
}
}
else
{
return std::unexpected(
makeUnexpectTokenError("ImportStmt", "module path or file string", currentToken()));
}
if (currentToken().type == TokenType::Semicolon)
{
return std::unexpected(Error(
ErrorType::SyntaxError,
"null statement is not allowed here",
"remove `;`",
makeSourceLocation(currentToken())));
}
const auto &expr_result = parseExpression();
if (!expr_result)
{
return std::unexpected(expr_result.error());
}
ExprStmt *exprStmt = arena.Allocate<ExprStmt>(*expr_result);
if (!match(TokenType::Semicolon))
{
return std::unexpected(makeExpectSemicolonError());
}
ImportStmt *importStmt = arena.Allocate<ImportStmt>(path, isFileImport, location);
return importStmt;
}
Result<Stmt *, Error> Parser::parseStatement()
{
StateProtector p(this, {State::Standby});
bool isPublic = match(TokenType::Public);
TokenType tt = currentToken().type;
switch (tt)
{
case TokenType::LeftBrace: return parseBlockStmt();
case TokenType::If: return parseIfStmt();
case TokenType::While: return parseWhileStmt();
case TokenType::For: return parseForStmt();
case TokenType::Import: return parseImportStmt();
case TokenType::Interface: return parseInterfaceDef(isPublic);
case TokenType::Implement: return parseImpl();
case TokenType::Variable: return parseVarDecl(isPublic);
case TokenType::Const: return parseConstDecl(isPublic);
case TokenType::Return:
{
return parseReturnStmt();
}
case TokenType::Function:
{
// 需要 lookahead: `func identifier` → 函数定义
// `func (` 或 `func {` → Lambda 表达式语句
if (peekToken().isIdentifier())
return parseFnDefStmt(isPublic);
goto expr_stmt;
}
case TokenType::Struct:
return parseStructDef(isPublic);
case TokenType::Break:
{
consumeToken();
SourceLocation loc = makeSourceLocation(prevToken());
if (!match(TokenType::Semicolon))
return std::unexpected(makeExpectSemicolonError());
return static_cast<Stmt *>(arena.Allocate<BreakStmt>(loc));
}
case TokenType::Continue:
{
consumeToken();
SourceLocation loc = makeSourceLocation(prevToken());
if (!match(TokenType::Semicolon))
return std::unexpected(makeExpectSemicolonError());
return static_cast<Stmt *>(arena.Allocate<ContinueStmt>(loc));
}
case TokenType::EndOfFile:
return nullptr;
case TokenType::Semicolon:
return std::unexpected(Error(
ErrorType::SyntaxError,
"null statement is not allowed here",
"remove `;`",
makeSourceLocation(currentToken())));
default:
break;
}
expr_stmt:
{
// 表达式语句 (fallback)
const auto &expr_result = parseExpression();
if (!expr_result)
return std::unexpected(expr_result.error());
ExprStmt *exprStmt = arena.Allocate<ExprStmt>(*expr_result);
if (!match(TokenType::Semicolon))
return std::unexpected(makeExpectSemicolonError());
return exprStmt;
}
}; // namespace Fig
}
}; // namespace Fig

View File

@@ -1,8 +1,8 @@
/*!
@file src/Parser/TypeExprParser.cpp
@brief 类型表达式解析器实现:支持泛型与空安全
@brief 类型表达式解析器实现 — 类型即值,产生 Expr* 而非 TypeExpr*
@author PuqiAR (im@puqiar.top)
@date 2026-03-08
@date 2026-06-06
*/
#include <Parser/Parser.hpp>
@@ -49,38 +49,51 @@ namespace Fig
return tp;
}
// 解析基础命名类型与泛型: List<Int>
Result<TypeExpr *, Error> Parser::parseNamedTypeExpr()
Result<Expr *, Error> Parser::parseNamedTypeExpr()
{
StateProtector p(this, {State::ParsingNamedTypeExpr});
SourceLocation location = makeSourceLocation(currentToken());
DynArray<String> path;
while (true)
if (!currentToken().isIdentifier())
{
const Token &tok = consumeToken();
const String &name = srcManager.GetSub(tok.index, tok.length);
path.push_back(name);
if (match(TokenType::Dot))
{
if (!currentToken().isIdentifier())
return std::unexpected(
makeUnexpectTokenError("Type", "identifier", currentToken()));
}
else
break;
return std::unexpected(
makeUnexpectTokenError("TypeExpr", "type name", currentToken()));
}
DynArray<TypeExpr *> arguments;
if (match(TokenType::Less)) // `<`
const Token &firstTok = consumeToken();
SourceLocation firstLoc = makeSourceLocation(firstTok);
const String &firstName = srcManager.GetSub(firstTok.index, firstTok.length);
IdentiExpr *ident = arena.Allocate<IdentiExpr>(firstName, firstLoc);
Expr *base = ident;
// a.b.c
while (match(TokenType::Dot))
{
if (!currentToken().isIdentifier())
{
return std::unexpected(
makeUnexpectTokenError("TypeExpr", "identifier after `.`", currentToken()));
}
const Token &tok = consumeToken();
const String &name = srcManager.GetSub(tok.index, tok.length);
SourceLocation loc = makeSourceLocation(tok);
base = arena.Allocate<MemberExpr>(base, name, loc);
}
// generic args
if (match(TokenType::Less))
{
DynArray<Expr *> args;
while (true)
{
auto result = parseTypeExpr();
if (!result)
return std::unexpected(result.error());
arguments.push_back(*result);
args.push_back(*result);
if (match(TokenType::Greater))
break; // `>`
@@ -88,12 +101,14 @@ namespace Fig
return std::unexpected(
makeUnexpectTokenError("TypeArgs", "'>' or ','", currentToken()));
}
base = arena.Allocate<ApplyExpr>(base, std::move(args), firstLoc);
}
return arena.Allocate<NamedTypeExpr>(path, arguments, location);
return base;
}
Result<TypeExpr *, Error> Parser::parseFnTypeExpr()
Result<Expr *, Error> Parser::parseFnTypeExpr()
{
StateProtector p(this, {State::ParsingFnTypeExpr});
SourceLocation location = makeSourceLocation(consumeToken()); // consume `func`
@@ -103,7 +118,7 @@ namespace Fig
makeUnexpectTokenError("FnTypeExpr", "lparen (", currentToken()));
}
DynArray<TypeExpr *> paraTypes;
DynArray<Expr *> paraTypes;
while (true)
{
@@ -130,7 +145,7 @@ namespace Fig
}
}
TypeExpr *returnType = nullptr;
Expr *returnType = nullptr;
if (match(TokenType::RightArrow)) // ->
{
@@ -146,10 +161,10 @@ namespace Fig
return fnTypeExpr;
}
// 解析主入口: 处理 `?` 后缀
Result<TypeExpr *, Error> Parser::parseTypeExpr()
Result<Expr *, Error> Parser::parseTypeExpr()
{
TypeExpr *base = nullptr;
Expr *base = nullptr;
if (currentToken().isIdentifier())
{
@@ -174,10 +189,10 @@ namespace Fig
return std::unexpected(makeUnexpectTokenError("TypeExpr", "name", currentToken()));
}
// type (?)
// nullable
if (currentToken().type == TokenType::Question) // ?
{
base = arena.Allocate<NullableTypeExpr>(
base = arena.Allocate<NullableExpr>(
base, makeSourceLocation(consumeToken())); // consume `?`
}

View File

@@ -678,7 +678,7 @@ namespace Fig
return idx;
}
Result<Type, Error> Analyzer::resolveTypeExpr(TypeExpr *texpr)
Result<Type, Error> Analyzer::resolveTypeExpr(Expr *texpr)
{
if (!texpr)
return typeCtx.GetBasic(TypeTag::Any);

View File

@@ -32,7 +32,7 @@ namespace Fig
// 核心递归查找:解决跨越函数边界的捕获问题
Result<Symbol*, Error> resolveSymbolInternal(const String &name, const SourceLocation &loc, Scope* startScope);
Result<Type, Error> resolveTypeExpr(TypeExpr *texpr);
Result<Type, Error> resolveTypeExpr(Expr *texpr);
Result<void, Error> pass1(Program *prog);
Result<void, Error> resolveTypes(Program *prog);
Result<void, Error> checkBodies(Program *prog);

View File

@@ -0,0 +1,232 @@
/* ==============================
Fig Parser Comprehensive Test
============================== */
// --- 单行注释 ---
/* ---
多行注释
--- */
// ─────────────────────────────────
// 1. 变量声明 var
// ─────────────────────────────────
var x; // Any, 无初始化
var a = 10; // 推断 Int
var b: Int = 20; // 显式类型
var c := 30; // 类型推断锁定
var d: Int; // 显式类型,无初始化
var e = "hello"; // 推断 String
var f = true; // 推断 Bool
var g = null; // 推断 Null
// ─────────────────────────────────
// 2. 常量声明 const
// ─────────────────────────────────
const PI = 3.14159; // 推断 Double
const MAX: Int = 100; // 显式类型
const NAME := "Fig"; // 类型推断锁定
const T: Double = 2.718; // 显式类型
// ─────────────────────────────────
// 3. 函数定义 func
// ─────────────────────────────────
func noop() {}
func add(a: Int, b: Int) -> Int { return a + b; }
func greet(name: String) -> String { return "Hello " + name + "!"; }
func quick(x) => x * 2; // 箭头简写
func noReturn() -> Null { return null; }
// ─────────────────────────────────
// 4. Lambda 表达式
// ─────────────────────────────────
var lambda1 = func(x, y) => x + y;
var lambda2 = func(x: Int) { return x * x; };
// ─────────────────────────────────
// 5. 控制流 if / while / for
// ─────────────────────────────────
func testControlFlow() {
// if-else
if true { var z = 1; }
if (x > 0) { var z = 2; }
if a > 10 { return 1; }
else if a > 5 { return 2; }
else { return 3; }
// while
while a < 10 { a = a + 1; }
while (a > 0) { a = a - 1; }
// for (C风格括号可选)
for var i = 0; i < 10; i = i + 1 { var _ = i; }
for (var j = 0; j < 5; j += 1) { var _ = j; }
for ; ; { break; } // 无限循环
// break / continue
while true { break; }
while true { continue; }
return 0;
}
// ─────────────────────────────────
// 6. 表达式运算符
// ─────────────────────────────────
func testOperators() -> Int {
var r = 0;
// 算术
r = 1 + 2;
r = 3 - 1;
r = 2 * 3;
r = 6 / 2;
r = 7 % 3;
r = 2 ** 3; // 幂运算
// 比较
var b1 = 1 == 1;
var b2 = 1 != 2;
var b3 = 1 < 2;
var b4 = 2 > 1;
var b5 = 1 <= 1;
var b6 = 2 >= 1;
// 逻辑
var l1 = true and false;
var l2 = true or false;
var l3 = not true;
var l4 = true && false; // &&
var l5 = true || false; // ||
// 复合赋值
r += 1;
r -= 1;
r *= 2;
r /= 2;
r %= 1;
r ^= 1;
// 位运算
var w1 = 1 & 2;
var w2 = 1 | 2;
var w3 = 1 ^ 2;
var w4 = ~1;
var w5 = 1 << 2;
var w6 = 4 >> 1;
// 前后缀 ++/--
var p = 0;
var pre = ++p;
var post = p--;
var n = --p;
// 前缀取反
var neg = -100;
var notExpr = not true;
// 三元
var t = a > 5 ? 1 : 0;
// 成员访问
var m = someObj.field;
// 类型检查 / 转换
var check = x is Int;
var cast = x as String;
// 索引
var idx = arr[0];
// 函数调用
var callRes = add(1, 2);
// 分组
var grouped = (1 + 2) * 3;
return r;
}
// ─────────────────────────────────
// 7. struct 结构体
// ─────────────────────────────────
struct Point {
public x: Int;
public y: Int;
public func toString() -> String {
return "(" + "x" + "," + "y" + ")";
}
}
struct Person {
name: String;
age: Int = 18; // 默认值
public func getName() -> String {
return name;
}
}
// ─────────────────────────────────
// 8. new 表达式
// ─────────────────────────────────
func testNewExpr() {
var p1 = new Point{1, 2}; // 位置参数
var p2 = new Point{x: 2, y: 3}; // 命名参数
var xx = 114;
var yy = 514;
var p3 = new Point{yy, xx}; // 简写
var p4 = new Point{}; // 空构造
}
// ─────────────────────────────────
// 9. interface 接口
// ─────────────────────────────────
interface Drawable {
func draw() -> String;
func getLayer() -> Int;
}
interface Printable {
func toString() -> String;
func getVersion() -> Int {
return 1;
}
}
// ─────────────────────────────────
// 10. impl 实现
// ─────────────────────────────────
struct Circle {
public radius: Double;
}
impl Drawable for Circle {
func draw() {
return "circle";
}
func getLayer() {
return 0;
}
}
// ─────────────────────────────────
// 11. import 导入
// ─────────────────────────────────
import std.io;
import "path/to/file.fig";
// ─────────────────────────────────
// 12. 闭包与嵌套函数
// ─────────────────────────────────
func outer(x: Int) -> Function {
func inner(n: Int) -> Int {
return n * x;
}
return inner;
}
var closureMaker = func(factor: Int) {
return func(n) => n * factor;
};