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/MemberExpr.hpp>
|
||||||
#include <Ast/Expr/NewExpr.hpp>
|
#include <Ast/Expr/NewExpr.hpp>
|
||||||
#include <Ast/Expr/PrefixExpr.hpp>
|
#include <Ast/Expr/PrefixExpr.hpp>
|
||||||
|
#include <Ast/Expr/TernaryExpr.hpp>
|
||||||
|
#include <Ast/Expr/PostfixExpr.hpp>
|
||||||
|
|
||||||
#include <Ast/Stmt/ControlFlowStmts.hpp>
|
#include <Ast/Stmt/ControlFlowStmts.hpp>
|
||||||
#include <Ast/Stmt/ExprStmt.hpp>
|
#include <Ast/Stmt/ExprStmt.hpp>
|
||||||
@@ -24,6 +26,8 @@
|
|||||||
#include <Ast/Stmt/ImplStmt.hpp>
|
#include <Ast/Stmt/ImplStmt.hpp>
|
||||||
#include <Ast/Stmt/InterfaceDefStmt.hpp>
|
#include <Ast/Stmt/InterfaceDefStmt.hpp>
|
||||||
#include <Ast/Stmt/StructDefStmt.hpp>
|
#include <Ast/Stmt/StructDefStmt.hpp>
|
||||||
|
#include <Ast/Stmt/ForStmt.hpp>
|
||||||
|
#include <Ast/Stmt/ImportStmt.hpp>
|
||||||
#include <Ast/Stmt/VarDecl.hpp>
|
#include <Ast/Stmt/VarDecl.hpp>
|
||||||
#include <Ast/Stmt/WhileStmt.hpp>
|
#include <Ast/Stmt/WhileStmt.hpp>
|
||||||
#include <Ast/TypeExpr.hpp>
|
#include <Ast/TypeExpr.hpp>
|
||||||
@@ -31,6 +31,8 @@ namespace Fig
|
|||||||
MemberExpr, // obj.prop
|
MemberExpr, // obj.prop
|
||||||
NewExpr, // new Point{}
|
NewExpr, // new Point{}
|
||||||
LambdaExpr,
|
LambdaExpr,
|
||||||
|
TernaryExpr, // cond ? then : else
|
||||||
|
PostfixExpr, // expr++ / expr--
|
||||||
|
|
||||||
/* Statements */
|
/* Statements */
|
||||||
ExprStmt,
|
ExprStmt,
|
||||||
@@ -45,12 +47,16 @@ namespace Fig
|
|||||||
ReturnStmt,
|
ReturnStmt,
|
||||||
BreakStmt,
|
BreakStmt,
|
||||||
ContinueStmt,
|
ContinueStmt,
|
||||||
|
ForStmt, // for loop
|
||||||
|
ImportStmt, // import
|
||||||
|
|
||||||
/* Type Expressions */
|
/* Type Expressions */
|
||||||
TypeExpr,
|
TypeExpr,
|
||||||
NamedTypeExpr,
|
NamedTypeExpr, // 废弃,用 IdentiExpr/MemberExpr/ApplyExpr 替代
|
||||||
NullableTypeExpr,
|
NullableTypeExpr, // 废弃,用 NullableExpr 替代
|
||||||
FnTypeExpr,
|
FnTypeExpr,
|
||||||
|
ApplyExpr, // 泛型实例化: List<Int>
|
||||||
|
NullableExpr, // 可空后缀: Int?
|
||||||
};
|
};
|
||||||
|
|
||||||
struct AstNode
|
struct AstNode
|
||||||
@@ -62,15 +68,6 @@ namespace Fig
|
|||||||
virtual ~AstNode() {};
|
virtual ~AstNode() {};
|
||||||
};
|
};
|
||||||
|
|
||||||
struct TypeExpr : public AstNode
|
|
||||||
{
|
|
||||||
TypeExpr()
|
|
||||||
{
|
|
||||||
type = AstType::TypeExpr;
|
|
||||||
}
|
|
||||||
virtual ~TypeExpr() = default;
|
|
||||||
};
|
|
||||||
|
|
||||||
struct Expr : public AstNode
|
struct Expr : public AstNode
|
||||||
{
|
{
|
||||||
// 语义分析后填充
|
// 语义分析后填充
|
||||||
@@ -116,4 +113,55 @@ namespace Fig
|
|||||||
return "<BlockStmt>";
|
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
|
} // namespace Fig
|
||||||
|
|||||||
@@ -15,7 +15,7 @@ namespace Fig
|
|||||||
// func (params) [-> return type] ([=> expr] / [ {stmt} ])
|
// func (params) [-> return type] ([=> expr] / [ {stmt} ])
|
||||||
|
|
||||||
DynArray<Param *> params;
|
DynArray<Param *> params;
|
||||||
TypeExpr *returnType;
|
Expr *returnType;
|
||||||
AstNode *body; // expr/blockstmt
|
AstNode *body; // expr/blockstmt
|
||||||
bool isExprBody;
|
bool isExprBody;
|
||||||
|
|
||||||
@@ -28,7 +28,7 @@ namespace Fig
|
|||||||
|
|
||||||
LambdaExpr(
|
LambdaExpr(
|
||||||
DynArray<Param *> _params,
|
DynArray<Param *> _params,
|
||||||
TypeExpr *_returnType,
|
Expr *_returnType,
|
||||||
AstNode *_body,
|
AstNode *_body,
|
||||||
bool _isExprBody,
|
bool _isExprBody,
|
||||||
SourceLocation _location) :
|
SourceLocation _location) :
|
||||||
|
|||||||
@@ -18,14 +18,14 @@ namespace Fig
|
|||||||
String name;
|
String name;
|
||||||
Expr *value;
|
Expr *value;
|
||||||
};
|
};
|
||||||
TypeExpr *typeExpr;
|
Expr *typeExpr;
|
||||||
DynArray<Arg> args;
|
DynArray<Arg> args;
|
||||||
|
|
||||||
NewExpr()
|
NewExpr()
|
||||||
{
|
{
|
||||||
type = AstType::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))
|
typeExpr(_te), args(std::move(_args))
|
||||||
{
|
{
|
||||||
type = AstType::NewExpr;
|
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::Minus, UnaryOperator::Negate},
|
||||||
{TokenType::Not, UnaryOperator::Not},
|
{TokenType::Not, UnaryOperator::Not},
|
||||||
{TokenType::Ampersand, UnaryOperator::AddressOf},
|
{TokenType::Ampersand, UnaryOperator::AddressOf},
|
||||||
|
{TokenType::DoublePlus, UnaryOperator::Increment},
|
||||||
|
{TokenType::DoubleMinus, UnaryOperator::Decrement},
|
||||||
};
|
};
|
||||||
return unaryOpMap;
|
return unaryOpMap;
|
||||||
}
|
}
|
||||||
@@ -40,6 +42,8 @@ namespace Fig
|
|||||||
|
|
||||||
{TokenType::And, BinaryOperator::LogicalAnd},
|
{TokenType::And, BinaryOperator::LogicalAnd},
|
||||||
{TokenType::Or, BinaryOperator::LogicalOr},
|
{TokenType::Or, BinaryOperator::LogicalOr},
|
||||||
|
{TokenType::DoubleAmpersand, BinaryOperator::LogicalAnd},
|
||||||
|
{TokenType::DoublePipe, BinaryOperator::LogicalOr},
|
||||||
|
|
||||||
{TokenType::Power, BinaryOperator::Power},
|
{TokenType::Power, BinaryOperator::Power},
|
||||||
|
|
||||||
@@ -49,6 +53,7 @@ namespace Fig
|
|||||||
{TokenType::AsteriskEqual, BinaryOperator::MultiplyAssign},
|
{TokenType::AsteriskEqual, BinaryOperator::MultiplyAssign},
|
||||||
{TokenType::SlashEqual, BinaryOperator::DivideAssign},
|
{TokenType::SlashEqual, BinaryOperator::DivideAssign},
|
||||||
{TokenType::PercentEqual, BinaryOperator::ModuloAssign},
|
{TokenType::PercentEqual, BinaryOperator::ModuloAssign},
|
||||||
|
{TokenType::Caret, BinaryOperator::BitXor},
|
||||||
{TokenType::CaretEqual, BinaryOperator::BitXorAssign},
|
{TokenType::CaretEqual, BinaryOperator::BitXorAssign},
|
||||||
|
|
||||||
{TokenType::Pipe, BinaryOperator::BitOr},
|
{TokenType::Pipe, BinaryOperator::BitOr},
|
||||||
@@ -56,7 +61,7 @@ namespace Fig
|
|||||||
{TokenType::ShiftLeft, BinaryOperator::ShiftLeft},
|
{TokenType::ShiftLeft, BinaryOperator::ShiftLeft},
|
||||||
{TokenType::ShiftRight, BinaryOperator::ShiftRight},
|
{TokenType::ShiftRight, BinaryOperator::ShiftRight},
|
||||||
|
|
||||||
{TokenType::Dot, BinaryOperator::MemberAccess},
|
{TokenType::As, BinaryOperator::As},
|
||||||
};
|
};
|
||||||
return binaryOpMap;
|
return binaryOpMap;
|
||||||
}
|
}
|
||||||
@@ -78,6 +83,8 @@ namespace Fig
|
|||||||
{UnaryOperator::Negate, 20001},
|
{UnaryOperator::Negate, 20001},
|
||||||
{UnaryOperator::Not, 20001},
|
{UnaryOperator::Not, 20001},
|
||||||
{UnaryOperator::AddressOf, 20001},
|
{UnaryOperator::AddressOf, 20001},
|
||||||
|
{UnaryOperator::Increment, 20001},
|
||||||
|
{UnaryOperator::Decrement, 20001},
|
||||||
};
|
};
|
||||||
return unbpm;
|
return unbpm;
|
||||||
}
|
}
|
||||||
@@ -109,6 +116,7 @@ namespace Fig
|
|||||||
{BinaryOperator::GreaterEqual, 2100},
|
{BinaryOperator::GreaterEqual, 2100},
|
||||||
|
|
||||||
{BinaryOperator::Is, 2100},
|
{BinaryOperator::Is, 2100},
|
||||||
|
{BinaryOperator::As, 2100},
|
||||||
|
|
||||||
{BinaryOperator::ShiftLeft, 3000},
|
{BinaryOperator::ShiftLeft, 3000},
|
||||||
{BinaryOperator::ShiftRight, 3000},
|
{BinaryOperator::ShiftRight, 3000},
|
||||||
@@ -117,10 +125,9 @@ namespace Fig
|
|||||||
{BinaryOperator::Subtract, 4000},
|
{BinaryOperator::Subtract, 4000},
|
||||||
{BinaryOperator::Multiply, 4500},
|
{BinaryOperator::Multiply, 4500},
|
||||||
{BinaryOperator::Divide, 4500},
|
{BinaryOperator::Divide, 4500},
|
||||||
|
{BinaryOperator::Modulo, 4500},
|
||||||
|
|
||||||
{BinaryOperator::Power, 5000},
|
{BinaryOperator::Power, 5000},
|
||||||
|
|
||||||
{BinaryOperator::MemberAccess, 40001},
|
|
||||||
};
|
};
|
||||||
return bnbpm;
|
return bnbpm;
|
||||||
}
|
}
|
||||||
@@ -153,6 +160,8 @@ namespace Fig
|
|||||||
case BinaryOperator::BitXorAssign:
|
case BinaryOperator::BitXorAssign:
|
||||||
case BinaryOperator::Power: return GetBinaryOpLBp(op) - 1;
|
case BinaryOperator::Power: return GetBinaryOpLBp(op) - 1;
|
||||||
|
|
||||||
|
case BinaryOperator::As: return GetBinaryOpLBp(op) + 1;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
/*
|
/*
|
||||||
左结合, 左绑定力 < 右
|
左结合, 左绑定力 < 右
|
||||||
|
|||||||
@@ -20,6 +20,8 @@ namespace Fig
|
|||||||
Negate, // 取反 -
|
Negate, // 取反 -
|
||||||
Not, // 逻辑非 ! / not
|
Not, // 逻辑非 ! / not
|
||||||
AddressOf, // 取引用 &
|
AddressOf, // 取引用 &
|
||||||
|
Increment, // ++
|
||||||
|
Decrement, // --
|
||||||
|
|
||||||
Count // 哨兵,(int) Count 获得运算符数量(注意,enum必须从 0 开始且不中断)
|
Count // 哨兵,(int) Count 获得运算符数量(注意,enum必须从 0 开始且不中断)
|
||||||
};
|
};
|
||||||
@@ -60,6 +62,8 @@ namespace Fig
|
|||||||
ShiftLeft, // 左移
|
ShiftLeft, // 左移
|
||||||
ShiftRight, // 右移
|
ShiftRight, // 右移
|
||||||
|
|
||||||
|
As, // as
|
||||||
|
|
||||||
// 成员访问
|
// 成员访问
|
||||||
MemberAccess, // .
|
MemberAccess, // .
|
||||||
|
|
||||||
|
|||||||
@@ -11,34 +11,34 @@
|
|||||||
namespace Fig
|
namespace Fig
|
||||||
{
|
{
|
||||||
struct Param : public AstNode {
|
struct Param : public AstNode {
|
||||||
String name;
|
String name;
|
||||||
TypeExpr *typeSpecifier;
|
Expr *typeSpecifier;
|
||||||
Expr *defaultValue;
|
Expr *defaultValue;
|
||||||
Type resolvedType;
|
Type resolvedType;
|
||||||
Param() { type = AstType::AstNode; }
|
Param() { type = AstType::AstNode; }
|
||||||
virtual ~Param() = default;
|
virtual ~Param() = default;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct PosParam final : public Param {
|
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);
|
name = std::move(_n); typeSpecifier = _ts; defaultValue = _dv; location = std::move(_loc);
|
||||||
}
|
}
|
||||||
virtual String toString() const override { return name; }
|
virtual String toString() const override { return name; }
|
||||||
};
|
};
|
||||||
|
|
||||||
struct FnDefStmt final : public Stmt {
|
struct FnDefStmt final : public Stmt {
|
||||||
String name;
|
String name;
|
||||||
DynArray<Param *> params;
|
DynArray<Param *> params;
|
||||||
TypeExpr *returnTypeSpecifier;
|
Expr *returnTypeSpecifier;
|
||||||
BlockStmt *body;
|
BlockStmt *body;
|
||||||
Type resolvedReturnType;
|
Type resolvedReturnType;
|
||||||
Symbol *resolvedSymbol = nullptr; // 连接物理符号
|
Symbol *resolvedSymbol = nullptr; // 连接物理符号
|
||||||
|
|
||||||
int protoIndex = -1; // 在CompiledModule扁平化protos的下标
|
int protoIndex = -1; // 在CompiledModule扁平化protos的下标
|
||||||
DynArray<UpvalueInfo> upvalues;
|
DynArray<UpvalueInfo> upvalues;
|
||||||
|
|
||||||
FnDefStmt() { type = AstType::FnDefStmt; }
|
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)
|
: name(std::move(_n)), params(std::move(_pa)), returnTypeSpecifier(_rt), body(_b)
|
||||||
{
|
{
|
||||||
type = AstType::FnDefStmt; isPublic = _p; location = std::move(_loc);
|
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
|
struct ImplStmt final : public Stmt
|
||||||
{
|
{
|
||||||
TypeExpr *interfaceType;
|
Expr *interfaceType;
|
||||||
TypeExpr *structType;
|
Expr *structType;
|
||||||
DynArray<FnDefStmt *> methods;
|
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))
|
interfaceType(_it), structType(_st), methods(std::move(_m))
|
||||||
{
|
{
|
||||||
type = AstType::ImplStmt;
|
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
|
struct Method
|
||||||
{
|
{
|
||||||
String name;
|
String name;
|
||||||
DynArray<TypeExpr*> params;
|
DynArray<Expr*> params;
|
||||||
TypeExpr *retType;
|
Expr *retType;
|
||||||
SourceLocation location;
|
SourceLocation location;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -17,7 +17,7 @@ namespace Fig
|
|||||||
bool typeInfer;
|
bool typeInfer;
|
||||||
|
|
||||||
String name;
|
String name;
|
||||||
TypeExpr *type;
|
Expr *type;
|
||||||
Expr *initExpr;
|
Expr *initExpr;
|
||||||
};
|
};
|
||||||
bool isPublic;
|
bool isPublic;
|
||||||
|
|||||||
@@ -15,7 +15,7 @@ namespace Fig
|
|||||||
struct VarDecl final : public Stmt
|
struct VarDecl final : public Stmt
|
||||||
{
|
{
|
||||||
String name;
|
String name;
|
||||||
TypeExpr *typeSpecifier;
|
Expr *typeSpecifier;
|
||||||
bool isInfer; // 是否用了 := 类型推断
|
bool isInfer; // 是否用了 := 类型推断
|
||||||
Expr *initExpr;
|
Expr *initExpr;
|
||||||
|
|
||||||
@@ -26,7 +26,7 @@ namespace Fig
|
|||||||
type = AstType::VarDecl;
|
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)),
|
name(std::move(_name)),
|
||||||
typeSpecifier(_typeSpecifier),
|
typeSpecifier(_typeSpecifier),
|
||||||
isInfer(_isInfer),
|
isInfer(_isInfer),
|
||||||
|
|||||||
@@ -12,13 +12,13 @@ namespace Fig
|
|||||||
struct NamedTypeExpr final : public TypeExpr
|
struct NamedTypeExpr final : public TypeExpr
|
||||||
{
|
{
|
||||||
DynArray<String> path;
|
DynArray<String> path;
|
||||||
DynArray<TypeExpr *> arguments;
|
DynArray<Expr *> arguments;
|
||||||
|
|
||||||
NamedTypeExpr()
|
NamedTypeExpr()
|
||||||
{
|
{
|
||||||
type = AstType::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))
|
path(std::move(_p)), arguments(std::move(_args))
|
||||||
{
|
{
|
||||||
type = AstType::NamedTypeExpr;
|
type = AstType::NamedTypeExpr;
|
||||||
@@ -51,9 +51,9 @@ namespace Fig
|
|||||||
|
|
||||||
struct NullableTypeExpr final : public TypeExpr
|
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;
|
type = AstType::NullableTypeExpr;
|
||||||
location = std::move(_loc);
|
location = std::move(_loc);
|
||||||
@@ -69,10 +69,10 @@ namespace Fig
|
|||||||
{
|
{
|
||||||
// func (paratypes...) -> return_type
|
// func (paratypes...) -> return_type
|
||||||
|
|
||||||
DynArray<TypeExpr *> paraTypes;
|
DynArray<Expr *> paraTypes;
|
||||||
TypeExpr *returnType;
|
Expr *returnType;
|
||||||
|
|
||||||
FnTypeExpr(DynArray<TypeExpr *> _paraTypes, TypeExpr *_returnType) :
|
FnTypeExpr(DynArray<Expr *> _paraTypes, Expr *_returnType) :
|
||||||
paraTypes(std::move(_paraTypes)), returnType(_returnType)
|
paraTypes(std::move(_paraTypes)), returnType(_returnType)
|
||||||
{
|
{
|
||||||
type = AstType::FnTypeExpr;
|
type = AstType::FnTypeExpr;
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
/*!
|
/*!
|
||||||
@file src/Compiler/ExprCompiler.cpp
|
@file src/Compiler/ExprCompiler.cpp
|
||||||
@brief 表达式编译器实现:水位线控制Register与零拷贝复用机制
|
@brief 表达式编译
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include <Ast/Expr/CallExpr.hpp>
|
#include <Ast/Expr/CallExpr.hpp>
|
||||||
@@ -167,7 +167,7 @@ namespace Fig
|
|||||||
|
|
||||||
if (sym->location == SymbolLocation::Local)
|
if (sym->location == SymbolLocation::Local)
|
||||||
{
|
{
|
||||||
// 零拷贝直读:如果是临时求值,直接返回变量的物理槽位,禁止产生副本
|
// no-copy for temp eval
|
||||||
if (target == NO_REG)
|
if (target == NO_REG)
|
||||||
return static_cast<Register>(sym->index);
|
return static_cast<Register>(sym->index);
|
||||||
|
|
||||||
@@ -253,7 +253,7 @@ namespace Fig
|
|||||||
&c->location);
|
&c->location);
|
||||||
}
|
}
|
||||||
|
|
||||||
// 回滚水位线, 释放传参时的临时占用
|
// free arg temps
|
||||||
current->freereg = mark;
|
current->freereg = mark;
|
||||||
|
|
||||||
// 目若 target 未指定,allocateReg 将复用 baseReg,实现零开销回写
|
// 目若 target 未指定,allocateReg 将复用 baseReg,实现零开销回写
|
||||||
@@ -317,7 +317,7 @@ namespace Fig
|
|||||||
return r_val;
|
return r_val;
|
||||||
}
|
}
|
||||||
|
|
||||||
Register mark = current->freereg; // 记录水位线
|
Register mark = current->freereg; // mark
|
||||||
|
|
||||||
auto r_l = compileExpr(in->left);
|
auto r_l = compileExpr(in->left);
|
||||||
if (!r_l)
|
if (!r_l)
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
/*!
|
/*!
|
||||||
@file src/Compiler/StmtCompiler.cpp
|
@file src/Compiler/StmtCompiler.cpp
|
||||||
@brief 语句编译器实现:实装水位线机制,彻底消灭硬编码寄存器释放
|
@brief 语句编译
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include <Ast/Stmt/FnDefStmt.hpp>
|
#include <Ast/Stmt/FnDefStmt.hpp>
|
||||||
@@ -35,7 +35,7 @@ namespace Fig
|
|||||||
auto *v = static_cast<VarDecl *>(stmt);
|
auto *v = static_cast<VarDecl *>(stmt);
|
||||||
if (current->enclosing == nullptr) // 处理全局变量
|
if (current->enclosing == nullptr) // 处理全局变量
|
||||||
{
|
{
|
||||||
Register mark = current->freereg; // 记录水位线
|
Register mark = current->freereg; // mark
|
||||||
auto regRes = compileExpr(v->initExpr);
|
auto regRes = compileExpr(v->initExpr);
|
||||||
if (!regRes)
|
if (!regRes)
|
||||||
return std::unexpected(regRes.error());
|
return std::unexpected(regRes.error());
|
||||||
@@ -74,7 +74,7 @@ namespace Fig
|
|||||||
Proto *newProto = new Proto();
|
Proto *newProto = new Proto();
|
||||||
newProto->name = f->name;
|
newProto->name = f->name;
|
||||||
newProto->numParams = static_cast<uint8_t>(f->params.size());
|
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());
|
f->protoIndex = static_cast<int>(module->protos.size());
|
||||||
module->protos.push_back(newProto);
|
module->protos.push_back(newProto);
|
||||||
@@ -141,7 +141,7 @@ namespace Fig
|
|||||||
auto *i = static_cast<IfStmt *>(stmt);
|
auto *i = static_cast<IfStmt *>(stmt);
|
||||||
DynArray<int> exitJumps;
|
DynArray<int> exitJumps;
|
||||||
|
|
||||||
Register mark = current->freereg; // 记录水位线
|
Register mark = current->freereg; // mark
|
||||||
auto r_cond = compileExpr(i->cond);
|
auto r_cond = compileExpr(i->cond);
|
||||||
if (!r_cond)
|
if (!r_cond)
|
||||||
return std::unexpected(r_cond.error());
|
return std::unexpected(r_cond.error());
|
||||||
@@ -204,7 +204,7 @@ namespace Fig
|
|||||||
auto *w = static_cast<WhileStmt *>(stmt);
|
auto *w = static_cast<WhileStmt *>(stmt);
|
||||||
int startIdx = static_cast<int>(current->proto->code.size());
|
int startIdx = static_cast<int>(current->proto->code.size());
|
||||||
|
|
||||||
Register mark = current->freereg; // 记录水位线
|
Register mark = current->freereg; // mark
|
||||||
auto r_cond = compileExpr(w->cond);
|
auto r_cond = compileExpr(w->cond);
|
||||||
if (!r_cond)
|
if (!r_cond)
|
||||||
return std::unexpected(r_cond.error());
|
return std::unexpected(r_cond.error());
|
||||||
@@ -228,7 +228,7 @@ namespace Fig
|
|||||||
|
|
||||||
case AstType::ReturnStmt: {
|
case AstType::ReturnStmt: {
|
||||||
auto *rs = static_cast<ReturnStmt *>(stmt);
|
auto *rs = static_cast<ReturnStmt *>(stmt);
|
||||||
Register mark = current->freereg; // 记录水位线
|
Register mark = current->freereg; // mark
|
||||||
Register retReg;
|
Register retReg;
|
||||||
|
|
||||||
if (rs->value)
|
if (rs->value)
|
||||||
@@ -253,7 +253,7 @@ namespace Fig
|
|||||||
}
|
}
|
||||||
|
|
||||||
case AstType::ExprStmt: {
|
case AstType::ExprStmt: {
|
||||||
Register mark = current->freereg; // 记录水位线
|
Register mark = current->freereg; // mark
|
||||||
auto reg = compileExpr(static_cast<ExprStmt *>(stmt)->expr);
|
auto reg = compileExpr(static_cast<ExprStmt *>(stmt)->expr);
|
||||||
if (!reg)
|
if (!reg)
|
||||||
return std::unexpected(reg.error());
|
return std::unexpected(reg.error());
|
||||||
|
|||||||
@@ -161,7 +161,7 @@ namespace Fig
|
|||||||
{
|
{
|
||||||
return std::unexpected(type_result.error());
|
return std::unexpected(type_result.error());
|
||||||
}
|
}
|
||||||
TypeExpr *type = *type_result;
|
Expr *type = *type_result;
|
||||||
|
|
||||||
if (!match(TokenType::LeftBrace))
|
if (!match(TokenType::LeftBrace))
|
||||||
{
|
{
|
||||||
@@ -175,6 +175,8 @@ namespace Fig
|
|||||||
new Point{1, 2}
|
new Point{1, 2}
|
||||||
Named:
|
Named:
|
||||||
new Point{x = 1, y = 2}
|
new Point{x = 1, y = 2}
|
||||||
|
Shorthand:
|
||||||
|
new Point{y, x}
|
||||||
*/
|
*/
|
||||||
|
|
||||||
DynArray<NewExpr::Arg> args;
|
DynArray<NewExpr::Arg> args;
|
||||||
@@ -195,11 +197,12 @@ namespace Fig
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (currentToken().isIdentifier() && peekToken().type == TokenType::Assign)
|
// named arg
|
||||||
|
if (currentToken().isIdentifier() && peekToken().type == TokenType::Colon)
|
||||||
{
|
{
|
||||||
const Token &name_token = consumeToken();
|
const Token &name_token = consumeToken();
|
||||||
const String &name = srcManager.GetSub(name_token.index, name_token.length);
|
const String &name = srcManager.GetSub(name_token.index, name_token.length);
|
||||||
consumeToken(); // consume `=`
|
consumeToken(); // consume `:`
|
||||||
|
|
||||||
SET_STOP_AT(TokenType::Comma, TokenType::RightBrace); // , / }
|
SET_STOP_AT(TokenType::Comma, TokenType::RightBrace); // , / }
|
||||||
auto result = parseExpression();
|
auto result = parseExpression();
|
||||||
@@ -213,7 +216,20 @@ namespace Fig
|
|||||||
*result
|
*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); // , / }
|
SET_STOP_AT(TokenType::Comma, TokenType::RightBrace); // , / }
|
||||||
auto result = parseExpression();
|
auto result = parseExpression();
|
||||||
@@ -226,7 +242,7 @@ namespace Fig
|
|||||||
.value = *result
|
.value = *result
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
if (match(TokenType::Comma))
|
if (match(TokenType::Comma))
|
||||||
{
|
{
|
||||||
@@ -273,7 +289,7 @@ namespace Fig
|
|||||||
}
|
}
|
||||||
params = *paraResult;
|
params = *paraResult;
|
||||||
|
|
||||||
TypeExpr *returnType = nullptr;
|
Expr *returnType = nullptr;
|
||||||
Token rightArrowToken;
|
Token rightArrowToken;
|
||||||
if (match(TokenType::RightArrow)) // ->
|
if (match(TokenType::RightArrow)) // ->
|
||||||
{
|
{
|
||||||
@@ -332,6 +348,7 @@ namespace Fig
|
|||||||
Expr *lhs = nullptr;
|
Expr *lhs = nullptr;
|
||||||
Token token = currentToken();
|
Token token = currentToken();
|
||||||
|
|
||||||
|
// NUD
|
||||||
if (token.isIdentifier())
|
if (token.isIdentifier())
|
||||||
{
|
{
|
||||||
const auto &lhs_result = parseIdentiExpr();
|
const auto &lhs_result = parseIdentiExpr();
|
||||||
@@ -350,7 +367,7 @@ namespace Fig
|
|||||||
}
|
}
|
||||||
lhs = *lhs_result;
|
lhs = *lhs_result;
|
||||||
}
|
}
|
||||||
else if (IsTokenOp(token.type, false)) // 是否是一元运算符
|
else if (IsTokenOp(token.type, false)) // 是否是一元前缀运算符
|
||||||
{
|
{
|
||||||
const auto &lhs_result = parsePrefixExpr();
|
const auto &lhs_result = parsePrefixExpr();
|
||||||
if (!lhs_result)
|
if (!lhs_result)
|
||||||
@@ -408,6 +425,7 @@ namespace Fig
|
|||||||
makeSourceLocation(prevToken())));
|
makeSourceLocation(prevToken())));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// LED
|
||||||
while (true)
|
while (true)
|
||||||
{
|
{
|
||||||
token = currentToken();
|
token = currentToken();
|
||||||
@@ -416,57 +434,116 @@ namespace Fig
|
|||||||
break;
|
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);
|
BinaryOperator op = TokenToBinaryOp(token);
|
||||||
BindingPower lbp = GetBinaryOpLBp(op);
|
BindingPower lbp = GetBinaryOpLBp(op);
|
||||||
if (rbp >= lbp)
|
if (rbp >= lbp)
|
||||||
{
|
{
|
||||||
// 前操作数的右绑定力比当前操作数的左绑定力大
|
|
||||||
// lhs被吸走
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
auto result = parseInfixExpr(lhs);
|
auto result = parseInfixExpr(lhs);
|
||||||
if (!result)
|
if (!result)
|
||||||
{
|
{
|
||||||
resetTermintors();
|
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
lhs = *result;
|
lhs = *result;
|
||||||
}
|
}
|
||||||
// 后缀运算符优先级非常大,几乎永远跟在操作数后面,因此我们可以直接结合
|
// [index]
|
||||||
// 而不用走正常路径
|
else if (token.type == TokenType::LeftBracket)
|
||||||
else if (token.type == TokenType::LeftBracket) // `[`
|
|
||||||
{
|
{
|
||||||
const auto &expr_result = parseIndexExpr(lhs);
|
const auto &expr_result = parseIndexExpr(lhs);
|
||||||
if (!expr_result)
|
if (!expr_result)
|
||||||
{
|
{
|
||||||
resetTermintors();
|
|
||||||
return expr_result;
|
return expr_result;
|
||||||
}
|
}
|
||||||
lhs = *expr_result;
|
lhs = *expr_result;
|
||||||
}
|
}
|
||||||
else if (token.type == TokenType::LeftParen) // `(`
|
// call
|
||||||
|
else if (token.type == TokenType::LeftParen)
|
||||||
{
|
{
|
||||||
const auto &expr_result = parseCallExpr(lhs);
|
const auto &expr_result = parseCallExpr(lhs);
|
||||||
if (!expr_result)
|
if (!expr_result)
|
||||||
{
|
{
|
||||||
resetTermintors();
|
|
||||||
return expr_result;
|
return expr_result;
|
||||||
}
|
}
|
||||||
lhs = *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
|
else
|
||||||
{
|
{
|
||||||
// return std::unexpected(Error(ErrorType::ExpectedExpression,
|
|
||||||
// "expression unexpectedly ended",
|
|
||||||
// "insert expressions",
|
|
||||||
// makeSourceLocation(token)));
|
|
||||||
return lhs;
|
return lhs;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return lhs;
|
return lhs;
|
||||||
}
|
}
|
||||||
|
|
||||||
}; // namespace Fig
|
}; // namespace Fig
|
||||||
|
|||||||
@@ -15,12 +15,16 @@ namespace Fig
|
|||||||
|
|
||||||
while (currentToken().type != TokenType::EndOfFile)
|
while (currentToken().type != TokenType::EndOfFile)
|
||||||
{
|
{
|
||||||
|
if (lexerError)
|
||||||
|
{
|
||||||
|
return std::unexpected(*lexerError);
|
||||||
|
}
|
||||||
auto result = parseStatement();
|
auto result = parseStatement();
|
||||||
if (!result)
|
if (!result)
|
||||||
{
|
{
|
||||||
return std::unexpected(result.error());
|
return std::unexpected(result.error());
|
||||||
}
|
}
|
||||||
|
|
||||||
Stmt *stmt = *result;
|
Stmt *stmt = *result;
|
||||||
if (stmt)
|
if (stmt)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -35,6 +35,7 @@ namespace Fig
|
|||||||
bool isEOF = false;
|
bool isEOF = false;
|
||||||
|
|
||||||
Diagnostics &diagnostics;
|
Diagnostics &diagnostics;
|
||||||
|
std::optional<Error> lexerError; // 词法错误缓存,避免 exit/abort
|
||||||
|
|
||||||
// 惰性获取下一个 Token,跳过注释
|
// 惰性获取下一个 Token,跳过注释
|
||||||
Token nextToken()
|
Token nextToken()
|
||||||
@@ -49,8 +50,12 @@ namespace Fig
|
|||||||
auto result = lexer.NextToken();
|
auto result = lexer.NextToken();
|
||||||
if (!result)
|
if (!result)
|
||||||
{
|
{
|
||||||
ReportError(result.error(), srcManager);
|
lexerError = result.error();
|
||||||
std::exit(-1);
|
isEOF = true;
|
||||||
|
Token eof = {0, 0, TokenType::EndOfFile};
|
||||||
|
buffer.push_back(eof);
|
||||||
|
index = buffer.size() - 1;
|
||||||
|
return buffer[index];
|
||||||
}
|
}
|
||||||
const Token &token = result.value();
|
const Token &token = result.value();
|
||||||
if (token.type == TokenType::Comments)
|
if (token.type == TokenType::Comments)
|
||||||
@@ -84,8 +89,12 @@ namespace Fig
|
|||||||
auto result = lexer.NextToken();
|
auto result = lexer.NextToken();
|
||||||
if (!result)
|
if (!result)
|
||||||
{
|
{
|
||||||
ReportError(result.error(), srcManager);
|
lexerError = result.error();
|
||||||
std::abort();
|
isEOF = true;
|
||||||
|
Token eof = {0, 0, TokenType::EndOfFile};
|
||||||
|
buffer.push_back(eof);
|
||||||
|
index = buffer.size() - 1;
|
||||||
|
return buffer.back();
|
||||||
}
|
}
|
||||||
if (result->type == TokenType::Comments)
|
if (result->type == TokenType::Comments)
|
||||||
continue;
|
continue;
|
||||||
@@ -158,20 +167,10 @@ namespace Fig
|
|||||||
return baseTerminators;
|
return baseTerminators;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::unordered_set<TokenType> &getTerminators()
|
|
||||||
{
|
|
||||||
static std::unordered_set<TokenType> terminators(getBaseTerminators());
|
|
||||||
return terminators;
|
|
||||||
}
|
|
||||||
void resetTermintors()
|
|
||||||
{
|
|
||||||
getTerminators() = getBaseTerminators();
|
|
||||||
}
|
|
||||||
|
|
||||||
bool shouldTerminate()
|
bool shouldTerminate()
|
||||||
{
|
{
|
||||||
const Token &token = currentToken();
|
const Token &token = currentToken();
|
||||||
if (getTerminators().contains(token.type))
|
if (getBaseTerminators().contains(token.type))
|
||||||
return true;
|
return true;
|
||||||
for (auto it = stateStack.rbegin(); it < stateStack.rend(); ++it)
|
for (auto it = stateStack.rbegin(); it < stateStack.rend(); ++it)
|
||||||
{
|
{
|
||||||
@@ -261,9 +260,9 @@ namespace Fig
|
|||||||
|
|
||||||
Result<decltype(StructDefStmt::typeParameters), Error> parseTypeParameters();
|
Result<decltype(StructDefStmt::typeParameters), Error> parseTypeParameters();
|
||||||
|
|
||||||
Result<TypeExpr *, Error> parseTypeExpr();
|
Result<Expr *, Error> parseTypeExpr();
|
||||||
Result<TypeExpr *, Error> parseNamedTypeExpr();
|
Result<Expr *, Error> parseNamedTypeExpr();
|
||||||
Result<TypeExpr *, Error> parseFnTypeExpr();
|
Result<Expr *, Error> parseFnTypeExpr();
|
||||||
|
|
||||||
Result<Expr *, Error> parseExpression(BindingPower = 0);
|
Result<Expr *, Error> parseExpression(BindingPower = 0);
|
||||||
Result<Expr *, Error> parseLiteralExpr();
|
Result<Expr *, Error> parseLiteralExpr();
|
||||||
@@ -277,6 +276,7 @@ namespace Fig
|
|||||||
|
|
||||||
Result<BlockStmt *, Error> parseBlockStmt();
|
Result<BlockStmt *, Error> parseBlockStmt();
|
||||||
Result<VarDecl *, Error> parseVarDecl(bool);
|
Result<VarDecl *, Error> parseVarDecl(bool);
|
||||||
|
Result<VarDecl *, Error> parseConstDecl(bool);
|
||||||
Result<IfStmt *, Error> parseIfStmt();
|
Result<IfStmt *, Error> parseIfStmt();
|
||||||
Result<WhileStmt *, Error> parseWhileStmt();
|
Result<WhileStmt *, Error> parseWhileStmt();
|
||||||
Result<DynArray<Param *>, Error> parseFnParams();
|
Result<DynArray<Param *>, Error> parseFnParams();
|
||||||
@@ -286,6 +286,8 @@ namespace Fig
|
|||||||
Result<Stmt *, Error> parseStructDef(bool);
|
Result<Stmt *, Error> parseStructDef(bool);
|
||||||
Result<Stmt *, Error> parseInterfaceDef(bool);
|
Result<Stmt *, Error> parseInterfaceDef(bool);
|
||||||
Result<Stmt *, Error> parseImpl();
|
Result<Stmt *, Error> parseImpl();
|
||||||
|
Result<Stmt *, Error> parseForStmt();
|
||||||
|
Result<Stmt *, Error> parseImportStmt();
|
||||||
|
|
||||||
Result<Stmt *, Error> parseStatement();
|
Result<Stmt *, Error> parseStatement();
|
||||||
|
|
||||||
|
|||||||
@@ -5,24 +5,25 @@ int main()
|
|||||||
{
|
{
|
||||||
using namespace Fig;
|
using namespace Fig;
|
||||||
|
|
||||||
String fileName = "test.fig";
|
String fileName = "test.fig";
|
||||||
String filePath = "T:/Files/Maker/Code/MyCodingLanguage/The Fig Project/Fig/test.fig";
|
String filePath =
|
||||||
|
"T:/Files/Maker/Code/MyCodingLanguage/The Fig Project/Fig/" + fileName;
|
||||||
|
|
||||||
SourceManager srcManager(filePath);
|
SourceManager srcManager(filePath);
|
||||||
|
|
||||||
String source = srcManager.Read();
|
String source = srcManager.Read();
|
||||||
if (!srcManager.read)
|
if (!srcManager.read)
|
||||||
{
|
{
|
||||||
std::cerr << "Couldn't read file";
|
std::cerr << "Couldn't read file: " << filePath << '\n';
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
Lexer lexer(source, fileName);
|
Lexer lexer(source, fileName);
|
||||||
|
|
||||||
Diagnostics diagnostics;
|
Diagnostics diagnostics;
|
||||||
Parser parser(lexer, srcManager, fileName, diagnostics);
|
Parser parser(lexer, srcManager, fileName, diagnostics);
|
||||||
|
|
||||||
auto result = parser.Parse();
|
auto result = parser.Parse();
|
||||||
if (!result)
|
if (!result)
|
||||||
{
|
{
|
||||||
ReportError(result.error(), srcManager);
|
ReportError(result.error(), srcManager);
|
||||||
@@ -32,8 +33,11 @@ int main()
|
|||||||
diagnostics.EmitAll(srcManager);
|
diagnostics.EmitAll(srcManager);
|
||||||
|
|
||||||
Program *program = *result;
|
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);
|
const String &name = srcManager.GetSub(currentToken().index, currentToken().length);
|
||||||
consumeToken();
|
consumeToken();
|
||||||
|
|
||||||
TypeExpr *typeSpeicifer = nullptr;
|
Expr *typeSpeicifer = nullptr;
|
||||||
if (match(TokenType::Colon))
|
if (match(TokenType::Colon))
|
||||||
{
|
{
|
||||||
auto result = parseTypeExpr();
|
auto result = parseTypeExpr();
|
||||||
@@ -99,6 +99,79 @@ namespace Fig
|
|||||||
return varDecl;
|
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()
|
Result<IfStmt *, Error> Parser::parseIfStmt()
|
||||||
{
|
{
|
||||||
StateProtector p(this, {State::ParsingIf});
|
StateProtector p(this, {State::ParsingIf});
|
||||||
@@ -294,6 +367,123 @@ namespace Fig
|
|||||||
return whileStmt;
|
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()
|
Result<DynArray<Param *>, Error> Parser::parseFnParams()
|
||||||
{
|
{
|
||||||
const Token &lpToken = consumeToken();
|
const Token &lpToken = consumeToken();
|
||||||
@@ -318,7 +508,7 @@ namespace Fig
|
|||||||
SourceLocation location = makeSourceLocation(nToken);
|
SourceLocation location = makeSourceLocation(nToken);
|
||||||
const String &name = srcManager.GetSub(nToken.index, nToken.length);
|
const String &name = srcManager.GetSub(nToken.index, nToken.length);
|
||||||
|
|
||||||
TypeExpr *type = nullptr;
|
Expr *type = nullptr;
|
||||||
if (match(TokenType::Colon))
|
if (match(TokenType::Colon))
|
||||||
{
|
{
|
||||||
auto result = parseTypeExpr();
|
auto result = parseTypeExpr();
|
||||||
@@ -345,8 +535,32 @@ namespace Fig
|
|||||||
PosParam *posParam = arena.Allocate<PosParam>(name, type, defaultValue, location);
|
PosParam *posParam = arena.Allocate<PosParam>(name, type, defaultValue, location);
|
||||||
params.push_back(posParam);
|
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::Comma))
|
||||||
{
|
{
|
||||||
|
if (match(TokenType::RightParen))
|
||||||
|
{
|
||||||
|
// 尾部逗号允许,如 func(a, b,)
|
||||||
|
break;
|
||||||
|
}
|
||||||
if (!currentToken().isIdentifier())
|
if (!currentToken().isIdentifier())
|
||||||
{
|
{
|
||||||
return std::unexpected(
|
return std::unexpected(
|
||||||
@@ -385,7 +599,7 @@ namespace Fig
|
|||||||
}
|
}
|
||||||
params = *paraResult;
|
params = *paraResult;
|
||||||
|
|
||||||
TypeExpr *returnType = nullptr;
|
Expr *returnType = nullptr;
|
||||||
if (match(TokenType::RightArrow))
|
if (match(TokenType::RightArrow))
|
||||||
{
|
{
|
||||||
auto result = parseTypeExpr();
|
auto result = parseTypeExpr();
|
||||||
@@ -405,11 +619,6 @@ namespace Fig
|
|||||||
return std::unexpected(result.error());
|
return std::unexpected(result.error());
|
||||||
}
|
}
|
||||||
|
|
||||||
// if (!match(TokenType::Semicolon)) // ;
|
|
||||||
// {
|
|
||||||
// return std::unexpected(makeExpectSemicolonError(prevToken()));
|
|
||||||
// }
|
|
||||||
|
|
||||||
if (match(TokenType::Semicolon))
|
if (match(TokenType::Semicolon))
|
||||||
{
|
{
|
||||||
diagnostics.Report(Error(
|
diagnostics.Report(Error(
|
||||||
@@ -518,7 +727,7 @@ namespace Fig
|
|||||||
|
|
||||||
// (public) field_name (: Type) (= expr) / (:= expr)
|
// (public) field_name (: Type) (= expr) / (:= expr)
|
||||||
|
|
||||||
bool isPublic = match(TokenType::Public);
|
bool isPublicField = match(TokenType::Public);
|
||||||
if (currentToken().isIdentifier())
|
if (currentToken().isIdentifier())
|
||||||
{
|
{
|
||||||
const Token &name_tok = consumeToken();
|
const Token &name_tok = consumeToken();
|
||||||
@@ -533,11 +742,11 @@ namespace Fig
|
|||||||
}
|
}
|
||||||
|
|
||||||
stDef->fields.push_back(
|
stDef->fields.push_back(
|
||||||
StructDefStmt::Field{isPublic, true, field_name, nullptr, *result});
|
StructDefStmt::Field{isPublicField, true, field_name, nullptr, *result});
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
TypeExpr *type = nullptr;
|
Expr *type = nullptr;
|
||||||
Expr *initExpr = nullptr;
|
Expr *initExpr = nullptr;
|
||||||
|
|
||||||
if (match(TokenType::Colon)) // :
|
if (match(TokenType::Colon)) // :
|
||||||
@@ -560,7 +769,7 @@ namespace Fig
|
|||||||
initExpr = *result;
|
initExpr = *result;
|
||||||
}
|
}
|
||||||
stDef->fields.push_back(
|
stDef->fields.push_back(
|
||||||
StructDefStmt::Field{isPublic, false, field_name, type, initExpr});
|
StructDefStmt::Field{isPublicField, false, field_name, type, initExpr});
|
||||||
}
|
}
|
||||||
if (!match(TokenType::Semicolon))
|
if (!match(TokenType::Semicolon))
|
||||||
{
|
{
|
||||||
@@ -569,7 +778,7 @@ namespace Fig
|
|||||||
}
|
}
|
||||||
else if (currentToken().type == TokenType::Function)
|
else if (currentToken().type == TokenType::Function)
|
||||||
{
|
{
|
||||||
auto result = parseFnDefStmt(isPublic);
|
auto result = parseFnDefStmt(isPublicField);
|
||||||
if (!result)
|
if (!result)
|
||||||
{
|
{
|
||||||
return result;
|
return result;
|
||||||
@@ -587,113 +796,444 @@ namespace Fig
|
|||||||
return stDef;
|
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(
|
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)
|
const Token &lbToken = prevToken();
|
||||||
{
|
|
||||||
return parseVarDecl(false);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (currentToken().type == TokenType::If)
|
InterfaceDefStmt *ifaceDef = arena.Allocate<InterfaceDefStmt>();
|
||||||
{
|
ifaceDef->isPublic = isPublic;
|
||||||
return parseIfStmt();
|
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())
|
// interface 方法需要 `func` 关键字
|
||||||
{
|
if (currentToken().type != TokenType::Function)
|
||||||
return parseFnDefStmt(false);
|
{
|
||||||
}
|
return std::unexpected(
|
||||||
|
makeUnexpectTokenError("InterfaceDef", "`func` for method", currentToken()));
|
||||||
|
}
|
||||||
|
consumeToken(); // consume `func`
|
||||||
|
|
||||||
if (currentToken().type == TokenType::Struct)
|
if (!currentToken().isIdentifier())
|
||||||
{
|
{
|
||||||
return parseStructDef(false);
|
return std::unexpected(
|
||||||
}
|
makeUnexpectTokenError("InterfaceDef", "method name", currentToken()));
|
||||||
|
}
|
||||||
|
|
||||||
if (currentToken().type == TokenType::Return)
|
const Token &methodNameToken = consumeToken();
|
||||||
{
|
const String &methodName =
|
||||||
return parseReturnStmt();
|
srcManager.GetSub(methodNameToken.index, methodNameToken.length);
|
||||||
}
|
|
||||||
|
|
||||||
if (match(TokenType::Break))
|
// 参数列表
|
||||||
{
|
if (!match(TokenType::LeftParen))
|
||||||
SourceLocation location = makeSourceLocation(prevToken());
|
{
|
||||||
if (!match(TokenType::Semicolon))
|
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());
|
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());
|
return std::unexpected(
|
||||||
if (!match(TokenType::Semicolon))
|
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);
|
if (match(TokenType::RightBrace))
|
||||||
return continueStmt;
|
{
|
||||||
|
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))
|
if (!match(TokenType::Semicolon))
|
||||||
{
|
{
|
||||||
return std::unexpected(makeExpectSemicolonError());
|
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;
|
return exprStmt;
|
||||||
}
|
}
|
||||||
}; // namespace Fig
|
}
|
||||||
|
|
||||||
|
}; // namespace Fig
|
||||||
|
|||||||
@@ -1,8 +1,8 @@
|
|||||||
/*!
|
/*!
|
||||||
@file src/Parser/TypeExprParser.cpp
|
@file src/Parser/TypeExprParser.cpp
|
||||||
@brief 类型表达式解析器实现:支持泛型与空安全
|
@brief 类型表达式解析器实现 — 类型即值,产生 Expr* 而非 TypeExpr*
|
||||||
@author PuqiAR (im@puqiar.top)
|
@author PuqiAR (im@puqiar.top)
|
||||||
@date 2026-03-08
|
@date 2026-06-06
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include <Parser/Parser.hpp>
|
#include <Parser/Parser.hpp>
|
||||||
@@ -49,38 +49,51 @@ namespace Fig
|
|||||||
return tp;
|
return tp;
|
||||||
}
|
}
|
||||||
|
|
||||||
// 解析基础命名类型与泛型: List<Int>
|
|
||||||
Result<TypeExpr *, Error> Parser::parseNamedTypeExpr()
|
|
||||||
|
Result<Expr *, Error> Parser::parseNamedTypeExpr()
|
||||||
{
|
{
|
||||||
StateProtector p(this, {State::ParsingNamedTypeExpr});
|
StateProtector p(this, {State::ParsingNamedTypeExpr});
|
||||||
SourceLocation location = makeSourceLocation(currentToken());
|
|
||||||
|
|
||||||
DynArray<String> path;
|
|
||||||
while (true)
|
if (!currentToken().isIdentifier())
|
||||||
{
|
{
|
||||||
const Token &tok = consumeToken();
|
return std::unexpected(
|
||||||
const String &name = srcManager.GetSub(tok.index, tok.length);
|
makeUnexpectTokenError("TypeExpr", "type name", currentToken()));
|
||||||
path.push_back(name);
|
|
||||||
|
|
||||||
if (match(TokenType::Dot))
|
|
||||||
{
|
|
||||||
if (!currentToken().isIdentifier())
|
|
||||||
return std::unexpected(
|
|
||||||
makeUnexpectTokenError("Type", "identifier", currentToken()));
|
|
||||||
}
|
|
||||||
else
|
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
DynArray<TypeExpr *> arguments;
|
const Token &firstTok = consumeToken();
|
||||||
if (match(TokenType::Less)) // `<`
|
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)
|
while (true)
|
||||||
{
|
{
|
||||||
auto result = parseTypeExpr();
|
auto result = parseTypeExpr();
|
||||||
if (!result)
|
if (!result)
|
||||||
return std::unexpected(result.error());
|
return std::unexpected(result.error());
|
||||||
arguments.push_back(*result);
|
args.push_back(*result);
|
||||||
|
|
||||||
if (match(TokenType::Greater))
|
if (match(TokenType::Greater))
|
||||||
break; // `>`
|
break; // `>`
|
||||||
@@ -88,12 +101,14 @@ namespace Fig
|
|||||||
return std::unexpected(
|
return std::unexpected(
|
||||||
makeUnexpectTokenError("TypeArgs", "'>' or ','", currentToken()));
|
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});
|
StateProtector p(this, {State::ParsingFnTypeExpr});
|
||||||
SourceLocation location = makeSourceLocation(consumeToken()); // consume `func`
|
SourceLocation location = makeSourceLocation(consumeToken()); // consume `func`
|
||||||
@@ -103,7 +118,7 @@ namespace Fig
|
|||||||
makeUnexpectTokenError("FnTypeExpr", "lparen (", currentToken()));
|
makeUnexpectTokenError("FnTypeExpr", "lparen (", currentToken()));
|
||||||
}
|
}
|
||||||
|
|
||||||
DynArray<TypeExpr *> paraTypes;
|
DynArray<Expr *> paraTypes;
|
||||||
|
|
||||||
while (true)
|
while (true)
|
||||||
{
|
{
|
||||||
@@ -130,7 +145,7 @@ namespace Fig
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
TypeExpr *returnType = nullptr;
|
Expr *returnType = nullptr;
|
||||||
|
|
||||||
if (match(TokenType::RightArrow)) // ->
|
if (match(TokenType::RightArrow)) // ->
|
||||||
{
|
{
|
||||||
@@ -146,10 +161,10 @@ namespace Fig
|
|||||||
return fnTypeExpr;
|
return fnTypeExpr;
|
||||||
}
|
}
|
||||||
|
|
||||||
// 解析主入口: 处理 `?` 后缀
|
|
||||||
Result<TypeExpr *, Error> Parser::parseTypeExpr()
|
Result<Expr *, Error> Parser::parseTypeExpr()
|
||||||
{
|
{
|
||||||
TypeExpr *base = nullptr;
|
Expr *base = nullptr;
|
||||||
|
|
||||||
if (currentToken().isIdentifier())
|
if (currentToken().isIdentifier())
|
||||||
{
|
{
|
||||||
@@ -174,10 +189,10 @@ namespace Fig
|
|||||||
return std::unexpected(makeUnexpectTokenError("TypeExpr", "name", currentToken()));
|
return std::unexpected(makeUnexpectTokenError("TypeExpr", "name", currentToken()));
|
||||||
}
|
}
|
||||||
|
|
||||||
// type (?)
|
// nullable
|
||||||
if (currentToken().type == TokenType::Question) // ?
|
if (currentToken().type == TokenType::Question) // ?
|
||||||
{
|
{
|
||||||
base = arena.Allocate<NullableTypeExpr>(
|
base = arena.Allocate<NullableExpr>(
|
||||||
base, makeSourceLocation(consumeToken())); // consume `?`
|
base, makeSourceLocation(consumeToken())); // consume `?`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -678,7 +678,7 @@ namespace Fig
|
|||||||
return idx;
|
return idx;
|
||||||
}
|
}
|
||||||
|
|
||||||
Result<Type, Error> Analyzer::resolveTypeExpr(TypeExpr *texpr)
|
Result<Type, Error> Analyzer::resolveTypeExpr(Expr *texpr)
|
||||||
{
|
{
|
||||||
if (!texpr)
|
if (!texpr)
|
||||||
return typeCtx.GetBasic(TypeTag::Any);
|
return typeCtx.GetBasic(TypeTag::Any);
|
||||||
|
|||||||
@@ -32,7 +32,7 @@ namespace Fig
|
|||||||
// 核心递归查找:解决跨越函数边界的捕获问题
|
// 核心递归查找:解决跨越函数边界的捕获问题
|
||||||
Result<Symbol*, Error> resolveSymbolInternal(const String &name, const SourceLocation &loc, Scope* startScope);
|
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> pass1(Program *prog);
|
||||||
Result<void, Error> resolveTypes(Program *prog);
|
Result<void, Error> resolveTypes(Program *prog);
|
||||||
Result<void, Error> checkBodies(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