Refactor: 重构Parser和AST结构,以支持新的语言特性
- 更新了 ParserTest,以改进文件路径处理和输出格式。 - 在 StmtParser 中新增了 parseConstDecl 和 parseForStmt 方法,用于处理常量声明和 for 循环。 - TypeExpr现归类为Expr。TypeExpr属于Expr,语义阶段视为Expr - 添加了新的 AST 节点:PostfixExpr、TernaryExpr、ForStmt 和 ImportStmt,用于表示新的语法结构。
This commit is contained in:
@@ -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>
|
||||
@@ -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
|
||||
|
||||
@@ -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) :
|
||||
|
||||
@@ -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;
|
||||
|
||||
35
src/Ast/Expr/PostfixExpr.hpp
Normal file
35
src/Ast/Expr/PostfixExpr.hpp
Normal 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
|
||||
35
src/Ast/Expr/TernaryExpr.hpp
Normal file
35
src/Ast/Expr/TernaryExpr.hpp
Normal 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
|
||||
@@ -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:
|
||||
/*
|
||||
左结合, 左绑定力 < 右
|
||||
|
||||
@@ -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, // .
|
||||
|
||||
|
||||
@@ -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
32
src/Ast/Stmt/ForStmt.hpp
Normal 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
|
||||
@@ -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;
|
||||
|
||||
33
src/Ast/Stmt/ImportStmt.hpp
Normal file
33
src/Ast/Stmt/ImportStmt.hpp
Normal 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
|
||||
@@ -16,8 +16,8 @@ namespace Fig
|
||||
struct Method
|
||||
{
|
||||
String name;
|
||||
DynArray<TypeExpr*> params;
|
||||
TypeExpr *retType;
|
||||
DynArray<Expr*> params;
|
||||
Expr *retType;
|
||||
SourceLocation location;
|
||||
};
|
||||
|
||||
|
||||
@@ -17,7 +17,7 @@ namespace Fig
|
||||
bool typeInfer;
|
||||
|
||||
String name;
|
||||
TypeExpr *type;
|
||||
Expr *type;
|
||||
Expr *initExpr;
|
||||
};
|
||||
bool isPublic;
|
||||
|
||||
@@ -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),
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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());
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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)
|
||||
{
|
||||
|
||||
@@ -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();
|
||||
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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 `?`
|
||||
}
|
||||
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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);
|
||||
|
||||
232
tests/Parser/parser_comprehensive_test.fig
Normal file
232
tests/Parser/parser_comprehensive_test.fig
Normal 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;
|
||||
};
|
||||
Reference in New Issue
Block a user