重构类型系统并改进诊断功能
- 更新了类型系统,新增了类型并优化了结构。 - 引入了基类型和派生类,用于函数、结构体和接口类型。 - 实现了类型上下文,用于管理内置类型和类型解析。 - 添加了诊断类,用于收集和报告警告和错误。 - 通过改进错误处理增强了虚拟机执行,以应对递归限制问题。 - 实现了反汇编器,将字节码转换为代码,以改善调试和分析。 - 添加了新的抽象语法树节点,用于成员表达式、对象初始化、接口和结构体定义。 - 引入了语义错误测试,包括重定义、未声明的变量和无效的结构字段。
This commit is contained in:
0
.continue/agents/new-config.yaml
Normal file
0
.continue/agents/new-config.yaml
Normal file
107
src/Ast/Base.hpp
107
src/Ast/Base.hpp
@@ -2,52 +2,55 @@
|
||||
@file src/Ast/Base.hpp
|
||||
@brief AstNode基类定义
|
||||
@author PuqiAR (im@puqiar.top)
|
||||
@date 2026-02-14
|
||||
@date 2026-03-08
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
#include <Core/SourceLocations.hpp>
|
||||
#include <Deps/Deps.hpp>
|
||||
|
||||
#include <Sema/Type.hpp>
|
||||
|
||||
#include <cstdint>
|
||||
|
||||
namespace Fig
|
||||
{
|
||||
enum class AstType : std::uint8_t
|
||||
{
|
||||
AstNode, // 基类
|
||||
Program, // 程序
|
||||
Expr, // 表达式
|
||||
Stmt, // 语句
|
||||
BlockStmt, // 块语句
|
||||
AstNode,
|
||||
Program,
|
||||
Expr,
|
||||
Stmt,
|
||||
BlockStmt,
|
||||
|
||||
/* Expressions */
|
||||
IdentiExpr, // 标识符表达式
|
||||
LiteralExpr, // 字面量表达式
|
||||
PrefixExpr, // 一元 前缀表达式
|
||||
InfixExpr, // 二元 中缀表达式
|
||||
|
||||
IndexExpr, // 后缀表达式,索引
|
||||
CallExpr, // 后缀表达式,函数调用
|
||||
IdentiExpr,
|
||||
LiteralExpr,
|
||||
PrefixExpr,
|
||||
InfixExpr,
|
||||
IndexExpr,
|
||||
CallExpr,
|
||||
MemberExpr, // obj.prop
|
||||
ObjectInitExpr, // new Point{}
|
||||
|
||||
/* Statements */
|
||||
ExprStmt, // 表达式语句,如 println(1)
|
||||
VarDecl, // 变量声明
|
||||
IfStmt, // If语句
|
||||
ElseIfStmt, // ElseIf语句,不准悬空,平铺式else if
|
||||
WhileStmt, // while语句
|
||||
FnDefStmt, // func函数定义语句
|
||||
ReturnStmt, // 返回语句
|
||||
BreakStmt, // break语句
|
||||
ContinueStmt, // continue语句
|
||||
ExprStmt,
|
||||
VarDecl,
|
||||
IfStmt,
|
||||
ElseIfStmt,
|
||||
WhileStmt,
|
||||
FnDefStmt,
|
||||
StructDefStmt,
|
||||
InterfaceDefStmt,
|
||||
ImplStmt, // impl Document for File {}
|
||||
ReturnStmt,
|
||||
BreakStmt,
|
||||
ContinueStmt,
|
||||
|
||||
/* Type Expressions */
|
||||
TypeExpr, // 基类
|
||||
NamedTypeExpr, // 命名类型,支持namespace, std.file这样的
|
||||
// 泛型等...
|
||||
TypeExpr,
|
||||
NamedTypeExpr,
|
||||
NullableTypeExpr
|
||||
};
|
||||
|
||||
struct AstNode
|
||||
{
|
||||
AstType type = AstType::AstNode;
|
||||
@@ -66,13 +69,10 @@ namespace Fig
|
||||
virtual ~TypeExpr() = default;
|
||||
};
|
||||
|
||||
struct Program;
|
||||
|
||||
struct Expr : public AstNode
|
||||
{
|
||||
TypeInfo *resolvedType = nullptr;
|
||||
// TODO: 可选的常量折叠
|
||||
// 拓展 isConstExpr和 constValue槽位
|
||||
// 语义分析后填充
|
||||
Type resolvedType;
|
||||
|
||||
Expr()
|
||||
{
|
||||
@@ -82,7 +82,7 @@ namespace Fig
|
||||
|
||||
struct Stmt : public AstNode
|
||||
{
|
||||
bool isPublic;
|
||||
bool isPublic = false;
|
||||
Stmt()
|
||||
{
|
||||
type = AstType::Stmt;
|
||||
@@ -92,22 +92,10 @@ namespace Fig
|
||||
struct Program final : public AstNode
|
||||
{
|
||||
DynArray<Stmt *> nodes;
|
||||
|
||||
Program()
|
||||
{
|
||||
type = AstType::Program;
|
||||
}
|
||||
|
||||
Program(DynArray<Stmt *> _nodes)
|
||||
{
|
||||
type = AstType::Program;
|
||||
nodes = std::move(_nodes);
|
||||
if (!_nodes.empty())
|
||||
{
|
||||
location = std::move(_nodes.back()->location);
|
||||
}
|
||||
}
|
||||
|
||||
virtual String toString() const override
|
||||
{
|
||||
return "<Program>";
|
||||
@@ -121,36 +109,9 @@ namespace Fig
|
||||
{
|
||||
type = AstType::BlockStmt;
|
||||
}
|
||||
BlockStmt(DynArray<Stmt *> _nodes)
|
||||
{
|
||||
type = AstType::BlockStmt;
|
||||
nodes = std::move(_nodes);
|
||||
if (!_nodes.empty())
|
||||
{
|
||||
location = std::move(_nodes.back()->location);
|
||||
}
|
||||
}
|
||||
virtual String toString() const override
|
||||
{
|
||||
return "<BlockStmt>";
|
||||
}
|
||||
};
|
||||
}; // namespace Fig
|
||||
|
||||
namespace std
|
||||
{
|
||||
template <>
|
||||
struct std::formatter<Fig::AstNode *, char>
|
||||
{
|
||||
constexpr auto parse(std::format_parse_context &ctx)
|
||||
{
|
||||
return ctx.begin();
|
||||
}
|
||||
|
||||
template <typename FormatContext>
|
||||
auto format(const Fig::AstNode *_node, FormatContext &ctx) const
|
||||
{
|
||||
return std::format_to(ctx.out(), "{}", _node->toString().toStdString());
|
||||
}
|
||||
};
|
||||
}; // namespace std
|
||||
} // namespace Fig
|
||||
|
||||
@@ -1,48 +1,32 @@
|
||||
/*!
|
||||
@file src/Ast/Expr/IdentiExpr.hpp
|
||||
@brief IdentiExpr定义
|
||||
@author PuqiAR (im@puqiar.top)
|
||||
@date 2026-02-14
|
||||
@brief 标识符表达式定义
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <Ast/Base.hpp>
|
||||
#include <Deps/Deps.hpp>
|
||||
#include <Sema/Environment.hpp>
|
||||
|
||||
namespace Fig
|
||||
{
|
||||
struct IdentiExpr final : Expr
|
||||
struct IdentiExpr final : public Expr
|
||||
{
|
||||
String name;
|
||||
|
||||
// Analyzer槽位
|
||||
|
||||
// 寻址空间
|
||||
bool isGlobal = false; // 是否全局, 全局变量存哈希/堆
|
||||
|
||||
// 仅 isGlobal = false 有效
|
||||
int resolvedDepth = -1; // 用于获取闭包上值, -1 代表未解析
|
||||
|
||||
// 栈内槽位
|
||||
int localId = -1; // 局部变量id, -1 未解析
|
||||
|
||||
String name;
|
||||
Symbol *resolvedSymbol = nullptr; // 语义分析后填充,Compiler 唯一的依赖
|
||||
|
||||
IdentiExpr()
|
||||
{
|
||||
type = AstType::IdentiExpr;
|
||||
}
|
||||
|
||||
IdentiExpr(String _name, SourceLocation _loc)
|
||||
IdentiExpr(String _name, SourceLocation _location) : name(std::move(_name))
|
||||
{
|
||||
type = AstType::IdentiExpr;
|
||||
name = std::move(_name);
|
||||
location = std::move(_loc);
|
||||
type = AstType::IdentiExpr;
|
||||
location = std::move(_location);
|
||||
}
|
||||
|
||||
virtual String toString() const override
|
||||
{
|
||||
return std::format("<IdentiExpr: {}>", name);
|
||||
return std::format("<IdentiExpr '{}'>", name);
|
||||
}
|
||||
};
|
||||
};
|
||||
} // namespace Fig
|
||||
|
||||
@@ -1,36 +1,27 @@
|
||||
/*!
|
||||
@file src/Ast/Expr/LiteralExpr.hpp
|
||||
@brief 字面量表达式定义
|
||||
@author PuqiAR (im@puqiar.top)
|
||||
@date 2026-02-14
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <Ast/Base.hpp>
|
||||
#include <Token/Token.hpp>
|
||||
|
||||
#include <Deps/Deps.hpp>
|
||||
|
||||
namespace Fig
|
||||
{
|
||||
struct LiteralExpr final : Expr
|
||||
struct LiteralExpr final : public Expr
|
||||
{
|
||||
Token token;
|
||||
Token literal;
|
||||
|
||||
LiteralExpr()
|
||||
{
|
||||
type = AstType::LiteralExpr;
|
||||
}
|
||||
LiteralExpr(const Token& token, SourceLocation _location) : token(token)
|
||||
LiteralExpr() { type = AstType::LiteralExpr; }
|
||||
LiteralExpr(const Token &_literal, SourceLocation _location) : literal(_literal)
|
||||
{
|
||||
type = AstType::LiteralExpr;
|
||||
location = std::move(_location);
|
||||
}
|
||||
|
||||
virtual String toString() const override
|
||||
{
|
||||
return std::format("<LiteralExpr: {}>", magic_enum::enum_name(token.type));
|
||||
virtual String toString() const override {
|
||||
return std::format("<LiteralExpr: {}>", magic_enum::enum_name(literal.type));
|
||||
}
|
||||
};
|
||||
}; // namespace Fig
|
||||
}
|
||||
|
||||
35
src/Ast/Expr/MemberExpr.hpp
Normal file
35
src/Ast/Expr/MemberExpr.hpp
Normal file
@@ -0,0 +1,35 @@
|
||||
/*!
|
||||
@file src/Ast/Expr/MemberExpr.hpp
|
||||
@brief 成员访问表达式定义:obj.member
|
||||
@author PuqiAR (im@puqiar.top)
|
||||
@date 2026-03-08
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <Ast/Base.hpp>
|
||||
|
||||
namespace Fig
|
||||
{
|
||||
struct MemberExpr final : public Expr
|
||||
{
|
||||
Expr *target; // 访问对象
|
||||
String name; // 成员名字
|
||||
|
||||
MemberExpr()
|
||||
{
|
||||
type = AstType::MemberExpr;
|
||||
}
|
||||
|
||||
MemberExpr(Expr *_t, String _n, SourceLocation _loc) : target(_t), name(std::move(_n))
|
||||
{
|
||||
type = AstType::MemberExpr;
|
||||
location = std::move(_loc);
|
||||
}
|
||||
|
||||
virtual String toString() const override
|
||||
{
|
||||
return std::format("<MemberExpr {}.{}>", target->toString(), name);
|
||||
}
|
||||
};
|
||||
} // namespace Fig
|
||||
50
src/Ast/Expr/ObjectInitExpr.hpp
Normal file
50
src/Ast/Expr/ObjectInitExpr.hpp
Normal file
@@ -0,0 +1,50 @@
|
||||
/*!
|
||||
@file src/Ast/Expr/ObjectInitExpr.hpp
|
||||
@brief 对象初始化表达式 AST 定义
|
||||
@author PuqiAR (im@puqiar.top)
|
||||
@date 2026-03-08
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <Ast/Base.hpp>
|
||||
|
||||
namespace Fig
|
||||
{
|
||||
struct ObjectInitExpr final : public Expr
|
||||
{
|
||||
struct Arg
|
||||
{
|
||||
String name;
|
||||
Expr *value;
|
||||
};
|
||||
TypeExpr *typeExpr;
|
||||
DynArray<Arg> args;
|
||||
|
||||
ObjectInitExpr()
|
||||
{
|
||||
type = AstType::ObjectInitExpr;
|
||||
}
|
||||
ObjectInitExpr(TypeExpr *_te, DynArray<Arg> _args, SourceLocation _loc) :
|
||||
typeExpr(_te), args(std::move(_args))
|
||||
{
|
||||
type = AstType::ObjectInitExpr;
|
||||
location = std::move(_loc);
|
||||
}
|
||||
|
||||
virtual String toString() const override
|
||||
{
|
||||
String res = "<ObjectInitExpr 'new " + typeExpr->toString() + "{";
|
||||
for (size_t i = 0; i < args.size(); ++i)
|
||||
{
|
||||
if (!args[i].name.empty())
|
||||
res += args[i].name + ": ";
|
||||
res += args[i].value->toString();
|
||||
if (i < args.size() - 1)
|
||||
res += ", ";
|
||||
}
|
||||
res += "}'>";
|
||||
return res;
|
||||
}
|
||||
};
|
||||
} // namespace Fig
|
||||
@@ -1,102 +1,47 @@
|
||||
/*!
|
||||
@file src/Ast/Stmt/FnDefStmt.hpp
|
||||
@brief FnDefStmt定义
|
||||
@author PuqiAR (im@puqiar.top)
|
||||
@date 2026-02-25
|
||||
@brief 函数定义 AST 节点
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <Ast/Base.hpp>
|
||||
#include <Sema/Environment.hpp>
|
||||
|
||||
namespace Fig
|
||||
{
|
||||
struct Param
|
||||
{
|
||||
String name;
|
||||
SourceLocation location;
|
||||
|
||||
TypeInfo *resolvedType = nullptr;
|
||||
int localId = -1;
|
||||
|
||||
virtual String toString() const = 0;
|
||||
};
|
||||
|
||||
struct PosParam final : public Param
|
||||
{
|
||||
TypeExpr *type;
|
||||
struct Param : public AstNode {
|
||||
String name;
|
||||
TypeExpr *typeSpecifier;
|
||||
Expr *defaultValue;
|
||||
|
||||
PosParam() {}
|
||||
PosParam(String _name, TypeExpr *_type, Expr *_defaultValue, SourceLocation _location) :
|
||||
type(_type), defaultValue(_defaultValue)
|
||||
{
|
||||
name = std::move(_name);
|
||||
location = std::move(_location);
|
||||
}
|
||||
|
||||
virtual String toString() const override
|
||||
{
|
||||
return std::format("<Pos {}: {}{}>",
|
||||
name,
|
||||
(type ? type->toString() : "Any"),
|
||||
(defaultValue ? " =" + defaultValue->toString() : ""));
|
||||
}
|
||||
Type resolvedType;
|
||||
Param() { type = AstType::AstNode; }
|
||||
virtual ~Param() = default;
|
||||
};
|
||||
|
||||
/*
|
||||
(public) func foo([name: (type) (= default value)]) (-> return type)
|
||||
{
|
||||
...
|
||||
struct PosParam final : public Param {
|
||||
PosParam(String _n, TypeExpr *_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;
|
||||
struct FnDefStmt final : public Stmt {
|
||||
String name;
|
||||
DynArray<Param *> params;
|
||||
TypeExpr *returnType;
|
||||
BlockStmt *body;
|
||||
TypeExpr *returnTypeSpecifier;
|
||||
BlockStmt *body;
|
||||
Type resolvedReturnType;
|
||||
Symbol *resolvedSymbol = nullptr; // 连接物理符号
|
||||
|
||||
TypeInfo *resolvedReturnType = nullptr;
|
||||
int localId = -1;
|
||||
|
||||
FnDefStmt()
|
||||
FnDefStmt() { type = AstType::FnDefStmt; }
|
||||
FnDefStmt(bool _p, String _n, DynArray<Param *> _pa, TypeExpr *_rt, BlockStmt *_b, SourceLocation _loc)
|
||||
: name(std::move(_n)), params(std::move(_pa)), returnTypeSpecifier(_rt), body(_b)
|
||||
{
|
||||
type = AstType::FnDefStmt;
|
||||
type = AstType::FnDefStmt; isPublic = _p; location = std::move(_loc);
|
||||
}
|
||||
|
||||
FnDefStmt(bool _isPublic,
|
||||
String _name,
|
||||
DynArray<Param *> _params,
|
||||
TypeExpr *_returnType,
|
||||
BlockStmt *_body,
|
||||
SourceLocation _location) :
|
||||
name(std::move(_name)), params(std::move(_params)), returnType(_returnType), body(_body)
|
||||
{
|
||||
type = AstType::FnDefStmt;
|
||||
isPublic = _isPublic;
|
||||
location = std::move(_location);
|
||||
}
|
||||
|
||||
virtual String toString() const override
|
||||
{
|
||||
String pStr;
|
||||
for (const Param *p : params)
|
||||
{
|
||||
if (p != *params.begin())
|
||||
{
|
||||
pStr += ", ";
|
||||
}
|
||||
pStr += p->toString();
|
||||
}
|
||||
return std::format("<FnDefStmt {}{}({}) -> {} {{{}}}>",
|
||||
(isPublic ? "public " : ""),
|
||||
name,
|
||||
pStr,
|
||||
(returnType ? returnType->toString() : "Any"),
|
||||
body->toString());
|
||||
virtual String toString() const override {
|
||||
return std::format("<FnDefStmt '{}'>", name);
|
||||
}
|
||||
};
|
||||
}; // namespace Fig
|
||||
}
|
||||
|
||||
32
src/Ast/Stmt/ImplStmt.hpp
Normal file
32
src/Ast/Stmt/ImplStmt.hpp
Normal file
@@ -0,0 +1,32 @@
|
||||
/*!
|
||||
@file src/Ast/Stmt/ImplStmt.hpp
|
||||
@brief 实现块 AST 节点
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
#include <Ast/Base.hpp>
|
||||
#include <Ast/Stmt/FnDefStmt.hpp>
|
||||
|
||||
namespace Fig
|
||||
{
|
||||
struct ImplStmt final : public Stmt
|
||||
{
|
||||
TypeExpr *interfaceType;
|
||||
TypeExpr *structType;
|
||||
DynArray<FnDefStmt *> methods;
|
||||
|
||||
ImplStmt(TypeExpr *_it, TypeExpr *_st, DynArray<FnDefStmt *> _m, SourceLocation _loc) :
|
||||
interfaceType(_it), structType(_st), methods(std::move(_m))
|
||||
{
|
||||
type = AstType::ImplStmt;
|
||||
location = std::move(_loc);
|
||||
}
|
||||
|
||||
virtual String toString() const override
|
||||
{
|
||||
String detail =
|
||||
(interfaceType ? interfaceType->toString() + " for " : "") + structType->toString();
|
||||
return std::format("<ImplStmt '{}'>", detail);
|
||||
}
|
||||
};
|
||||
} // namespace Fig
|
||||
39
src/Ast/Stmt/InterfaceDefStmt.hpp
Normal file
39
src/Ast/Stmt/InterfaceDefStmt.hpp
Normal file
@@ -0,0 +1,39 @@
|
||||
/*!
|
||||
@file src/Ast/Stmt/InterfaceDefStmt.hpp
|
||||
@brief 接口定义 AST 节点
|
||||
@author PuqiAR (im@puqiar.top)
|
||||
@date 2026-03-08
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <Ast/Base.hpp>
|
||||
|
||||
namespace Fig
|
||||
{
|
||||
struct InterfaceDefStmt final : public Stmt
|
||||
{
|
||||
struct Method
|
||||
{
|
||||
String name;
|
||||
DynArray<TypeExpr*> params;
|
||||
TypeExpr *retType;
|
||||
SourceLocation location;
|
||||
};
|
||||
|
||||
bool isPublic;
|
||||
String name;
|
||||
DynArray<Method> methods;
|
||||
|
||||
InterfaceDefStmt() { type = AstType::InterfaceDefStmt; }
|
||||
|
||||
InterfaceDefStmt(bool _p, String _n, DynArray<Method> _m, SourceLocation _loc)
|
||||
: isPublic(_p), name(std::move(_n)), methods(std::move(_m))
|
||||
{
|
||||
type = AstType::InterfaceDefStmt;
|
||||
location = std::move(_loc);
|
||||
}
|
||||
|
||||
virtual String toString() const override { return "<InterfaceDefStmt>"; }
|
||||
};
|
||||
} // namespace Fig
|
||||
56
src/Ast/Stmt/StructDefStmt.hpp
Normal file
56
src/Ast/Stmt/StructDefStmt.hpp
Normal file
@@ -0,0 +1,56 @@
|
||||
/*!
|
||||
@file src/Ast/Stmt/StructDefStmt.hpp
|
||||
@brief 结构体定义 AST 节点
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
#include <Ast/Base.hpp>
|
||||
#include <Ast/Stmt/FnDefStmt.hpp>
|
||||
|
||||
namespace Fig
|
||||
{
|
||||
struct StructDefStmt final : public Stmt
|
||||
{
|
||||
struct Field
|
||||
{
|
||||
String name;
|
||||
TypeExpr *type;
|
||||
bool isPublic;
|
||||
};
|
||||
bool isPublic;
|
||||
String name;
|
||||
DynArray<String> typeParameters;
|
||||
DynArray<Field> fields;
|
||||
DynArray<FnDefStmt *> methods;
|
||||
|
||||
StructDefStmt()
|
||||
{
|
||||
type = AstType::StructDefStmt;
|
||||
}
|
||||
StructDefStmt(bool _p,
|
||||
String _n,
|
||||
DynArray<String> _tp,
|
||||
DynArray<Field> _f,
|
||||
DynArray<FnDefStmt *> _m,
|
||||
SourceLocation _loc) :
|
||||
isPublic(_p),
|
||||
name(std::move(_n)),
|
||||
typeParameters(std::move(_tp)),
|
||||
fields(std::move(_f)),
|
||||
methods(std::move(_m))
|
||||
{
|
||||
type = AstType::StructDefStmt;
|
||||
location = std::move(_loc);
|
||||
}
|
||||
|
||||
virtual String toString() const override
|
||||
{
|
||||
String detail = name;
|
||||
if (!typeParameters.empty())
|
||||
{
|
||||
detail += "<...>";
|
||||
}
|
||||
return std::format("<StructDefStmt '{}'>", detail);
|
||||
}
|
||||
};
|
||||
} // namespace Fig
|
||||
@@ -1,8 +1,6 @@
|
||||
/*!
|
||||
@file src/Ast/TypeExpr.hpp
|
||||
@brief TypeExpr定义
|
||||
@author PuqiAR (im@puqiar.top)
|
||||
@date 2026-02-25
|
||||
@brief 类型表达式 AST 定义:支持泛型与空安全
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
@@ -11,26 +9,59 @@
|
||||
|
||||
namespace Fig
|
||||
{
|
||||
|
||||
struct NamedTypeExpr final : public TypeExpr
|
||||
{
|
||||
DynArray<String> path; // {"std", "file"} etc.
|
||||
DynArray<String> path;
|
||||
DynArray<TypeExpr *> arguments;
|
||||
|
||||
NamedTypeExpr()
|
||||
{
|
||||
type = AstType::NamedTypeExpr;
|
||||
}
|
||||
|
||||
NamedTypeExpr(DynArray<String> _path, SourceLocation _location) :
|
||||
path(std::move(_path))
|
||||
NamedTypeExpr(DynArray<String> _p, DynArray<TypeExpr *> _args, SourceLocation _loc) :
|
||||
path(std::move(_p)), arguments(std::move(_args))
|
||||
{
|
||||
type = AstType::NamedTypeExpr;
|
||||
location = std::move(_location);
|
||||
type = AstType::NamedTypeExpr;
|
||||
location = std::move(_loc);
|
||||
}
|
||||
|
||||
virtual String toString() const override
|
||||
{
|
||||
return std::format("<NamedTypeExpr '{}'>", path);
|
||||
String detail = "";
|
||||
for (size_t i = 0; i < path.size(); ++i)
|
||||
{
|
||||
detail += path[i];
|
||||
if (i < path.size() - 1)
|
||||
detail += ".";
|
||||
}
|
||||
if (!arguments.empty())
|
||||
{
|
||||
detail += "<";
|
||||
for (size_t i = 0; i < arguments.size(); ++i)
|
||||
{
|
||||
detail += arguments[i]->toString();
|
||||
if (i < arguments.size() - 1)
|
||||
detail += ", ";
|
||||
}
|
||||
detail += ">";
|
||||
}
|
||||
return std::format("<NamedTypeExpr '{}'>", detail);
|
||||
}
|
||||
};
|
||||
};
|
||||
|
||||
struct NullableTypeExpr final : public TypeExpr
|
||||
{
|
||||
TypeExpr *inner;
|
||||
|
||||
NullableTypeExpr(TypeExpr *_inner, SourceLocation _loc) : inner(_inner)
|
||||
{
|
||||
type = AstType::NullableTypeExpr;
|
||||
location = std::move(_loc);
|
||||
}
|
||||
|
||||
virtual String toString() const override
|
||||
{
|
||||
return std::format("<NullableTypeExpr '{}?'>", inner->toString());
|
||||
}
|
||||
};
|
||||
} // namespace Fig
|
||||
|
||||
@@ -1,87 +1,83 @@
|
||||
/*!
|
||||
@file src/Bytecode/Bytecode.hpp
|
||||
@brief 字节码Bytecode定义
|
||||
@author PuqiAR (im@puqiar.top)
|
||||
@date 2026-02-18
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <cstdint>
|
||||
|
||||
#pragma once
|
||||
#include <cstdint>
|
||||
|
||||
namespace Fig
|
||||
{
|
||||
|
||||
// 定长 32-bit
|
||||
using Instruction = std::uint32_t;
|
||||
|
||||
enum class OpCode : std::uint8_t
|
||||
{
|
||||
Exit, // 结束运行
|
||||
|
||||
LoadK, // iABx 模式: R[A] = Constants[Bx]
|
||||
LoadTrue, // iABC: R[A] = true
|
||||
LoadFalse, // iABC: R[A] = false
|
||||
LoadNull, // iABC: R[A] = null
|
||||
Exit,
|
||||
Exit_MaxRecursionDepthExceeded,
|
||||
|
||||
FastCall, // iABC: A: ProtoIdx, B: 函数起始寄存器
|
||||
Call, // 动态派发 iABC: A: 函数体对象寄存器 B: 函数起始寄存器
|
||||
Return, // iABC 模式: 返回 R[A] 的值
|
||||
LoadK,
|
||||
LoadTrue,
|
||||
LoadFalse,
|
||||
LoadNull,
|
||||
|
||||
LoadFn, // 惰性装修, iABx: R[A] = new FunctionObject...
|
||||
FastCall,
|
||||
Call,
|
||||
Return,
|
||||
|
||||
Jmp, // iAsBx: ip += sBx 无条件跳转
|
||||
JmpIfFalse, // iAsBx: 如果 R[A] 为假, ip += sBx
|
||||
LoadFn,
|
||||
|
||||
Mov, // iABx: R[A] = R[Bx]
|
||||
Jmp,
|
||||
JmpIfFalse,
|
||||
|
||||
Add, // iABC: R[A] = R[B] + R[C]
|
||||
Sub, // iABC: R[A] = R[B] - R[C]
|
||||
Mul, // iABC: R[A] = R[B] * R[C]
|
||||
Div, // iABC: R[A] = R[B] / R[C]
|
||||
Mod, // iABC: R[A] = R[B] % R[C]
|
||||
BitXor, // iABC: R[A] = R[B] ^ R[C]
|
||||
Mov,
|
||||
|
||||
IntFastAdd, // iABC: R[A] (Int) = R[B] (Int) + R[C] (Int)
|
||||
IntFastSub, // iABC: R[A] (Int) = R[B] (Int) - R[C] (Int)
|
||||
IntFastMul, // iABC: R[A] (Int) = R[B] (Int) * R[C] (Int)
|
||||
IntFastDiv, // iABC: R[A] (Double) = R[B] (Int) / R[C] (Int)
|
||||
Add,
|
||||
Sub,
|
||||
Mul,
|
||||
Div,
|
||||
Mod,
|
||||
BitXor,
|
||||
|
||||
Equal, // iABC: R[A] = R[B] == R[C]
|
||||
NotEqual, // iABC: R[A] = R[B] != R[C]
|
||||
Greater, // iABC: R[A] = R[B] > R[C]
|
||||
Less, // iABC: R[A] = R[B] < R[C]
|
||||
GreaterEqual, // iABC: R[A] = R[B] >= R[C]
|
||||
LessEqual, // iABC: R[A] = R[B] <= R[C]
|
||||
IntFastAdd,
|
||||
IntFastSub,
|
||||
IntFastMul,
|
||||
IntFastDiv,
|
||||
|
||||
Count, // 哨兵
|
||||
Equal,
|
||||
NotEqual,
|
||||
Greater,
|
||||
Less,
|
||||
GreaterEqual,
|
||||
LessEqual,
|
||||
|
||||
GetGlobal,
|
||||
SetGlobal,
|
||||
GetUpval,
|
||||
SetUpval,
|
||||
Copy,
|
||||
|
||||
Count
|
||||
};
|
||||
|
||||
namespace Op
|
||||
{
|
||||
// [OpCode: 8] [A: 8] [Bx: 16]
|
||||
[[nodiscard]] inline constexpr Instruction iABx(OpCode op, std::uint8_t a, std::uint16_t bx)
|
||||
{
|
||||
return static_cast<std::uint32_t>(op) | (static_cast<std::uint32_t>(a) << 8)
|
||||
| (static_cast<std::uint32_t>(bx) << 16);
|
||||
}
|
||||
|
||||
// [OpCode: 8] [A: 8] [B: 8] [C: 8]
|
||||
[[nodiscard]] inline constexpr Instruction iABC(
|
||||
OpCode op, std::uint8_t a, std::uint8_t b, std::uint8_t c)
|
||||
[[nodiscard]] inline constexpr Instruction iABC(OpCode op, std::uint8_t a, std::uint8_t b, std::uint8_t c)
|
||||
{
|
||||
return static_cast<std::uint32_t>(op) | (static_cast<std::uint32_t>(a) << 8)
|
||||
| (static_cast<std::uint32_t>(b) << 16) | (static_cast<std::uint32_t>(c) << 24);
|
||||
}
|
||||
|
||||
[[nodiscard]]
|
||||
inline constexpr Instruction iAsBx(OpCode op, std::uint8_t a, std::int16_t sbx)
|
||||
[[nodiscard]] inline constexpr Instruction iAsBx(OpCode op, std::uint8_t a, std::int16_t sbx)
|
||||
{
|
||||
return static_cast<std::uint32_t>(op) | (static_cast<std::uint32_t>(a) << 8)
|
||||
| (static_cast<std::uint32_t>(static_cast<std::uint16_t>(sbx)) << 16);
|
||||
}
|
||||
} // namespace Op
|
||||
} // namespace Fig
|
||||
} // namespace Fig
|
||||
|
||||
100
src/Bytecode/Disassembler.cpp
Normal file
100
src/Bytecode/Disassembler.cpp
Normal file
@@ -0,0 +1,100 @@
|
||||
/*!
|
||||
@file src/Bytecode/Disassembler.cpp
|
||||
@brief 字节码反汇编器实现
|
||||
*/
|
||||
|
||||
#include <Bytecode/Disassembler.hpp>
|
||||
#include <iostream>
|
||||
#include <format>
|
||||
|
||||
namespace Fig
|
||||
{
|
||||
void Disassembler::DisassembleModule(const CompiledModule *module)
|
||||
{
|
||||
if (!module) return;
|
||||
std::cout << "--- Module Disassembly ---" << std::endl;
|
||||
for (auto *proto : module->protos)
|
||||
{
|
||||
DisassembleProto(proto);
|
||||
}
|
||||
}
|
||||
|
||||
void Disassembler::DisassembleProto(const Proto *proto)
|
||||
{
|
||||
if (!proto) return;
|
||||
|
||||
std::cout << std::format("\n--- Proto: {} (Regs: {}, Params: {}) ---\n",
|
||||
proto->name, proto->maxRegisters, proto->numParams);
|
||||
|
||||
for (size_t i = 0; i < proto->code.size(); ++i)
|
||||
{
|
||||
Instruction inst = proto->code[i];
|
||||
OpCode op = static_cast<OpCode>(inst & 0xFF);
|
||||
uint8_t a = (inst >> 8) & 0xFF;
|
||||
|
||||
std::cout << std::format("[{:04}] {:<12} ", i, magic_enum::enum_name(op));
|
||||
|
||||
Format fmt = GetFormat(op);
|
||||
if (fmt == Format::ABC)
|
||||
{
|
||||
uint8_t b = (inst >> 16) & 0xFF;
|
||||
uint8_t c = (inst >> 24) & 0xFF;
|
||||
std::cout << std::format("A:{:<3} B:{:<3} C:{:<3}", a, b, c);
|
||||
}
|
||||
else if (fmt == Format::ABx)
|
||||
{
|
||||
uint16_t bx = (inst >> 16) & 0xFFFF;
|
||||
std::cout << std::format("A:{:<3} Bx:{:<5}", a, bx);
|
||||
|
||||
// 自动关联常量池
|
||||
if (op == OpCode::LoadK && bx < proto->constants.size())
|
||||
{
|
||||
std::cout << std::format(" ; {}", proto->constants[bx].ToString());
|
||||
}
|
||||
}
|
||||
else if (fmt == Format::AsBx)
|
||||
{
|
||||
int16_t sbx = static_cast<int16_t>((inst >> 16) & 0xFFFF);
|
||||
std::cout << std::format("A:{:<3} sBx:{:<5}", a, sbx);
|
||||
|
||||
// 计算跳转绝对地址
|
||||
if (op == OpCode::Jmp || op == OpCode::JmpIfFalse)
|
||||
{
|
||||
std::cout << std::format(" ; to [{:04}]", i + sbx + 1);
|
||||
}
|
||||
}
|
||||
std::cout << "\n";
|
||||
}
|
||||
|
||||
if (!proto->constants.empty())
|
||||
{
|
||||
std::cout << "Constants:\n";
|
||||
for (size_t i = 0; i < proto->constants.size(); ++i)
|
||||
{
|
||||
std::cout << std::format(" [{}] {}\n", i, proto->constants[i].ToString());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Disassembler::Format Disassembler::GetFormat(OpCode op)
|
||||
{
|
||||
switch (op)
|
||||
{
|
||||
case OpCode::LoadK:
|
||||
case OpCode::Mov:
|
||||
case OpCode::GetGlobal:
|
||||
case OpCode::SetGlobal:
|
||||
case OpCode::LoadFn:
|
||||
return Format::ABx;
|
||||
|
||||
case OpCode::Exit:
|
||||
case OpCode::Exit_MaxRecursionDepthExceeded:
|
||||
case OpCode::Jmp:
|
||||
case OpCode::JmpIfFalse:
|
||||
return Format::AsBx;
|
||||
|
||||
default:
|
||||
return Format::ABC;
|
||||
}
|
||||
}
|
||||
} // namespace Fig
|
||||
34
src/Bytecode/Disassembler.hpp
Normal file
34
src/Bytecode/Disassembler.hpp
Normal file
@@ -0,0 +1,34 @@
|
||||
/*!
|
||||
@file src/Bytecode/Disassembler.hpp
|
||||
@brief 字节码反汇编器:物理还原指令语义
|
||||
@author PuqiAR (im@puqiar.top)
|
||||
@date 2026-03-08
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <Bytecode/Bytecode.hpp>
|
||||
#include <Compiler/Compiler.hpp>
|
||||
|
||||
namespace Fig
|
||||
{
|
||||
class Disassembler
|
||||
{
|
||||
public:
|
||||
// 反汇编整个模块
|
||||
static void DisassembleModule(const CompiledModule *module);
|
||||
|
||||
// 反汇编单个函数原型
|
||||
static void DisassembleProto(const Proto *proto);
|
||||
|
||||
private:
|
||||
enum class Format
|
||||
{
|
||||
ABC,
|
||||
ABx,
|
||||
AsBx
|
||||
};
|
||||
|
||||
static Format GetFormat(OpCode op);
|
||||
};
|
||||
} // namespace Fig
|
||||
@@ -1,66 +1,63 @@
|
||||
#include <Compiler/Compiler.hpp>
|
||||
#include <Core/Core.hpp>
|
||||
#include <Deps/Deps.hpp>
|
||||
#include <Lexer/Lexer.hpp>
|
||||
#include <Parser/Parser.hpp>
|
||||
#include <SourceManager/SourceManager.hpp>
|
||||
|
||||
|
||||
#include <Sema/Analyzer.hpp>
|
||||
#include <Compiler/Compiler.hpp>
|
||||
#include <Bytecode/Disassembler.hpp>
|
||||
#include <iostream>
|
||||
#include <print>
|
||||
#include <filesystem>
|
||||
|
||||
int main()
|
||||
{
|
||||
using namespace 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/tests/Compiler/test_basic.fig";
|
||||
|
||||
SourceManager manager(filePath);
|
||||
manager.Read();
|
||||
|
||||
if (!manager.read)
|
||||
if (!std::filesystem::exists(filePath.toStdString()))
|
||||
{
|
||||
std::cerr << "Couldn't read file";
|
||||
std::cerr << "CRITICAL: Test file not found at: " << filePath << "\n";
|
||||
return 1;
|
||||
}
|
||||
|
||||
Lexer lexer(manager.GetSource(), fileName);
|
||||
Parser parser(lexer, manager, fileName);
|
||||
SourceManager sm{filePath};
|
||||
String source = sm.Read();
|
||||
|
||||
const auto &program_result = parser.Parse();
|
||||
if (!program_result)
|
||||
if (!sm.read || source.length() == 0)
|
||||
{
|
||||
ReportError(program_result.error(), manager);
|
||||
return 1;
|
||||
}
|
||||
Program *program = *program_result;
|
||||
|
||||
Compiler compiler(fileName, manager);
|
||||
const auto &comp_result = compiler.Compile(program);
|
||||
if (!comp_result)
|
||||
{
|
||||
ReportError(comp_result.error(), manager);
|
||||
std::cerr << "CRITICAL: SourceManager failed to read: " << filePath << "\n";
|
||||
return 1;
|
||||
}
|
||||
|
||||
CompiledModule *compiledModule = *comp_result;
|
||||
Lexer lexer(source, filePath);
|
||||
Parser parser(lexer, sm, filePath);
|
||||
|
||||
size_t cnt = 0;
|
||||
for (Proto *proto : compiledModule->protos)
|
||||
auto pRes = parser.Parse();
|
||||
if (!pRes)
|
||||
{
|
||||
std::cout << "=====================\n"
|
||||
<< "Proto: " << cnt++ << '\n';
|
||||
std::cout << "=== Constant Pool ===" << '\n';
|
||||
for (size_t i = 0; i < proto->constants.size(); ++i)
|
||||
{
|
||||
std::print("[{}] {}\n", i, proto->constants[i].ToString());
|
||||
}
|
||||
|
||||
DumpCode(proto->code);
|
||||
|
||||
std::cout << "\nMax Stack Size: " << (int) proto->maxStack << std::endl;
|
||||
ReportError(pRes.error(), sm);
|
||||
return 1;
|
||||
}
|
||||
|
||||
Program *program = *pRes;
|
||||
std::cout << "Successfully parsed nodes: " << program->nodes.size() << "\n";
|
||||
|
||||
Analyzer analyzer(sm);
|
||||
auto aRes = analyzer.Analyze(program);
|
||||
if (!aRes)
|
||||
{
|
||||
ReportError(aRes.error(), sm);
|
||||
return 1;
|
||||
}
|
||||
|
||||
Diagnostics diag;
|
||||
Compiler compiler(sm, diag);
|
||||
auto cRes = compiler.Compile(program);
|
||||
if (!cRes)
|
||||
{
|
||||
ReportError(cRes.error(), sm);
|
||||
return 1;
|
||||
}
|
||||
|
||||
// 使用正式的 Disassembler
|
||||
Disassembler::DisassembleModule(*cRes);
|
||||
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,36 +1,125 @@
|
||||
/*!
|
||||
@file src/Compiler/Compiler.cpp
|
||||
@brief 编译器实现
|
||||
@author PuqiAR (im@puqiar.top)
|
||||
@date 2026-02-18
|
||||
@brief 编译器主逻辑实现:物理 Bootstrapper 与双步扫描
|
||||
*/
|
||||
|
||||
#include <Compiler/Compiler.hpp>
|
||||
#include <Ast/Stmt/FnDefStmt.hpp>
|
||||
|
||||
namespace Fig
|
||||
{
|
||||
Result<CompiledModule *, Error> Compiler::Compile(Program *program)
|
||||
{
|
||||
current->freeReg = 0;
|
||||
module = new CompiledModule();
|
||||
|
||||
for (Stmt *stmt : program->nodes)
|
||||
// 1. 预留 Protos[0] 给 Bootstrapper
|
||||
Proto *bootProto = new Proto();
|
||||
bootProto->name = "[bootstrapper]";
|
||||
module->protos.push_back(bootProto);
|
||||
|
||||
int initIdx = -1;
|
||||
int mainIdx = -1;
|
||||
|
||||
// 2. 第一步:预扫描顶层函数,锁定物理索引
|
||||
for (auto *stmt : program->nodes)
|
||||
{
|
||||
auto result = compileStmt(static_cast<Stmt *>(stmt));
|
||||
if (!result)
|
||||
if (stmt->type == AstType::FnDefStmt)
|
||||
{
|
||||
return std::unexpected(result.error());
|
||||
auto *f = static_cast<FnDefStmt *>(stmt);
|
||||
int idx = (int) module->protos.size();
|
||||
Proto *p = new Proto();
|
||||
p->name = f->name;
|
||||
p->numParams = (uint8_t) f->params.size();
|
||||
p->maxRegisters = p->numParams;
|
||||
|
||||
module->protos.push_back(p);
|
||||
|
||||
// 连接物理符号到索引
|
||||
if (f->resolvedSymbol)
|
||||
{
|
||||
f->resolvedSymbol->index = idx;
|
||||
}
|
||||
|
||||
if (f->name == "init")
|
||||
initIdx = idx;
|
||||
if (f->name == "main")
|
||||
mainIdx = idx;
|
||||
}
|
||||
}
|
||||
|
||||
if (mainFuncIndex != -1)
|
||||
// 3. 第二步:在 Bootstrapper 环境中编译所有语句
|
||||
FuncState bootState(bootProto, nullptr);
|
||||
current = &bootState;
|
||||
|
||||
for (auto *stmt : program->nodes)
|
||||
{
|
||||
std::uint8_t baseReg = AllocReg();
|
||||
Emit(Op::iABC(OpCode::FastCall, mainFuncIndex, baseReg, 0));
|
||||
auto res = compileStmt(stmt);
|
||||
if (!res)
|
||||
{
|
||||
return std::unexpected(res.error());
|
||||
}
|
||||
}
|
||||
|
||||
Emit(Op::iABC(OpCode::Exit, 0, 0, 0)); // 一定要退出,这是虚拟机退出信号,否则ub
|
||||
|
||||
CompiledModule *compiledModule = new CompiledModule(fileName, allProtos);
|
||||
return compiledModule;
|
||||
// 4. 发射 Bootstrapper 引导指令
|
||||
if (initIdx != -1)
|
||||
{
|
||||
emit(Op::iABC(OpCode::FastCall, (uint8_t) initIdx, 0, 0));
|
||||
}
|
||||
|
||||
if (mainIdx != -1)
|
||||
{
|
||||
emit(Op::iABC(OpCode::FastCall, (uint8_t) mainIdx, 0, 0));
|
||||
}
|
||||
|
||||
emit(Op::iAsBx(OpCode::Exit, 0, 0));
|
||||
|
||||
return module;
|
||||
}
|
||||
}; // namespace Fig
|
||||
|
||||
int Compiler::getGlobalID(const String &name)
|
||||
{
|
||||
if (globalIDMap.contains(name))
|
||||
return globalIDMap[name];
|
||||
int id = (int) globalIDMap.size();
|
||||
globalIDMap[name] = id;
|
||||
return id;
|
||||
}
|
||||
|
||||
Result<Register, Error> Compiler::allocateReg(const SourceLocation &loc)
|
||||
{
|
||||
if (current->freereg >= MAX_REGISTERS)
|
||||
{
|
||||
return std::unexpected(Error(ErrorType::RegisterOverflow, "too many registers", "", loc));
|
||||
}
|
||||
|
||||
Register reg = current->freereg++;
|
||||
if (reg >= current->proto->maxRegisters)
|
||||
{
|
||||
current->proto->maxRegisters = reg + 1;
|
||||
}
|
||||
return reg;
|
||||
}
|
||||
|
||||
void Compiler::freeReg(Register count)
|
||||
{
|
||||
if (current->freereg >= count)
|
||||
{
|
||||
current->freereg -= count;
|
||||
}
|
||||
}
|
||||
|
||||
int Compiler::addConstant(Value val)
|
||||
{
|
||||
if (current->constantMap.contains(val))
|
||||
return current->constantMap[val];
|
||||
int idx = (int) current->proto->constants.size();
|
||||
current->proto->constants.push_back(val);
|
||||
current->constantMap[val] = idx;
|
||||
return idx;
|
||||
}
|
||||
|
||||
void Compiler::emit(Instruction instr)
|
||||
{
|
||||
current->proto->code.push_back(instr);
|
||||
}
|
||||
} // namespace Fig
|
||||
|
||||
@@ -1,390 +1,72 @@
|
||||
/*!
|
||||
@file src/Compiler/Compiler.hpp
|
||||
@brief 编译器定义
|
||||
@author PuqiAR (im@puqiar.top)
|
||||
@date 2026-02-19
|
||||
@brief 编译器定义:物理直连 Bootstrapper
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <Ast/Ast.hpp>
|
||||
#include <Bytecode/Bytecode.hpp>
|
||||
#include <Deps/Deps.hpp>
|
||||
#include <Error/Error.hpp>
|
||||
#include <Error/Diagnostics.hpp>
|
||||
#include <Object/Object.hpp>
|
||||
#include <SourceManager/SourceManager.hpp>
|
||||
|
||||
#include <cassert>
|
||||
#include <iostream>
|
||||
|
||||
namespace Fig
|
||||
{
|
||||
// 编译产物-函数
|
||||
using Register = std::uint8_t;
|
||||
|
||||
struct UpvalueInfo { uint8_t index; bool isLocal; };
|
||||
|
||||
struct Proto
|
||||
{
|
||||
String name;
|
||||
DynArray<Instruction> code;
|
||||
DynArray<Value> constants;
|
||||
std::uint8_t maxStack = 0; // 函数运行所需寄存器数量
|
||||
};
|
||||
|
||||
struct LocalVar
|
||||
{
|
||||
int localId; // AST 传来的纯数字 ID
|
||||
std::uint8_t reg; // 分配到的物理寄存器 ID
|
||||
int depth; // 物理作用域深度(用于 EndScope 释放寄存器)
|
||||
};
|
||||
|
||||
inline constexpr int MAX_LOCALS = 250;
|
||||
inline constexpr int MAX_CONSTANTS = UINT16_MAX + 1;
|
||||
|
||||
// 任何跨函数、跨模块的编译,都压入弹出这个 State
|
||||
struct FuncState
|
||||
{
|
||||
String name;
|
||||
FuncState *enclosing = nullptr; // 指向外层状态 (支持闭包)
|
||||
Proto *proto = nullptr;
|
||||
|
||||
std::uint8_t freeReg = 0;
|
||||
int scopeDepth = 0;
|
||||
DynArray<LocalVar> locals;
|
||||
|
||||
std::uint8_t fastRegMap[UINT8_MAX + 1]; // 256, 索引 = localId, 值 = 寄存器 id
|
||||
|
||||
FuncState(String _name, FuncState *enc = nullptr) : name(std::move(_name)), enclosing(enc)
|
||||
{
|
||||
proto = new Proto();
|
||||
std::fill_n(fastRegMap, 256, UINT8_MAX); // 255代表未分配
|
||||
}
|
||||
// 注意:这里不 delete proto,因为 proto 是要作为编译产物吐出去的
|
||||
DynArray<UpvalueInfo> upvalues;
|
||||
uint8_t maxRegisters = 0;
|
||||
uint8_t numParams = 0;
|
||||
};
|
||||
|
||||
struct CompiledModule
|
||||
{
|
||||
String name; // 供调试/打印
|
||||
DynArray<Proto *> protos; // 扁平化函数原型
|
||||
|
||||
CompiledModule(String _name, DynArray<Proto *> _protos) :
|
||||
name(std::move(_name)), protos(std::move(_protos))
|
||||
{
|
||||
}
|
||||
|
||||
~CompiledModule()
|
||||
{
|
||||
for (auto *p : protos)
|
||||
{
|
||||
delete p;
|
||||
}
|
||||
}
|
||||
DynArray<Proto *> protos;
|
||||
};
|
||||
|
||||
class Compiler
|
||||
{
|
||||
private:
|
||||
String fileName;
|
||||
static constexpr Register MAX_REGISTERS = 250;
|
||||
static constexpr Register NO_REG = 255;
|
||||
|
||||
SourceManager &manager;
|
||||
FuncState *current = nullptr; // 永远指向当前正在编译的上下文
|
||||
|
||||
int mainFuncIndex = -1;
|
||||
HashMap<int, int> globalFuncMap; // localid -> ProtoIdx
|
||||
|
||||
public:
|
||||
DynArray<Proto *> allProtos;
|
||||
|
||||
struct FuncStateProtector
|
||||
struct FuncState
|
||||
{
|
||||
Compiler *compiler;
|
||||
FuncState *prevState;
|
||||
Proto *proto;
|
||||
Register freereg;
|
||||
FuncState *enclosing;
|
||||
HashMap<Value, int> constantMap;
|
||||
|
||||
[[nodiscard]]
|
||||
FuncStateProtector(Compiler *comp, FuncState *newState) :
|
||||
compiler(comp), prevState(comp->current)
|
||||
{
|
||||
compiler->current = newState;
|
||||
}
|
||||
|
||||
~FuncStateProtector()
|
||||
{
|
||||
compiler->current = prevState;
|
||||
}
|
||||
FuncState(Proto *p, FuncState *e)
|
||||
: proto(p), freereg(p->numParams), enclosing(e) {}
|
||||
};
|
||||
|
||||
Compiler(String _fileName, SourceManager &_manager) :
|
||||
fileName(std::move(_fileName)), manager(_manager)
|
||||
{
|
||||
// 初始化顶级作用域
|
||||
current = new FuncState("global", nullptr);
|
||||
allProtos.push_back(current->proto); // 最顶层, bootstrapper
|
||||
}
|
||||
FuncState *current = nullptr;
|
||||
CompiledModule *module = nullptr;
|
||||
SourceManager &manager;
|
||||
Diagnostics &diag;
|
||||
|
||||
~Compiler()
|
||||
{
|
||||
// 内存清理 (如果有异常中断)
|
||||
while (current != nullptr)
|
||||
{
|
||||
FuncState *prev = current->enclosing;
|
||||
delete current;
|
||||
current = prev;
|
||||
}
|
||||
}
|
||||
HashMap<String, int> globalIDMap;
|
||||
int getGlobalID(const String& name);
|
||||
|
||||
Result<Register, Error> allocateReg(const SourceLocation &loc);
|
||||
void freeReg(Register count = 1);
|
||||
int addConstant(Value val);
|
||||
|
||||
void emit(Instruction instr);
|
||||
|
||||
Result<void, Error> compileStmt(Stmt *stmt);
|
||||
Result<Register, Error> compileExpr(Expr *expr, Register target = NO_REG);
|
||||
|
||||
public:
|
||||
Compiler(SourceManager &m, Diagnostics &d) : manager(m), diag(d) {}
|
||||
Result<CompiledModule *, Error> Compile(Program *program);
|
||||
|
||||
private:
|
||||
void PushState(String _name)
|
||||
{
|
||||
current = new FuncState(std::move(_name));
|
||||
}
|
||||
|
||||
Proto *PopState()
|
||||
{
|
||||
FuncState *oldState = current;
|
||||
Proto *finishedProto = oldState->proto;
|
||||
|
||||
current = oldState->enclosing;
|
||||
delete oldState;
|
||||
|
||||
return finishedProto;
|
||||
}
|
||||
|
||||
std::uint8_t AllocReg()
|
||||
{
|
||||
if (current->freeReg >= 255)
|
||||
{
|
||||
assert(false && "Register overflow!");
|
||||
}
|
||||
std::uint8_t reg = current->freeReg++;
|
||||
if (current->freeReg > current->proto->maxStack)
|
||||
{
|
||||
current->proto->maxStack = current->freeReg;
|
||||
}
|
||||
return reg;
|
||||
}
|
||||
|
||||
void FreeReg(std::uint8_t reg)
|
||||
{
|
||||
// 如果这个寄存器被局部变量使用,不释放直接 Return
|
||||
for (const auto &local : current->locals)
|
||||
{
|
||||
if (local.reg == reg)
|
||||
{
|
||||
return; // 拒绝释放,保护局部变量生命周期
|
||||
}
|
||||
}
|
||||
|
||||
// 如果它是纯粹的临时计算结果),释放
|
||||
if (reg == current->freeReg - 1)
|
||||
{
|
||||
current->freeReg--;
|
||||
}
|
||||
}
|
||||
void Emit(Instruction inst)
|
||||
{
|
||||
current->proto->code.push_back(inst);
|
||||
}
|
||||
|
||||
std::uint16_t AddConstant(Value v)
|
||||
{
|
||||
auto it =
|
||||
std::find(current->proto->constants.begin(), current->proto->constants.end(), v);
|
||||
if (it != current->proto->constants.end())
|
||||
{
|
||||
return std::distance(current->proto->constants.begin(), it);
|
||||
}
|
||||
|
||||
current->proto->constants.push_back(v);
|
||||
return static_cast<std::uint16_t>(current->proto->constants.size() - 1);
|
||||
}
|
||||
|
||||
void BeginScope()
|
||||
{
|
||||
current->scopeDepth++;
|
||||
}
|
||||
|
||||
void EndScope()
|
||||
{
|
||||
current->scopeDepth--;
|
||||
while (!current->locals.empty() && current->locals.back().depth > current->scopeDepth)
|
||||
{
|
||||
FreeReg(current->locals.back().reg);
|
||||
current->locals.pop_back();
|
||||
}
|
||||
}
|
||||
|
||||
std::uint8_t DeclareLocal(int localId)
|
||||
{
|
||||
std::uint8_t reg = AllocReg();
|
||||
current->locals.push_back(LocalVar{localId, reg, current->scopeDepth});
|
||||
current->fastRegMap[localId] = reg;
|
||||
return reg;
|
||||
}
|
||||
|
||||
std::uint8_t DeclareLocal(int localId, std::uint8_t reg) // 表示复用哪个寄存器
|
||||
{
|
||||
current->locals.push_back(LocalVar{localId, reg, current->scopeDepth});
|
||||
current->fastRegMap[localId] = reg;
|
||||
return reg;
|
||||
}
|
||||
|
||||
// 发射一条跳转指令,并返回它在代码数组里的绝对索引 (Index)
|
||||
int EmitJump(OpCode op, std::uint8_t aReg = 0)
|
||||
{
|
||||
// 预填 0
|
||||
Emit(Op::iAsBx(op, aReg, 0));
|
||||
return current->proto->code.size() - 1;
|
||||
}
|
||||
|
||||
// 填真实偏移量到那条指令里
|
||||
void PatchJump(int instructionIndex)
|
||||
{
|
||||
// 目标地址就是当前代码数组的末尾
|
||||
int target = current->proto->code.size();
|
||||
|
||||
// 相对偏移量 = 目标地址 - 指令自身所在的地址 - 1
|
||||
// (因为 VM 里的 ip 在取指后会自动 +1,所以偏移要减去 1)
|
||||
int offset = target - instructionIndex - 1;
|
||||
|
||||
if (offset < INT16_MIN || offset > INT16_MAX)
|
||||
{
|
||||
assert(false && "PatchJump: Jump offset exceeds 16-bit signed limit!");
|
||||
}
|
||||
Instruction &inst = current->proto->code[instructionIndex];
|
||||
inst = (inst & 0x0000FFFF)
|
||||
| (static_cast<Instruction>(static_cast<std::uint16_t>(offset)) << 16);
|
||||
}
|
||||
|
||||
SourceLocation makeSourceLocation(AstNode *node)
|
||||
{
|
||||
SourceLocation location = node->location; // copy
|
||||
location.functionName = current->name;
|
||||
location.fileName = fileName;
|
||||
return location;
|
||||
}
|
||||
|
||||
Result<std::uint8_t, Error> compileIdentiExpr(IdentiExpr *);
|
||||
Result<std::uint8_t, Error> compileLiteral(LiteralExpr *);
|
||||
|
||||
Result<std::uint8_t, Error> compileAssignment(
|
||||
InfixExpr *); // 编译赋值,由 CompileInfixExpr调用
|
||||
Result<std::uint8_t, Error> compileInfixExpr(InfixExpr *);
|
||||
|
||||
Result<std::uint8_t, Error> compileLeftValue(
|
||||
Expr *); // 左值对象,可以是变量、结构体字段或模块对象
|
||||
|
||||
Result<std::uint8_t, Error> compileCallExpr(CallExpr *);
|
||||
|
||||
Result<std::uint8_t, Error> compileExpr(Expr *);
|
||||
|
||||
/* Statements */
|
||||
Result<void, Error> compileVarDecl(VarDecl *);
|
||||
Result<void, Error> compileBlockStmt(BlockStmt *);
|
||||
Result<void, Error> compileIfStmt(IfStmt *);
|
||||
Result<void, Error> compileWhileStmt(WhileStmt *);
|
||||
Result<void, Error> compileFnDefStmt(FnDefStmt *);
|
||||
Result<void, Error> compileReturnStmt(ReturnStmt *);
|
||||
|
||||
Result<void, Error> compileStmt(Stmt *);
|
||||
};
|
||||
|
||||
inline void DisassembleInstruction(Instruction inst, std::size_t index)
|
||||
{
|
||||
// 提取OpCode (低 8 位)
|
||||
auto op = static_cast<OpCode>(inst & 0xFF);
|
||||
|
||||
std::string_view opName = magic_enum::enum_name(op);
|
||||
|
||||
// 所有指令至少都有 A 操作数 (8~15 位)
|
||||
std::uint8_t a = (inst >> 8) & 0xFF;
|
||||
|
||||
// 地址补零,指令名左对齐占 10 字符
|
||||
std::cout << std::format("{:04d} {:<10} ", index, opName);
|
||||
|
||||
switch (op)
|
||||
{
|
||||
case OpCode::Exit: {
|
||||
break;
|
||||
}
|
||||
|
||||
case OpCode::Mov: {
|
||||
// iABx 模式
|
||||
std::uint16_t bx = (inst >> 16) & 0xFFFF;
|
||||
std::cout << std::format("R{:<3} R[{}]", a, bx);
|
||||
break;
|
||||
}
|
||||
case OpCode::LoadK: {
|
||||
// iABx 模式:解析 Bx (16~31 位)
|
||||
std::uint16_t bx = (inst >> 16) & 0xFFFF;
|
||||
std::cout << std::format("R{:<3} K[{}]", a, bx);
|
||||
break;
|
||||
}
|
||||
|
||||
case OpCode::Jmp:
|
||||
case OpCode::JmpIfFalse: {
|
||||
// iAsBx
|
||||
std::int16_t sbx = static_cast<std::uint16_t>(inst >> 16);
|
||||
std::cout << std::format("R{:<3} [{}]", a, sbx);
|
||||
break;
|
||||
}
|
||||
|
||||
case OpCode::FastCall:
|
||||
{
|
||||
std::uint8_t b = (inst >> 16) & 0xFF;
|
||||
std::cout << std::format("Proto{:<3} R[{}]+", a, b);
|
||||
break;
|
||||
}
|
||||
case OpCode::Call:
|
||||
{
|
||||
std::uint8_t b = (inst >> 16) & 0xFF;
|
||||
std::cout << std::format("R{:<3} R[{}]+", a, b);
|
||||
break;
|
||||
}
|
||||
|
||||
case OpCode::LoadTrue:
|
||||
case OpCode::LoadFalse:
|
||||
case OpCode::LoadNull:
|
||||
case OpCode::Add:
|
||||
case OpCode::Sub:
|
||||
case OpCode::Mul:
|
||||
case OpCode::Div:
|
||||
case OpCode::Mod:
|
||||
|
||||
case OpCode::IntFastAdd:
|
||||
case OpCode::IntFastSub:
|
||||
case OpCode::IntFastMul:
|
||||
case OpCode::IntFastDiv:
|
||||
{
|
||||
// iABC 模式:解析 B (16~23 位) 和 C (24~31 位)
|
||||
std::uint8_t b = (inst >> 16) & 0xFF;
|
||||
std::uint8_t c = (inst >> 24) & 0xFF;
|
||||
std::cout << std::format("R{:<3} R{:<3} R{}", a, b, c);
|
||||
break;
|
||||
}
|
||||
case OpCode::Return: {
|
||||
// iA 模式:只用到了 A
|
||||
std::cout << std::format("R{}", a);
|
||||
break;
|
||||
}
|
||||
|
||||
case OpCode::LoadFn: {
|
||||
std::uint16_t bx = (inst >> 16) & 0xFFFF;
|
||||
std::cout << std::format("R{:<3} Proto[{}]", a, bx);
|
||||
break;
|
||||
}
|
||||
|
||||
// default: {
|
||||
// std::cout << "?";
|
||||
// break;
|
||||
// }
|
||||
}
|
||||
std::cout << '\n';
|
||||
}
|
||||
|
||||
inline void DumpCode(const DynArray<Instruction> &code)
|
||||
{
|
||||
std::cout << " Bytecode\n";
|
||||
for (std::size_t i = 0; i < code.size(); ++i)
|
||||
{
|
||||
DisassembleInstruction(code[i], i);
|
||||
}
|
||||
}
|
||||
}; // namespace Fig
|
||||
}
|
||||
|
||||
@@ -1,370 +1,313 @@
|
||||
/*!
|
||||
@file src/Compiler/ExprCompiler.cpp
|
||||
@brief 编译器实现(表达式部分)
|
||||
@author PuqiAR (im@puqiar.top)
|
||||
@date 2026-02-19
|
||||
@brief 表达式编译器实现:引入水位线(Watermark)与零拷贝复用机制
|
||||
*/
|
||||
|
||||
#include <Ast/Expr/CallExpr.hpp>
|
||||
#include <Ast/Expr/IdentiExpr.hpp>
|
||||
#include <Ast/Expr/InfixExpr.hpp>
|
||||
#include <Ast/Expr/LiteralExpr.hpp>
|
||||
#include <Compiler/Compiler.hpp>
|
||||
#include <charconv>
|
||||
#include <limits>
|
||||
#include <system_error>
|
||||
|
||||
|
||||
namespace Fig
|
||||
{
|
||||
Result<std::uint8_t, Error> Compiler::compileIdentiExpr(IdentiExpr *ie)
|
||||
static Result<Value, Error> parsePhysicalNumber(const String &raw, const SourceLocation &loc)
|
||||
{
|
||||
// TODO: 处理全局变量和闭包 Upvalue
|
||||
std::uint8_t targetReg = current->fastRegMap[ie->localId];
|
||||
char buffer[128];
|
||||
int j = 0;
|
||||
bool isFloat = false;
|
||||
for (size_t i = 0; i < raw.length() && j < 127; ++i)
|
||||
{
|
||||
char32_t c = raw[i];
|
||||
if (c == '_')
|
||||
continue;
|
||||
if (c == '.' || c == 'e' || c == 'E')
|
||||
isFloat = true;
|
||||
buffer[j++] = (char) c;
|
||||
}
|
||||
buffer[j] = '\0';
|
||||
|
||||
if (targetReg == UINT8_MAX)
|
||||
if (isFloat)
|
||||
{
|
||||
assert(false && "Compiler Bug: Encountered unmapped localId in fastRegMap!");
|
||||
double dVal;
|
||||
auto [ptr, ec] = std::from_chars(buffer, buffer + j, dVal);
|
||||
if (ec != std::errc())
|
||||
return std::unexpected(Error(ErrorType::SyntaxError, "float overflow", "", loc));
|
||||
return Value::FromDouble(dVal);
|
||||
}
|
||||
return targetReg;
|
||||
}
|
||||
Result<std::uint8_t, Error> Compiler::compileLiteral(
|
||||
LiteralExpr *lit) // 编译字面量, 负责转换 token -> Value
|
||||
{
|
||||
const Token &token = lit->token;
|
||||
String lexeme = manager.GetSub(token.index, token.length);
|
||||
|
||||
if (!token.isLiteral())
|
||||
else
|
||||
{
|
||||
assert(false && "CompileLiteral: token is not literal");
|
||||
}
|
||||
|
||||
Value v;
|
||||
|
||||
if (token.type == TokenType::LiteralNull)
|
||||
{
|
||||
v = Value::GetNullInstance();
|
||||
}
|
||||
else if (token.type == TokenType::LiteralTrue)
|
||||
{
|
||||
v = Value::GetTrueInstance();
|
||||
}
|
||||
else if (token.type == TokenType::LiteralFalse)
|
||||
{
|
||||
v = Value::GetFalseInstance();
|
||||
}
|
||||
else if (token.type == TokenType::LiteralNumber)
|
||||
{
|
||||
// TODO: 更换为无异常手写数字解析版本 (charconv也可)
|
||||
if (lexeme.contains(U'.') || lexeme.contains(U'e'))
|
||||
int base = 10;
|
||||
const char *start = buffer;
|
||||
if (j > 2 && buffer[0] == '0')
|
||||
{
|
||||
// 非整数
|
||||
double d = std::stod(lexeme.toStdString());
|
||||
v = Value::FromDouble(d);
|
||||
if (buffer[1] == 'x' || buffer[1] == 'X')
|
||||
{
|
||||
base = 16;
|
||||
start += 2;
|
||||
}
|
||||
else if (buffer[1] == 'b' || buffer[1] == 'B')
|
||||
{
|
||||
base = 2;
|
||||
start += 2;
|
||||
}
|
||||
}
|
||||
int64_t iVal;
|
||||
auto [ptr, ec] = std::from_chars(start, buffer + j, iVal, base);
|
||||
if (ec != std::errc())
|
||||
return std::unexpected(Error(ErrorType::SyntaxError, "integer overflow", "", loc));
|
||||
|
||||
if (iVal >= std::numeric_limits<int32_t>::min()
|
||||
&& iVal <= std::numeric_limits<int32_t>::max())
|
||||
{
|
||||
return Value::FromInt(static_cast<int32_t>(iVal));
|
||||
}
|
||||
else
|
||||
{
|
||||
std::int32_t i = std::stoi(lexeme.toStdString());
|
||||
v = Value::FromInt(i);
|
||||
return Value::FromDouble(static_cast<double>(iVal));
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
assert("false" && "CompileLiteral: unsupport literal");
|
||||
}
|
||||
|
||||
std::uint8_t targetReg = AllocReg();
|
||||
|
||||
if (current->proto->constants.size() >= MAX_CONSTANTS)
|
||||
{
|
||||
return std::unexpected(Error(ErrorType::TooManyConstants,
|
||||
std::format("constant limit exceeded: {}", MAX_CONSTANTS),
|
||||
"How did you write such code? try global variable or split file",
|
||||
makeSourceLocation(lit)));
|
||||
}
|
||||
|
||||
std::uint16_t kIndex = AddConstant(v);
|
||||
|
||||
Emit(Op::iABx(OpCode::LoadK, targetReg, kIndex));
|
||||
return targetReg;
|
||||
}
|
||||
Result<std::uint8_t, Error> Compiler::compileAssignment(
|
||||
InfixExpr *infix) // 编译赋值,由 CompileInfixExpr调用
|
||||
|
||||
Result<Register, Error> Compiler::compileExpr(Expr *expr, Register target)
|
||||
{
|
||||
// op必须为 =
|
||||
const auto &_lhsReg = compileLeftValue(infix->left); // 必须为左值对象
|
||||
if (!_lhsReg)
|
||||
if (expr == nullptr)
|
||||
{
|
||||
return _lhsReg;
|
||||
}
|
||||
std::uint8_t lhsReg = *_lhsReg;
|
||||
|
||||
const auto &_rhsReg = compileExpr(infix->right);
|
||||
std::uint8_t rhsReg = *_rhsReg;
|
||||
|
||||
FreeReg(rhsReg);
|
||||
switch (infix->op)
|
||||
{
|
||||
case BinaryOperator::Assign: {
|
||||
Emit(Op::iABx(OpCode::Mov, lhsReg, rhsReg)); // lhsReg = rhsReg
|
||||
break;
|
||||
}
|
||||
case BinaryOperator::AddAssign: {
|
||||
Emit(Op::iABC(OpCode::Add, lhsReg, lhsReg, rhsReg)); // lhsReg = lhsReg + rhsReg
|
||||
break;
|
||||
}
|
||||
case BinaryOperator::SubAssign: {
|
||||
Emit(Op::iABC(OpCode::Sub, lhsReg, lhsReg, rhsReg)); // lhsReg = lhsReg - rhsReg
|
||||
break;
|
||||
}
|
||||
case BinaryOperator::MultiplyAssign: {
|
||||
Emit(Op::iABC(OpCode::Mul, lhsReg, lhsReg, rhsReg)); // lhsReg = lhsReg * rhsReg
|
||||
break;
|
||||
}
|
||||
case BinaryOperator::DivideAssign: {
|
||||
Emit(Op::iABC(OpCode::Div, lhsReg, lhsReg, rhsReg)); // lhsReg = lhsReg / rhsReg
|
||||
break;
|
||||
}
|
||||
case BinaryOperator::ModuloAssign: {
|
||||
Emit(Op::iABC(OpCode::Mod, lhsReg, lhsReg, rhsReg)); // lhsReg = lhsReg % rhsReg
|
||||
break;
|
||||
}
|
||||
case BinaryOperator::BitXorAssign: {
|
||||
Emit(Op::iABC(OpCode::BitXor, lhsReg, lhsReg, rhsReg)); // lhsReg = lhsReg ^ rhsReg
|
||||
break;
|
||||
}
|
||||
default: {
|
||||
assert(false && "CompileAssignment: op unsupported yet");
|
||||
}
|
||||
}
|
||||
return lhsReg; // 返回赋值的结果,支持连续赋值
|
||||
}
|
||||
Result<std::uint8_t, Error> Compiler::compileInfixExpr(
|
||||
InfixExpr *infix) // 编译中缀表达式,返回一个存放结果的寄存器 ID
|
||||
{
|
||||
if (infix->op >= BinaryOperator::Assign && infix->op <= BinaryOperator::BitXorAssign)
|
||||
{
|
||||
return compileAssignment(infix);
|
||||
return std::unexpected(
|
||||
Error(ErrorType::InternalError, "null expr in compiler", "", {}));
|
||||
}
|
||||
|
||||
Expr *left = infix->left;
|
||||
Expr *right = infix->right;
|
||||
|
||||
const auto &_lhsReg = compileExpr(left);
|
||||
if (!_lhsReg)
|
||||
{
|
||||
return _lhsReg;
|
||||
}
|
||||
std::uint8_t lhsReg = *_lhsReg;
|
||||
const auto &_rhsReg = compileExpr(right);
|
||||
if (!_rhsReg)
|
||||
{
|
||||
return _rhsReg;
|
||||
}
|
||||
std::uint8_t rhsReg = *_rhsReg;
|
||||
|
||||
FreeReg(rhsReg);
|
||||
FreeReg(lhsReg);
|
||||
|
||||
std::uint8_t resultReg = AllocReg();
|
||||
|
||||
switch (infix->op)
|
||||
{
|
||||
case BinaryOperator::Add: {
|
||||
if (left->resolvedType == right->resolvedType && left->resolvedType->isInt())
|
||||
{
|
||||
// Int + Int
|
||||
Emit(Op::iABC(OpCode::IntFastAdd, resultReg, lhsReg, rhsReg));
|
||||
}
|
||||
else
|
||||
{
|
||||
Emit(Op::iABC(OpCode::Add, resultReg, lhsReg, rhsReg));
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case BinaryOperator::Subtract: {
|
||||
if (left->resolvedType == right->resolvedType && left->resolvedType->isInt())
|
||||
{
|
||||
// Int - Int
|
||||
Emit(Op::iABC(OpCode::IntFastSub, resultReg, lhsReg, rhsReg));
|
||||
}
|
||||
else
|
||||
{
|
||||
Emit(Op::iABC(OpCode::Sub, resultReg, lhsReg, rhsReg));
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case BinaryOperator::Multiply: {
|
||||
if (left->resolvedType == right->resolvedType && left->resolvedType->isInt())
|
||||
{
|
||||
// Int * Int
|
||||
Emit(Op::iABC(OpCode::IntFastMul, resultReg, lhsReg, rhsReg));
|
||||
}
|
||||
else
|
||||
{
|
||||
Emit(Op::iABC(OpCode::Mul, resultReg, lhsReg, rhsReg));
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case BinaryOperator::Divide: {
|
||||
if (left->resolvedType == right->resolvedType && left->resolvedType->isInt())
|
||||
{
|
||||
// Int / Int
|
||||
Emit(Op::iABC(OpCode::IntFastDiv, resultReg, lhsReg, rhsReg));
|
||||
}
|
||||
else
|
||||
{
|
||||
Emit(Op::iABC(OpCode::Div, resultReg, lhsReg, rhsReg));
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case BinaryOperator::Modulo: {
|
||||
Emit(Op::iABC(OpCode::Mod, resultReg, lhsReg, rhsReg));
|
||||
break;
|
||||
}
|
||||
|
||||
case BinaryOperator::Greater: {
|
||||
Emit(Op::iABC(OpCode::Greater, resultReg, lhsReg, rhsReg));
|
||||
break;
|
||||
}
|
||||
|
||||
case BinaryOperator::GreaterEqual: {
|
||||
Emit(Op::iABC(OpCode::GreaterEqual, resultReg, lhsReg, rhsReg));
|
||||
break;
|
||||
}
|
||||
|
||||
case BinaryOperator::Less: {
|
||||
Emit(Op::iABC(OpCode::Less, resultReg, lhsReg, rhsReg));
|
||||
break;
|
||||
}
|
||||
|
||||
case BinaryOperator::LessEqual: {
|
||||
Emit(Op::iABC(OpCode::LessEqual, resultReg, lhsReg, rhsReg));
|
||||
break;
|
||||
}
|
||||
|
||||
case BinaryOperator::Equal: {
|
||||
Emit(Op::iABC(OpCode::Equal, resultReg, lhsReg, rhsReg));
|
||||
break;
|
||||
}
|
||||
|
||||
default: assert(false && "CompileInfixExpr: op unsupported yet");
|
||||
}
|
||||
return resultReg;
|
||||
}
|
||||
Result<std::uint8_t, Error> Compiler::compileLeftValue(
|
||||
Expr *expr) // 左值对象,可以是变量、结构体字段或模块对象
|
||||
{
|
||||
switch (expr->type)
|
||||
{
|
||||
case AstType::IdentiExpr:
|
||||
return compileIdentiExpr(static_cast<IdentiExpr *>(expr));
|
||||
// TODO: 数组切片(a[0])或对象属性(a.b)
|
||||
case AstType::LiteralExpr: {
|
||||
auto *l = static_cast<LiteralExpr *>(expr);
|
||||
Register r = (target == NO_REG) ? *allocateReg(l->location) : target;
|
||||
|
||||
default:
|
||||
// Analyzer 有漏洞(编译器内部
|
||||
// 直接崩溃
|
||||
assert(false && "Compiler Bug: Invalid L-value bypassed Analyzer!");
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
Result<std::uint8_t, Error> Compiler::compileCallExpr(CallExpr *expr)
|
||||
{
|
||||
bool isStatic = false; // 是否为单纯的 fn(...) 静态函数调用
|
||||
int protoIdx = -1;
|
||||
|
||||
if (expr->callee->type == AstType::IdentiExpr)
|
||||
{
|
||||
IdentiExpr *id = static_cast<IdentiExpr *>(expr->callee);
|
||||
// 如果是函数名且深度为 0 (全局/扁平函数池)
|
||||
if (id->resolvedType->tag == TypeTag::Function && id->resolvedDepth == 0)
|
||||
{
|
||||
if (globalFuncMap.contains(id->localId))
|
||||
const Token &tok = l->literal;
|
||||
if (tok.type == TokenType::LiteralNumber)
|
||||
{
|
||||
isStatic = true;
|
||||
protoIdx = globalFuncMap[id->localId];
|
||||
auto vRes =
|
||||
parsePhysicalNumber(manager.GetSub(tok.index, tok.length), l->location);
|
||||
if (!vRes)
|
||||
return std::unexpected(vRes.error());
|
||||
emit(Op::iABx(OpCode::LoadK, r, static_cast<uint16_t>(addConstant(*vRes))));
|
||||
}
|
||||
else if (tok.type == TokenType::LiteralString)
|
||||
{
|
||||
int kIdx = addConstant(Value::GetNullInstance()); // TODO: String 支持
|
||||
emit(Op::iABx(OpCode::LoadK, r, static_cast<uint16_t>(kIdx)));
|
||||
}
|
||||
else if (tok.type == TokenType::LiteralNull)
|
||||
{
|
||||
emit(Op::iABC(OpCode::LoadNull, r, 0, 0));
|
||||
}
|
||||
else if (tok.type == TokenType::LiteralTrue)
|
||||
{
|
||||
emit(Op::iABC(OpCode::LoadTrue, r, 0, 0));
|
||||
}
|
||||
else if (tok.type == TokenType::LiteralFalse)
|
||||
{
|
||||
emit(Op::iABC(OpCode::LoadFalse, r, 0, 0));
|
||||
}
|
||||
return r;
|
||||
}
|
||||
}
|
||||
|
||||
std::uint8_t baseReg = AllocReg();
|
||||
|
||||
if (!isStatic)
|
||||
{
|
||||
auto calleeRes = compileExpr(expr->callee);
|
||||
if (!calleeRes)
|
||||
{
|
||||
return calleeRes;
|
||||
}
|
||||
|
||||
if (*calleeRes != baseReg)
|
||||
{
|
||||
Emit(Op::iABx(OpCode::Mov, baseReg, *calleeRes));
|
||||
}
|
||||
}
|
||||
|
||||
for (size_t i = 0; i < expr->args.size(); ++i)
|
||||
{
|
||||
std::uint8_t argTarget = AllocReg();
|
||||
auto argRes = compileExpr(expr->args.args[i]);
|
||||
if (!argRes)
|
||||
{
|
||||
return argRes;
|
||||
}
|
||||
|
||||
if (*argRes != argTarget)
|
||||
{
|
||||
Emit(Op::iABx(OpCode::Mov, argTarget, *argRes));
|
||||
}
|
||||
}
|
||||
|
||||
std::uint8_t expectRet = 1;
|
||||
|
||||
if (isStatic)
|
||||
{
|
||||
Emit(Op::iABC(OpCode::FastCall, (std::uint8_t) protoIdx, baseReg, expectRet));
|
||||
}
|
||||
else
|
||||
{
|
||||
Emit(Op::iABC(OpCode::Call, baseReg, baseReg, expectRet));
|
||||
}
|
||||
|
||||
for (size_t i = 0; i < expr->args.args.size(); ++i)
|
||||
{
|
||||
current->freeReg--;
|
||||
}
|
||||
return baseReg; // 返回值起点
|
||||
}
|
||||
|
||||
Result<std::uint8_t, Error> Compiler::compileExpr(
|
||||
Expr *expr) // 编译表达式,必定返回一个存放结果的寄存器 ID
|
||||
{
|
||||
switch (expr->type)
|
||||
{
|
||||
case AstType::Stmt:
|
||||
case AstType::Expr:
|
||||
case AstType::AstNode: assert(false && "CompileExpr: bad node type"); break;
|
||||
|
||||
case AstType::IdentiExpr: {
|
||||
return compileLeftValue(expr); // 左值直接转换成右值
|
||||
}
|
||||
auto *i = static_cast<IdentiExpr *>(expr);
|
||||
Symbol *sym = i->resolvedSymbol;
|
||||
|
||||
case AstType::LiteralExpr: {
|
||||
LiteralExpr *lit = static_cast<LiteralExpr *>(expr);
|
||||
|
||||
auto result = compileLiteral(lit);
|
||||
if (!result)
|
||||
if (sym->location == SymbolLocation::Local)
|
||||
{
|
||||
return std::unexpected(result.error());
|
||||
}
|
||||
std::uint8_t targetReg = *result;
|
||||
return targetReg;
|
||||
}
|
||||
// 零拷贝直读:如果是临时求值,直接返回变量的物理槽位,禁止产生副本
|
||||
if (target == NO_REG)
|
||||
return static_cast<Register>(sym->index);
|
||||
|
||||
case AstType::InfixExpr: {
|
||||
return compileInfixExpr(static_cast<InfixExpr *>(expr));
|
||||
// 仅在被强制指定目标(如参数装填)时发射搬运指令
|
||||
if (target != sym->index)
|
||||
{
|
||||
emit(Op::iABx(OpCode::Mov, target, static_cast<uint16_t>(sym->index)));
|
||||
}
|
||||
return target;
|
||||
}
|
||||
|
||||
Register r = (target == NO_REG) ? *allocateReg(i->location) : target;
|
||||
if (sym->location == SymbolLocation::Upvalue)
|
||||
{
|
||||
emit(Op::iABC(OpCode::GetUpval, r, static_cast<uint8_t>(sym->index), 0));
|
||||
}
|
||||
else if (sym->location == SymbolLocation::Global)
|
||||
{
|
||||
int gId = getGlobalID(i->name);
|
||||
emit(Op::iABx(OpCode::GetGlobal, r, static_cast<uint16_t>(gId)));
|
||||
}
|
||||
return r;
|
||||
}
|
||||
|
||||
case AstType::CallExpr: {
|
||||
return compileCallExpr(static_cast<CallExpr *>(expr));
|
||||
auto *c = static_cast<CallExpr *>(expr);
|
||||
Register mark = current->freereg; // 记录调用前的栈顶水位
|
||||
Register baseReg = current->freereg; // 锁定滑窗基址
|
||||
|
||||
// 连续装填参数,占据 baseReg, baseReg+1, baseReg+2...
|
||||
for (auto *arg : c->args.args)
|
||||
{
|
||||
auto allocRes = allocateReg(arg->location);
|
||||
if (!allocRes)
|
||||
{
|
||||
return allocRes;
|
||||
}
|
||||
|
||||
Register argTarget = *allocRes;
|
||||
auto res = compileExpr(arg, argTarget);
|
||||
if (!res)
|
||||
return std::unexpected(res.error());
|
||||
}
|
||||
|
||||
if (c->callee->type == AstType::IdentiExpr)
|
||||
{
|
||||
// 静态去虚化:编译期直接跳板
|
||||
auto *id = static_cast<IdentiExpr *>(c->callee);
|
||||
int protoIdx = id->resolvedSymbol->index;
|
||||
emit(Op::iABC(OpCode::FastCall,
|
||||
static_cast<uint8_t>(protoIdx),
|
||||
baseReg,
|
||||
static_cast<uint8_t>(c->args.args.size())));
|
||||
}
|
||||
else
|
||||
{
|
||||
// 动态闭包调用
|
||||
auto r_fn = compileExpr(c->callee);
|
||||
if (!r_fn)
|
||||
return std::unexpected(r_fn.error());
|
||||
emit(Op::iABC(
|
||||
OpCode::Call, *r_fn, baseReg, static_cast<uint8_t>(c->args.args.size())));
|
||||
}
|
||||
|
||||
// 回滚水位线:彻底释放传参时的临时占用
|
||||
current->freereg = mark;
|
||||
|
||||
// 目标对齐:若 target 未指定,allocateReg 将自然复用 baseReg,实现零开销回写
|
||||
|
||||
Register r_dest;
|
||||
if (target == NO_REG)
|
||||
{
|
||||
auto res = allocateReg(c->location);
|
||||
if (!res)
|
||||
return std::unexpected(res.error());
|
||||
r_dest = *res;
|
||||
}
|
||||
else
|
||||
{
|
||||
r_dest = target;
|
||||
}
|
||||
|
||||
if (r_dest != baseReg)
|
||||
{
|
||||
emit(Op::iABx(OpCode::Mov, r_dest, baseReg));
|
||||
}
|
||||
|
||||
return r_dest;
|
||||
}
|
||||
|
||||
case AstType::InfixExpr: {
|
||||
auto *in = static_cast<InfixExpr *>(expr);
|
||||
if (in->op == BinaryOperator::Assign)
|
||||
{
|
||||
auto r_val = compileExpr(in->right, target);
|
||||
if (!r_val)
|
||||
return std::unexpected(r_val.error());
|
||||
|
||||
if (in->left->type == AstType::IdentiExpr)
|
||||
{
|
||||
auto *lid = static_cast<IdentiExpr *>(in->left);
|
||||
Symbol *sym = lid->resolvedSymbol;
|
||||
if (sym->location == SymbolLocation::Local)
|
||||
{
|
||||
emit(Op::iABx(OpCode::Mov, static_cast<Register>(sym->index), *r_val));
|
||||
}
|
||||
else if (sym->location == SymbolLocation::Upvalue)
|
||||
{
|
||||
emit(Op::iABC(
|
||||
OpCode::SetUpval, *r_val, static_cast<Register>(sym->index), 0));
|
||||
}
|
||||
else
|
||||
{
|
||||
emit(Op::iABx(OpCode::SetGlobal,
|
||||
*r_val,
|
||||
static_cast<uint16_t>(getGlobalID(lid->name))));
|
||||
}
|
||||
}
|
||||
return r_val;
|
||||
}
|
||||
|
||||
Register mark = current->freereg; // 记录水位线
|
||||
|
||||
auto r_l = compileExpr(in->left);
|
||||
if (!r_l)
|
||||
return std::unexpected(r_l.error());
|
||||
auto r_r = compileExpr(in->right);
|
||||
if (!r_r)
|
||||
return std::unexpected(r_r.error());
|
||||
|
||||
bool isInt = in->left->resolvedType.is(TypeTag::Int)
|
||||
&& in->right->resolvedType.is(TypeTag::Int);
|
||||
OpCode op;
|
||||
switch (in->op)
|
||||
{
|
||||
case BinaryOperator::Add: op = isInt ? OpCode::IntFastAdd : OpCode::Add; break;
|
||||
case BinaryOperator::Subtract:
|
||||
op = isInt ? OpCode::IntFastSub : OpCode::Sub;
|
||||
break;
|
||||
case BinaryOperator::Multiply:
|
||||
op = isInt ? OpCode::IntFastMul : OpCode::Mul;
|
||||
break;
|
||||
case BinaryOperator::Divide:
|
||||
op = isInt ? OpCode::IntFastDiv : OpCode::Div;
|
||||
break;
|
||||
case BinaryOperator::Modulo: op = OpCode::Mod; break;
|
||||
case BinaryOperator::BitXor: op = OpCode::BitXor; break;
|
||||
case BinaryOperator::Equal: op = OpCode::Equal; break;
|
||||
case BinaryOperator::NotEqual: op = OpCode::NotEqual; break;
|
||||
case BinaryOperator::Greater: op = OpCode::Greater; break;
|
||||
case BinaryOperator::Less: op = OpCode::Less; break;
|
||||
case BinaryOperator::GreaterEqual: op = OpCode::GreaterEqual; break;
|
||||
case BinaryOperator::LessEqual: op = OpCode::LessEqual; break;
|
||||
default:
|
||||
return std::unexpected(Error(ErrorType::InternalError,
|
||||
"unsupported binary operator",
|
||||
"",
|
||||
in->location));
|
||||
}
|
||||
|
||||
// 释放左右操作数产生的临时寄存器
|
||||
current->freereg = mark;
|
||||
|
||||
// 复用已释放的物理槽位存放计算结果
|
||||
Register r_d;
|
||||
if (target == NO_REG)
|
||||
{
|
||||
auto res = allocateReg(in->location);
|
||||
if (!res)
|
||||
return std::unexpected(res.error());
|
||||
r_d = *res;
|
||||
}
|
||||
else
|
||||
{
|
||||
r_d = target;
|
||||
}
|
||||
|
||||
emit(Op::iABC(op, r_d, *r_l, *r_r));
|
||||
|
||||
return r_d;
|
||||
}
|
||||
|
||||
default: break;
|
||||
}
|
||||
return std::unexpected(
|
||||
Error(ErrorType::InternalError, "unsupported expr", "", expr->location));
|
||||
}
|
||||
} // namespace Fig
|
||||
@@ -1,282 +1,215 @@
|
||||
/*!
|
||||
@file src/Compiler/StmtCompiler.cpp
|
||||
@brief 编译器实现(语句部分)
|
||||
@author PuqiAR (im@puqiar.top)
|
||||
@date 2026-02-19
|
||||
@brief 语句编译器实现:实装水位线机制,彻底消灭硬编码寄存器释放
|
||||
*/
|
||||
|
||||
#include <Ast/Stmt/FnDefStmt.hpp>
|
||||
#include <Ast/Stmt/IfStmt.hpp>
|
||||
#include <Ast/Stmt/VarDecl.hpp>
|
||||
#include <Ast/Stmt/WhileStmt.hpp>
|
||||
#include <Compiler/Compiler.hpp>
|
||||
|
||||
|
||||
namespace Fig
|
||||
{
|
||||
Result<void, Error> Compiler::compileVarDecl(VarDecl *varDecl)
|
||||
Result<void, Error> Compiler::compileStmt(Stmt *stmt)
|
||||
{
|
||||
if (current->freeReg > MAX_LOCALS)
|
||||
if (stmt == nullptr)
|
||||
{
|
||||
return std::unexpected(Error(ErrorType::TooManyLocals,
|
||||
std::format("local limit exceeded: {}", MAX_LOCALS),
|
||||
"try split function or use arrays/structs...",
|
||||
makeSourceLocation(varDecl)));
|
||||
return {};
|
||||
}
|
||||
|
||||
std::uint8_t varReg;
|
||||
if (varDecl->initExpr)
|
||||
{
|
||||
auto result = compileExpr(varDecl->initExpr);
|
||||
if (!result)
|
||||
{
|
||||
return std::unexpected(result.error());
|
||||
}
|
||||
std::uint8_t resultReg = *result;
|
||||
varReg = DeclareLocal(varDecl->localId, resultReg); // 复用临时计算结果寄存器
|
||||
}
|
||||
else
|
||||
{
|
||||
// TODO: 未初始化提供初始值
|
||||
varReg = DeclareLocal(varDecl->localId);
|
||||
}
|
||||
|
||||
return Result<void, Error>();
|
||||
}
|
||||
|
||||
Result<void, Error> Compiler::compileBlockStmt(BlockStmt *blockStmt)
|
||||
{
|
||||
for (Stmt *stmt : blockStmt->nodes)
|
||||
{
|
||||
auto result = compileStmt(stmt);
|
||||
if (!result)
|
||||
{
|
||||
return result;
|
||||
}
|
||||
}
|
||||
return {};
|
||||
}
|
||||
|
||||
Result<void, Error> Compiler::compileIfStmt(IfStmt *stmt)
|
||||
{
|
||||
/*
|
||||
if cond1
|
||||
{
|
||||
}
|
||||
else if cond2 #1
|
||||
{
|
||||
}
|
||||
else if cond3 #2
|
||||
{
|
||||
}
|
||||
else #3
|
||||
{
|
||||
}
|
||||
quit #4
|
||||
|
||||
Bytecode:
|
||||
JmpIfFalse cond1 #1
|
||||
; consequent内容
|
||||
; ...
|
||||
; if条件为true, 跳过所有 else/elseif
|
||||
|
||||
Jmp #4
|
||||
|
||||
; #1
|
||||
JmpIfFalse cond2 #2
|
||||
; consequent
|
||||
|
||||
Jmp #4
|
||||
|
||||
; #2
|
||||
JmpIfFalse cond3 #3
|
||||
; consequent
|
||||
|
||||
Jmp #4
|
||||
|
||||
; #3
|
||||
; 没有一次执行分支
|
||||
; else部分
|
||||
; ...
|
||||
|
||||
#4
|
||||
|
||||
*/
|
||||
std::vector<int> exitJumps; // 所有分支都要跳到最后,收集所有jump最后回填
|
||||
const auto &condResult = compileExpr(stmt->cond);
|
||||
if (!condResult)
|
||||
{
|
||||
return std::unexpected(condResult.error());
|
||||
}
|
||||
std::uint8_t condReg = *condResult;
|
||||
int jumpToNext = EmitJump(OpCode::JmpIfFalse, condReg);
|
||||
FreeReg(condReg);
|
||||
|
||||
const auto &blockResult = compileStmt(stmt->consequent);
|
||||
if (!blockResult)
|
||||
{
|
||||
return blockResult;
|
||||
}
|
||||
|
||||
exitJumps.push_back(EmitJump(OpCode::Jmp)); // 执行完if直接跳到出口
|
||||
PatchJump(jumpToNext); // 回填,跳到下一个else/elseif
|
||||
|
||||
for (auto *elif : stmt->elifs)
|
||||
{
|
||||
const auto &elifCondResult = compileExpr(elif->cond);
|
||||
if (!elifCondResult)
|
||||
return std::unexpected(elifCondResult.error());
|
||||
std::uint8_t elifCondReg = *elifCondResult;
|
||||
|
||||
jumpToNext = EmitJump(OpCode::JmpIfFalse, elifCondReg);
|
||||
FreeReg(elifCondReg);
|
||||
|
||||
const auto &blockResult = compileStmt(elif->consequent);
|
||||
if (!blockResult)
|
||||
{
|
||||
return blockResult;
|
||||
}
|
||||
exitJumps.push_back(EmitJump(OpCode::Jmp)); // 执行完else if,跳到出口
|
||||
PatchJump(jumpToNext); // 跳到下一个分支
|
||||
}
|
||||
|
||||
if (stmt->alternate)
|
||||
{
|
||||
auto result = compileStmt(stmt->alternate);
|
||||
if (!result)
|
||||
{
|
||||
return result;
|
||||
}
|
||||
}
|
||||
for (int exitIndex : exitJumps)
|
||||
{
|
||||
PatchJump(exitIndex); // 回填所有跳转出口的指令
|
||||
}
|
||||
return {};
|
||||
}
|
||||
|
||||
Result<void, Error> Compiler::compileWhileStmt(WhileStmt *stmt)
|
||||
{
|
||||
int beginIns = current->proto->code.size() - 1;
|
||||
|
||||
auto condRegResult = compileExpr(stmt->cond);
|
||||
if (!condRegResult)
|
||||
{
|
||||
return std::unexpected(condRegResult.error());
|
||||
}
|
||||
|
||||
std::uint8_t condReg = *condRegResult;
|
||||
|
||||
int exitJump = EmitJump(OpCode::JmpIfFalse, condReg);
|
||||
auto bodyResult = compileBlockStmt(stmt->body);
|
||||
|
||||
if (!bodyResult)
|
||||
{
|
||||
return bodyResult;
|
||||
}
|
||||
Emit(Op::iAsBx(
|
||||
OpCode::Jmp, 0, beginIns - current->proto->code.size())); // 回到开头对condition求值
|
||||
PatchJump(exitJump);
|
||||
return {};
|
||||
}
|
||||
|
||||
Result<void, Error> Compiler::compileFnDefStmt(FnDefStmt *stmt)
|
||||
{
|
||||
std::uint8_t funcReg = DeclareLocal(stmt->localId);
|
||||
|
||||
// 创建子函数编译状态
|
||||
// 传入 current 作为 enclosing,用于后续支持闭包 Upvalue 查找
|
||||
FuncState childState(stmt->name, current);
|
||||
|
||||
allProtos.push_back(childState.proto);
|
||||
std::uint16_t protoIdx = static_cast<std::uint16_t>(allProtos.size() - 1);
|
||||
|
||||
globalFuncMap[stmt->localId] = protoIdx; // 把函数的local id映射到protoIdx
|
||||
|
||||
{
|
||||
FuncStateProtector stateGuard(this, &childState);
|
||||
|
||||
AllocReg();
|
||||
|
||||
// 将参数映射为子函数的初始局部变量 (R0, R1...)
|
||||
for (Param *p : stmt->params)
|
||||
{
|
||||
PosParam *posParam = static_cast<PosParam *>(p); // TODO: 其他参数支持...
|
||||
// 按顺序分配寄存器
|
||||
DeclareLocal(posParam->localId);
|
||||
}
|
||||
|
||||
// B编译函数体语句
|
||||
auto bodyRes = compileStmt(stmt->body);
|
||||
if (!bodyRes)
|
||||
return bodyRes;
|
||||
|
||||
// 隐式返回 null
|
||||
std::uint8_t resReg = AllocReg();
|
||||
Emit(Op::iABC(OpCode::LoadNull, resReg, 0, 0));
|
||||
Emit(Op::iABC(OpCode::Return, resReg, 0, 0));
|
||||
}
|
||||
|
||||
|
||||
// 5. 检查是否是 main 函数
|
||||
if (stmt->name == U"main")
|
||||
{
|
||||
this->mainFuncIndex = protoIdx;
|
||||
}
|
||||
|
||||
Emit(Op::iABx(OpCode::LoadFn, funcReg, protoIdx));
|
||||
|
||||
return {};
|
||||
}
|
||||
|
||||
Result<void, Error> Compiler::compileReturnStmt(ReturnStmt *stmt)
|
||||
{
|
||||
auto res = compileExpr(stmt->value);
|
||||
if (!res)
|
||||
{
|
||||
return std::unexpected(res.error());
|
||||
}
|
||||
|
||||
Emit(Op::iABC(OpCode::Return, *res, 0, 0));
|
||||
return {};
|
||||
}
|
||||
|
||||
Result<void, Error> Compiler::compileStmt(Stmt *stmt) // 编译语句
|
||||
{
|
||||
switch (stmt->type)
|
||||
{
|
||||
case AstType::ExprStmt: {
|
||||
ExprStmt *exprStmt = static_cast<ExprStmt *>(stmt);
|
||||
Expr *expr = exprStmt->expr;
|
||||
auto result = compileExpr(expr);
|
||||
if (!result)
|
||||
case AstType::BlockStmt: {
|
||||
auto *b = static_cast<BlockStmt *>(stmt);
|
||||
for (auto *n : b->nodes)
|
||||
{
|
||||
return std::unexpected(result.error());
|
||||
auto res = compileStmt(n);
|
||||
if (!res)
|
||||
return res;
|
||||
}
|
||||
FreeReg(*result);
|
||||
break;
|
||||
}
|
||||
|
||||
case AstType::VarDecl: {
|
||||
return compileVarDecl(static_cast<VarDecl *>(stmt));
|
||||
}
|
||||
auto *v = static_cast<VarDecl *>(stmt);
|
||||
if (current->enclosing == nullptr) // 处理全局变量
|
||||
{
|
||||
Register mark = current->freereg; // 记录水位线
|
||||
auto regRes = compileExpr(v->initExpr);
|
||||
if (!regRes)
|
||||
return std::unexpected(regRes.error());
|
||||
|
||||
case AstType::BlockStmt: {
|
||||
return compileBlockStmt(static_cast<BlockStmt *>(stmt));
|
||||
}
|
||||
emit(Op::iABx(
|
||||
OpCode::SetGlobal, *regRes, static_cast<uint16_t>(getGlobalID(v->name))));
|
||||
current->freereg = mark; // 释放初始化表达式的临时占用
|
||||
}
|
||||
else
|
||||
{
|
||||
// 抬升水位,锁死局部变量的物理槽位
|
||||
Register targetReg = static_cast<Register>(v->localId);
|
||||
while (current->freereg <= targetReg)
|
||||
{
|
||||
auto allocRes = allocateReg(v->location);
|
||||
if (!allocRes)
|
||||
{
|
||||
return std::unexpected(allocRes.error());
|
||||
}
|
||||
}
|
||||
|
||||
case AstType::IfStmt: {
|
||||
return compileIfStmt(static_cast<IfStmt *>(stmt));
|
||||
}
|
||||
|
||||
case AstType::WhileStmt: {
|
||||
return compileWhileStmt(static_cast<WhileStmt *>(stmt));
|
||||
auto regRes = compileExpr(v->initExpr, targetReg);
|
||||
if (!regRes)
|
||||
return std::unexpected(regRes.error());
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case AstType::FnDefStmt: {
|
||||
return compileFnDefStmt(static_cast<FnDefStmt *>(stmt));
|
||||
}
|
||||
|
||||
case AstType::ReturnStmt: {
|
||||
return compileReturnStmt(static_cast<ReturnStmt *>(stmt));
|
||||
}
|
||||
}
|
||||
auto *f = static_cast<FnDefStmt *>(stmt);
|
||||
|
||||
return Result<void, Error>();
|
||||
// 物理连线:对接 Compile() 第一阶段预分配的 Proto
|
||||
Proto *p = module->protos[f->resolvedSymbol->index];
|
||||
|
||||
FuncState fs(p, current);
|
||||
FuncState *old = current;
|
||||
current = &fs;
|
||||
|
||||
auto res = compileStmt(f->body);
|
||||
if (!res)
|
||||
return res;
|
||||
|
||||
// 窥孔拦截:防死代码污染
|
||||
if (p->code.empty() || static_cast<OpCode>(p->code.back() & 0xFF) != OpCode::Return)
|
||||
{
|
||||
emit(Op::iABC(OpCode::Return, 0, 0, 0));
|
||||
}
|
||||
|
||||
current = old;
|
||||
break;
|
||||
}
|
||||
|
||||
case AstType::IfStmt: {
|
||||
auto *i = static_cast<IfStmt *>(stmt);
|
||||
DynArray<int> exitJumps;
|
||||
|
||||
Register mark = current->freereg; // 记录水位线
|
||||
auto r_cond = compileExpr(i->cond);
|
||||
if (!r_cond)
|
||||
return std::unexpected(r_cond.error());
|
||||
|
||||
int jmpToNext = static_cast<int>(current->proto->code.size());
|
||||
emit(Op::iAsBx(OpCode::JmpIfFalse, *r_cond, 0));
|
||||
current->freereg = mark; // 回收条件表达式临时槽位
|
||||
|
||||
if (auto r = compileStmt(i->consequent); !r)
|
||||
return r;
|
||||
exitJumps.push_back(static_cast<int>(current->proto->code.size()));
|
||||
emit(Op::iAsBx(OpCode::Jmp, 0, 0));
|
||||
|
||||
int targetIdx = static_cast<int>(current->proto->code.size());
|
||||
current->proto->code[jmpToNext] = Op::iAsBx(
|
||||
OpCode::JmpIfFalse, *r_cond, static_cast<int16_t>(targetIdx - jmpToNext - 1));
|
||||
|
||||
for (auto *elif : i->elifs)
|
||||
{
|
||||
Register elifMark = current->freereg;
|
||||
auto ec = compileExpr(elif->cond);
|
||||
if (!ec)
|
||||
return std::unexpected(ec.error());
|
||||
|
||||
int nextElif = static_cast<int>(current->proto->code.size());
|
||||
emit(Op::iAsBx(OpCode::JmpIfFalse, *ec, 0));
|
||||
current->freereg = elifMark; // 回收 elif 临时槽位
|
||||
|
||||
if (auto r = compileStmt(elif->consequent); !r)
|
||||
return r;
|
||||
exitJumps.push_back(static_cast<int>(current->proto->code.size()));
|
||||
emit(Op::iAsBx(OpCode::Jmp, 0, 0));
|
||||
|
||||
int target = static_cast<int>(current->proto->code.size());
|
||||
current->proto->code[nextElif] = Op::iAsBx(
|
||||
OpCode::JmpIfFalse, *ec, static_cast<int16_t>(target - nextElif - 1));
|
||||
}
|
||||
|
||||
if (i->alternate)
|
||||
{
|
||||
if (auto r = compileStmt(i->alternate); !r)
|
||||
return r;
|
||||
}
|
||||
|
||||
int endIdx = static_cast<int>(current->proto->code.size());
|
||||
for (int pos : exitJumps)
|
||||
{
|
||||
current->proto->code[pos] =
|
||||
Op::iAsBx(OpCode::Jmp, 0, static_cast<int16_t>(endIdx - pos - 1));
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case AstType::WhileStmt: {
|
||||
auto *w = static_cast<WhileStmt *>(stmt);
|
||||
int startIdx = static_cast<int>(current->proto->code.size());
|
||||
|
||||
Register mark = current->freereg; // 记录水位线
|
||||
auto r_cond = compileExpr(w->cond);
|
||||
if (!r_cond)
|
||||
return std::unexpected(r_cond.error());
|
||||
|
||||
int exitJmpIdx = static_cast<int>(current->proto->code.size());
|
||||
emit(Op::iAsBx(OpCode::JmpIfFalse, *r_cond, 0));
|
||||
current->freereg = mark; // 回收循环条件临时槽位
|
||||
|
||||
if (auto r = compileStmt(w->body); !r)
|
||||
return r;
|
||||
|
||||
int backJmpIdx = static_cast<int>(current->proto->code.size());
|
||||
emit(Op::iAsBx(OpCode::Jmp, 0, static_cast<int16_t>(startIdx - backJmpIdx - 1)));
|
||||
|
||||
int endIdx = static_cast<int>(current->proto->code.size());
|
||||
current->proto->code[exitJmpIdx] = Op::iAsBx(
|
||||
OpCode::JmpIfFalse, *r_cond, static_cast<int16_t>(endIdx - exitJmpIdx - 1));
|
||||
break;
|
||||
}
|
||||
|
||||
case AstType::ReturnStmt: {
|
||||
auto *rs = static_cast<ReturnStmt *>(stmt);
|
||||
Register mark = current->freereg; // 记录水位线
|
||||
Register retReg;
|
||||
|
||||
if (rs->value)
|
||||
{
|
||||
auto r = compileExpr(rs->value);
|
||||
if (!r)
|
||||
return std::unexpected(r.error());
|
||||
retReg = *r;
|
||||
}
|
||||
else
|
||||
{
|
||||
auto r = allocateReg(rs->location);
|
||||
if (!r)
|
||||
return std::unexpected(r.error());
|
||||
emit(Op::iABC(OpCode::LoadNull, *r, 0, 0));
|
||||
retReg = *r;
|
||||
}
|
||||
|
||||
emit(Op::iABC(OpCode::Return, retReg, 0, 0));
|
||||
current->freereg = mark; // 回收返回值计算的占用
|
||||
break;
|
||||
}
|
||||
|
||||
case AstType::ExprStmt: {
|
||||
Register mark = current->freereg; // 记录水位线
|
||||
auto reg = compileExpr(static_cast<ExprStmt *>(stmt)->expr);
|
||||
if (!reg)
|
||||
return std::unexpected(reg.error());
|
||||
|
||||
current->freereg = mark; // 彻底抛弃孤立表达式的副作用
|
||||
break;
|
||||
}
|
||||
|
||||
default: break;
|
||||
}
|
||||
return {};
|
||||
}
|
||||
}; // namespace Fig
|
||||
} // namespace Fig
|
||||
47
src/Error/Diagnostics.hpp
Normal file
47
src/Error/Diagnostics.hpp
Normal file
@@ -0,0 +1,47 @@
|
||||
/*!
|
||||
@file src/Error/Diagnostics.hpp
|
||||
@brief 诊断信息收集器:用于存储警告与非致命错误
|
||||
@author PuqiAR (im@puqiar.top)
|
||||
@date 2026-03-08
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <Error/Error.hpp>
|
||||
|
||||
namespace Fig
|
||||
{
|
||||
class Diagnostics
|
||||
{
|
||||
private:
|
||||
DynArray<Error> errors;
|
||||
|
||||
public:
|
||||
void Report(Error err)
|
||||
{
|
||||
errors.push_back(std::move(err));
|
||||
}
|
||||
|
||||
// 统一打印所有收集到的信息
|
||||
void EmitAll(const SourceManager &manager)
|
||||
{
|
||||
for (const auto &err : errors)
|
||||
{
|
||||
ReportError(err, manager);
|
||||
}
|
||||
}
|
||||
|
||||
bool HasErrors() const
|
||||
{
|
||||
for (const auto &err : errors)
|
||||
{
|
||||
if (!err.IsWarning()) return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
const DynArray<Error>& GetErrors() const { return errors; }
|
||||
|
||||
void Clear() { errors.clear(); }
|
||||
};
|
||||
} // namespace Fig
|
||||
@@ -59,8 +59,12 @@ namespace Fig
|
||||
|
||||
case TooManyLocals: return "TooManyLocals";
|
||||
case TooManyConstants: return "TooManyConstants";
|
||||
|
||||
case RegisterOverflow: return "RegisterOverflow";
|
||||
case InternalError: return "InternalError";
|
||||
// default: return "Some one forgot to add case to `ErrorTypeToString`";
|
||||
}
|
||||
return "UnknownError";
|
||||
}
|
||||
|
||||
void PrintSystemInfos()
|
||||
@@ -170,4 +174,4 @@ namespace Fig
|
||||
ost << '\n';
|
||||
}
|
||||
}
|
||||
}; // namespace Fig
|
||||
}; // namespace Fig
|
||||
|
||||
@@ -11,7 +11,6 @@
|
||||
#include <Deps/Deps.hpp>
|
||||
#include <SourceManager/SourceManager.hpp>
|
||||
|
||||
|
||||
#include <source_location>
|
||||
|
||||
namespace Fig
|
||||
@@ -51,6 +50,10 @@ namespace Fig
|
||||
// compile errors
|
||||
TooManyLocals,
|
||||
TooManyConstants,
|
||||
|
||||
// --- 新增:编译器内部与VM约束 ---
|
||||
RegisterOverflow,
|
||||
InternalError,
|
||||
};
|
||||
|
||||
const char *ErrorTypeToString(ErrorType type);
|
||||
@@ -77,6 +80,9 @@ namespace Fig
|
||||
location = _location;
|
||||
thrower_loc = _throwerloc;
|
||||
}
|
||||
|
||||
// 新增:适配诊断系统的辅助判定
|
||||
bool IsWarning() const { return static_cast<unsigned int>(type) < 2000; }
|
||||
};
|
||||
|
||||
namespace TerminalColors
|
||||
@@ -174,4 +180,4 @@ namespace Fig
|
||||
}
|
||||
|
||||
void ReportError(const Error &error, const SourceManager &srcManager);
|
||||
}; // namespace Fig
|
||||
}; // namespace Fig
|
||||
|
||||
@@ -187,7 +187,7 @@ namespace Fig
|
||||
|
||||
/*
|
||||
C风格继承 + 手动分发
|
||||
禁止任何 virtual 达到最高效率
|
||||
禁止核心使用任何 virtual 达到最高效率
|
||||
*/
|
||||
enum class ObjectType : uint8_t
|
||||
{
|
||||
@@ -227,5 +227,23 @@ namespace Fig
|
||||
{
|
||||
return type == ObjectType::Instance;
|
||||
}
|
||||
|
||||
// 调试输出
|
||||
virtual String toString() const
|
||||
{
|
||||
return "Object";
|
||||
}
|
||||
};
|
||||
} // namespace Fig
|
||||
} // namespace Fig
|
||||
|
||||
namespace std
|
||||
{
|
||||
template <>
|
||||
struct hash<Fig::Value>
|
||||
{
|
||||
std::size_t operator()(const Fig::Value &v) const noexcept
|
||||
{
|
||||
return std::hash<std::uint64_t>()(v.Raw());
|
||||
}
|
||||
};
|
||||
} // namespace std
|
||||
@@ -25,5 +25,10 @@ namespace Fig
|
||||
struct StringObject final : public Object
|
||||
{
|
||||
String data; // 40 bytes
|
||||
|
||||
virtual String toString() const override
|
||||
{
|
||||
return data;
|
||||
}
|
||||
};
|
||||
};
|
||||
@@ -39,6 +39,10 @@ namespace Fig
|
||||
0 - UnaryOperators::Count BinaryOperators::Count
|
||||
*/
|
||||
|
||||
Value fields[];
|
||||
|
||||
|
||||
|
||||
Object *GetUnaryOperator(UnaryOperator _op)
|
||||
{
|
||||
std::uint8_t idx = static_cast<std::uint8_t>(_op);
|
||||
|
||||
@@ -9,7 +9,7 @@
|
||||
|
||||
namespace Fig
|
||||
{
|
||||
Result<LiteralExpr *, Error> Parser::parseLiteralExpr() // 当前token为literal时调用
|
||||
Result<Expr *, Error> Parser::parseLiteralExpr() // 当前token为literal时调用
|
||||
{
|
||||
StateProtector p(this, {State::ParsingLiteralExpr});
|
||||
|
||||
@@ -17,7 +17,7 @@ namespace Fig
|
||||
LiteralExpr *node = arena.Allocate<LiteralExpr>(literal_token, makeSourceLocation(literal_token));
|
||||
return node;
|
||||
}
|
||||
Result<IdentiExpr *, Error> Parser::parseIdentiExpr() // 当前token为Identifier调用
|
||||
Result<Expr *, Error> Parser::parseIdentiExpr() // 当前token为Identifier调用
|
||||
{
|
||||
StateProtector p(this, {State::ParsingIdentiExpr});
|
||||
|
||||
@@ -27,7 +27,7 @@ namespace Fig
|
||||
return node;
|
||||
}
|
||||
|
||||
Result<InfixExpr *, Error> Parser::parseInfixExpr(Expr *lhs) // 当前token为 op
|
||||
Result<Expr *, Error> Parser::parseInfixExpr(Expr *lhs) // 当前token为 op
|
||||
{
|
||||
StateProtector p(this, {State::ParsingInfixExpr});
|
||||
|
||||
@@ -46,7 +46,7 @@ namespace Fig
|
||||
return node;
|
||||
}
|
||||
|
||||
Result<PrefixExpr *, Error> Parser::parsePrefixExpr() // 当前token为op
|
||||
Result<Expr *, Error> Parser::parsePrefixExpr() // 当前token为op
|
||||
{
|
||||
StateProtector p(this, {State::ParsingPrefixExpr});
|
||||
|
||||
@@ -65,7 +65,7 @@ namespace Fig
|
||||
return node;
|
||||
}
|
||||
|
||||
Result<IndexExpr *, Error> Parser::parseIndexExpr(
|
||||
Result<Expr *, Error> Parser::parseIndexExpr(
|
||||
Expr *base) // 由 parseExpression调用, 当前token为 `[`
|
||||
{
|
||||
StateProtector p(this, {State::ParsingIndexExpr});
|
||||
@@ -91,7 +91,7 @@ namespace Fig
|
||||
return indexExpr;
|
||||
}
|
||||
|
||||
Result<CallExpr *, Error> Parser::parseCallExpr(
|
||||
Result<Expr *, Error> Parser::parseCallExpr(
|
||||
Expr *callee) // 由 parseExpression调用, 当前token为 `(`
|
||||
{
|
||||
StateProtector p(this, {State::ParsingCallExpr});
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
/*!
|
||||
@file src/Parser/Parser.cpp
|
||||
@brief 语法分析器(Pratt + 手动递归下降) 实现
|
||||
@brief 语法分析器实现
|
||||
@author PuqiAR (im@puqiar.top)
|
||||
@date 2026-02-14
|
||||
@date 2026-03-08
|
||||
*/
|
||||
|
||||
#include <Parser/Parser.hpp>
|
||||
@@ -12,21 +12,22 @@ namespace Fig
|
||||
Result<Program *, Error> Parser::Parse()
|
||||
{
|
||||
Program *program = arena.Allocate<Program>();
|
||||
while (!isEOF)
|
||||
|
||||
while (currentToken().type != TokenType::EndOfFile)
|
||||
{
|
||||
auto result = parseStatement();
|
||||
if (!result)
|
||||
{
|
||||
return std::unexpected(result.error());
|
||||
}
|
||||
|
||||
Stmt *stmt = *result;
|
||||
if (!stmt)
|
||||
if (stmt)
|
||||
{
|
||||
continue;
|
||||
program->nodes.push_back(stmt);
|
||||
}
|
||||
program->nodes.push_back(stmt);
|
||||
}
|
||||
|
||||
return program;
|
||||
|
||||
}
|
||||
}; // namespace Fig
|
||||
}; // namespace Fig
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
@file src/Parser/Parser.hpp
|
||||
@brief 语法分析器(Pratt + 手动递归下降) 定义
|
||||
@author PuqiAR (im@puqiar.top)
|
||||
@date 2026-02-14
|
||||
@date 2026-03-08
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
@@ -16,12 +16,10 @@
|
||||
|
||||
#include <cstddef>
|
||||
#include <cstdlib>
|
||||
|
||||
#include <unordered_set>
|
||||
|
||||
namespace Fig
|
||||
{
|
||||
|
||||
class Parser
|
||||
{
|
||||
private:
|
||||
@@ -29,60 +27,56 @@ namespace Fig
|
||||
Lexer &lexer;
|
||||
SourceManager &srcManager;
|
||||
|
||||
size_t index = 0; // token在buffer下标
|
||||
DynArray<Token> buffer;
|
||||
size_t index = 0; // 当前 Token 在 buffer 中的下标
|
||||
DynArray<Token> buffer; // 已从 Lexer 读取的 Token 缓存
|
||||
|
||||
String fileName;
|
||||
bool isEOF = false;
|
||||
|
||||
bool isEOF = false;
|
||||
|
||||
// 惰性获取下一个 Token,跳过注释
|
||||
Token nextToken()
|
||||
{
|
||||
assert(!isEOF && "nextToken: eof but called nextToken");
|
||||
if (index + 1 < buffer.size())
|
||||
{
|
||||
return buffer[++index];
|
||||
}
|
||||
auto result = lexer.NextToken();
|
||||
if (!result)
|
||||
if (isEOF)
|
||||
return buffer[index];
|
||||
|
||||
while (true)
|
||||
{
|
||||
ReportError(result.error(), srcManager);
|
||||
std::exit(-1);
|
||||
auto result = lexer.NextToken();
|
||||
if (!result)
|
||||
{
|
||||
ReportError(result.error(), srcManager);
|
||||
std::exit(-1);
|
||||
}
|
||||
const Token &token = result.value();
|
||||
if (token.type == TokenType::Comments)
|
||||
continue; // 惰性跳过注释
|
||||
|
||||
if (token.type == TokenType::EndOfFile)
|
||||
isEOF = true;
|
||||
buffer.push_back(token);
|
||||
index = buffer.size() - 1;
|
||||
return buffer[index];
|
||||
}
|
||||
const Token &token = result.value();
|
||||
if (token.type == TokenType::EndOfFile)
|
||||
{
|
||||
isEOF = true;
|
||||
}
|
||||
buffer.push_back(token);
|
||||
index++;
|
||||
return token;
|
||||
}
|
||||
|
||||
inline Token prevToken()
|
||||
{
|
||||
if (buffer.size() < 2)
|
||||
{
|
||||
return currentToken();
|
||||
}
|
||||
return buffer[buffer.size() - 2];
|
||||
return (index > 0) ? buffer[index - 1] : buffer[0];
|
||||
}
|
||||
|
||||
inline Token currentToken()
|
||||
{
|
||||
if (buffer.empty())
|
||||
{
|
||||
return nextToken();
|
||||
}
|
||||
return buffer.back();
|
||||
return buffer[index];
|
||||
}
|
||||
|
||||
// 惰性窥视后续 Token
|
||||
Token peekToken(size_t lookahead = 1)
|
||||
{
|
||||
assert(!isEOF && "peekToken: eof but called peekToken");
|
||||
|
||||
size_t peekIndex = index + lookahead;
|
||||
while (peekIndex >= buffer.size() && !isEOF)
|
||||
size_t targetIndex = index + lookahead;
|
||||
while (targetIndex >= buffer.size() && !isEOF)
|
||||
{
|
||||
auto result = lexer.NextToken();
|
||||
if (!result)
|
||||
@@ -90,29 +84,22 @@ namespace Fig
|
||||
ReportError(result.error(), srcManager);
|
||||
std::abort();
|
||||
}
|
||||
const Token &token = result.value();
|
||||
if (token.type == TokenType::EndOfFile)
|
||||
{
|
||||
if (result->type == TokenType::Comments)
|
||||
continue;
|
||||
if (result->type == TokenType::EndOfFile)
|
||||
isEOF = true;
|
||||
}
|
||||
buffer.push_back(token);
|
||||
buffer.push_back(*result);
|
||||
}
|
||||
if (peekIndex >= buffer.size()) // 没有那么多token
|
||||
{
|
||||
return buffer.back(); // back是EOF Token
|
||||
}
|
||||
return buffer[peekIndex];
|
||||
return (targetIndex >= buffer.size()) ? buffer.back() : buffer[targetIndex];
|
||||
}
|
||||
|
||||
inline Token consumeToken()
|
||||
{
|
||||
if (isEOF)
|
||||
return buffer.back();
|
||||
Token current = currentToken();
|
||||
nextToken();
|
||||
if (current.type != TokenType::EndOfFile)
|
||||
nextToken();
|
||||
return current;
|
||||
}
|
||||
|
||||
inline bool match(TokenType type)
|
||||
{
|
||||
if (currentToken().type == type)
|
||||
@@ -123,47 +110,18 @@ namespace Fig
|
||||
return false;
|
||||
}
|
||||
|
||||
inline Error makeUnexpectTokenError(const String &stmtType,
|
||||
const String &expect,
|
||||
const Token &tokenGot,
|
||||
std::source_location loc = std::source_location::current())
|
||||
{
|
||||
return Error(ErrorType::SyntaxError,
|
||||
std::format("expect '{}' in {}, got `{}`",
|
||||
expect,
|
||||
stmtType,
|
||||
magic_enum::enum_name(tokenGot.type)),
|
||||
"none",
|
||||
makeSourceLocation(tokenGot),
|
||||
loc);
|
||||
}
|
||||
|
||||
inline Error makeExpectSemicolonError(
|
||||
std::source_location loc = std::source_location::current())
|
||||
{
|
||||
return Error(ErrorType::SyntaxError,
|
||||
"expect ';' after statement",
|
||||
"insert ';'",
|
||||
makeSourceLocation(currentToken()),
|
||||
loc);
|
||||
}
|
||||
|
||||
public:
|
||||
struct State
|
||||
{
|
||||
enum StateType : std::uint8_t
|
||||
{
|
||||
Standby,
|
||||
|
||||
ParsingLiteralExpr,
|
||||
ParsingIdentiExpr,
|
||||
|
||||
ParsingInfixExpr,
|
||||
ParsingPrefixExpr,
|
||||
|
||||
ParsingIndexExpr,
|
||||
ParsingCallExpr,
|
||||
|
||||
ParsingVarDecl,
|
||||
ParsingIf,
|
||||
ParsingWhile,
|
||||
@@ -171,9 +129,7 @@ namespace Fig
|
||||
ParsingReturn,
|
||||
ParsingBreak,
|
||||
ParsingContinue,
|
||||
|
||||
ParsingNamedTypeExpr,
|
||||
|
||||
} type = StateType::Standby;
|
||||
std::unordered_set<TokenType> stopAt = {};
|
||||
};
|
||||
@@ -190,134 +146,121 @@ namespace Fig
|
||||
return baseTerminators;
|
||||
}
|
||||
|
||||
std::unordered_set<TokenType> &getTerminators() // 返回固定的终止符
|
||||
std::unordered_set<TokenType> &getTerminators()
|
||||
{
|
||||
/*
|
||||
Syntax terminators:
|
||||
; ) ] } , EOF
|
||||
*/
|
||||
|
||||
static std::unordered_set<TokenType> terminators(getBaseTerminators());
|
||||
return terminators;
|
||||
}
|
||||
|
||||
void resetTermintors()
|
||||
{
|
||||
getTerminators() = getBaseTerminators();
|
||||
}
|
||||
bool shouldTerminate() // 判断是否终结
|
||||
{
|
||||
const Token &token = currentToken();
|
||||
const auto &terminators = getTerminators();
|
||||
|
||||
if (terminators.contains(token.type))
|
||||
{
|
||||
bool shouldTerminate()
|
||||
{
|
||||
const Token &token = currentToken();
|
||||
if (getTerminators().contains(token.type))
|
||||
return true;
|
||||
}
|
||||
for (auto it = stateStack.rbegin(); it < stateStack.rend(); ++it)
|
||||
{
|
||||
if (it->stopAt.contains(token.type))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
DynArray<State> stateStack;
|
||||
|
||||
State ¤tState()
|
||||
State ¤tState()
|
||||
{
|
||||
return stateStack.back();
|
||||
}
|
||||
|
||||
void pushState(State _state)
|
||||
{
|
||||
stateStack.push_back(std::move(_state));
|
||||
}
|
||||
|
||||
void popState()
|
||||
{
|
||||
if (!stateStack.empty())
|
||||
{
|
||||
stateStack.pop_back();
|
||||
}
|
||||
}
|
||||
|
||||
class StateProtector
|
||||
struct StateProtector
|
||||
{
|
||||
Parser *parser;
|
||||
|
||||
public:
|
||||
StateProtector(Parser *p, const State &newState) : parser(p)
|
||||
Parser *p;
|
||||
StateProtector(Parser *_p, State _s) : p(_p)
|
||||
{
|
||||
parser->pushState(newState);
|
||||
p->pushState(_s);
|
||||
}
|
||||
|
||||
~StateProtector()
|
||||
{
|
||||
parser->popState();
|
||||
p->popState();
|
||||
}
|
||||
|
||||
// 禁止拷贝
|
||||
StateProtector(const StateProtector &) = delete;
|
||||
StateProtector &operator=(const StateProtector &) = delete;
|
||||
};
|
||||
|
||||
public:
|
||||
Parser(Lexer &_lexer, SourceManager &_srcManager, String _fileName) :
|
||||
lexer(_lexer), srcManager(_srcManager), fileName(std::move(_fileName))
|
||||
{
|
||||
pushState(State());
|
||||
}
|
||||
|
||||
private:
|
||||
SourceLocation makeSourceLocation(const Token &tok)
|
||||
{
|
||||
auto [line, column] = srcManager.GetLineColumn(tok.index);
|
||||
// 物理防爆盾:防止因解析错位导致的异常列号引起终端 OOM
|
||||
if (column > 5000)
|
||||
column = 1;
|
||||
return SourceLocation(SourcePosition(line, column, tok.length),
|
||||
fileName,
|
||||
"[internal parser]",
|
||||
magic_enum::enum_name(currentState().type).data());
|
||||
}
|
||||
|
||||
/* TypeExpressions */
|
||||
inline Error makeUnexpectTokenError(const String &stmt, const String &exp, const Token &got)
|
||||
{
|
||||
return Error(ErrorType::SyntaxError,
|
||||
std::format(
|
||||
"expect '{}' in {}, got `{}`", exp, stmt, magic_enum::enum_name(got.type)),
|
||||
"none",
|
||||
makeSourceLocation(got));
|
||||
}
|
||||
|
||||
Result<NamedTypeExpr *, Error> parseNamedTypeExpr(); // 当前token为identifier
|
||||
inline Error makeExpectSemicolonError()
|
||||
{
|
||||
return Error(ErrorType::SyntaxError,
|
||||
"expect ';' after statement",
|
||||
"insert ';'",
|
||||
makeSourceLocation(currentToken()));
|
||||
}
|
||||
|
||||
Result<TypeExpr *, Error> parseTypeExpr();
|
||||
|
||||
/* Expressions */
|
||||
Result<LiteralExpr *, Error> parseLiteralExpr(); // 当前token为literal时调用
|
||||
Result<IdentiExpr *, Error> parseIdentiExpr(); // 当前token为Identifier调用
|
||||
|
||||
Result<InfixExpr *, Error> parseInfixExpr(
|
||||
Expr *); // 由 parseExpression递归调用, 当前token为op
|
||||
Result<PrefixExpr *, Error> parsePrefixExpr(); // 由 parseExpression递归调用, 当前token为op
|
||||
|
||||
Result<IndexExpr *, Error> parseIndexExpr(
|
||||
Expr *); // 由 parseExpression调用, 当前token为 `[`
|
||||
Result<CallExpr *, Error> parseCallExpr(Expr *); // 由 parseExpression调用, 当前token为 `(`
|
||||
Result<TypeExpr *, Error> parseNamedTypeExpr();
|
||||
|
||||
Result<Expr *, Error> parseExpression(BindingPower = 0);
|
||||
Result<Expr *, Error> parseLiteralExpr();
|
||||
Result<Expr *, Error> parseIdentiExpr();
|
||||
Result<Expr *, Error> parsePrefixExpr();
|
||||
Result<Expr *, Error> parseInfixExpr(Expr *);
|
||||
Result<Expr *, Error> parseIndexExpr(Expr *);
|
||||
Result<Expr *, Error> parseCallExpr(Expr *);
|
||||
Result<Expr *, Error> parseNewExpr();
|
||||
|
||||
/* Statements */
|
||||
Result<BlockStmt *, Error> parseBlockStmt(); // 当前token为 {
|
||||
Result<VarDecl *, Error> parseVarDecl(bool); // 由 parseStatement调用, 当前token为 var
|
||||
Result<IfStmt *, Error> parseIfStmt(); // 由 parseStatement调用, 当前token为 if
|
||||
Result<WhileStmt *, Error> parseWhileStmt(); // 由 parseStatement调用, 当前token为 while
|
||||
Result<BlockStmt *, Error> parseBlockStmt();
|
||||
Result<VarDecl *, Error> parseVarDecl(bool);
|
||||
Result<IfStmt *, Error> parseIfStmt();
|
||||
Result<WhileStmt *, Error> parseWhileStmt();
|
||||
Result<DynArray<Param *>, Error> parseFnParams();
|
||||
Result<FnDefStmt *, Error> parseFnDefStmt(bool);
|
||||
Result<ReturnStmt *, Error> parseReturnStmt();
|
||||
|
||||
Result<DynArray<Param *>, Error> parseFnParams(); // 由 parseFnDefStmt或lambda调用
|
||||
Result<FnDefStmt *, Error> parseFnDefStmt(bool); // 由 parseStatement调用, 当前token为 func
|
||||
Result<Stmt *, Error> parseStructDef(bool);
|
||||
Result<Stmt *, Error> parseInterfaceDef(bool);
|
||||
Result<Stmt *, Error> parseImpl();
|
||||
|
||||
Result<ReturnStmt *, Error> parseReturnStmt(); // 由 parseStatement调用, 当前token为 return
|
||||
// continue break直接由parseStatement一步解析
|
||||
|
||||
Result<Stmt *, Error> parseStatement();
|
||||
Result<Stmt *, Error> parseStatement();
|
||||
|
||||
public:
|
||||
Parser(Lexer &_lexer, SourceManager &_src, String _file) :
|
||||
lexer(_lexer), srcManager(_src), fileName(std::move(_file))
|
||||
{
|
||||
pushState(State());
|
||||
}
|
||||
|
||||
Result<Program *, Error> Parse();
|
||||
};
|
||||
|
||||
#define SET_STOP_AT(...) currentState().stopAt = {__VA_ARGS__};
|
||||
}; // namespace Fig
|
||||
} // namespace Fig
|
||||
|
||||
@@ -7,6 +7,7 @@ int main()
|
||||
|
||||
String fileName = "test.fig";
|
||||
String filePath = "T:/Files/Maker/Code/MyCodingLanguage/The Fig Project/Fig/test.fig";
|
||||
|
||||
SourceManager srcManager(filePath);
|
||||
|
||||
String source = srcManager.Read();
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*!
|
||||
@file src/Parser/StmtParser.hpp
|
||||
@file src/Parser/StmtParser.cpp
|
||||
@brief 语法分析器(Pratt + 手动递归下降) 语句解析实现
|
||||
@author PuqiAR (im@puqiar.top)
|
||||
@date 2026-02-19
|
||||
@@ -9,9 +9,9 @@
|
||||
|
||||
namespace Fig
|
||||
{
|
||||
Result<BlockStmt *, Error> Parser::parseBlockStmt() // 当前token为 {
|
||||
Result<BlockStmt *, Error> Parser::parseBlockStmt()
|
||||
{
|
||||
SourceLocation location = makeSourceLocation(consumeToken()); // consume `{`
|
||||
SourceLocation location = makeSourceLocation(consumeToken());
|
||||
BlockStmt *stmt = arena.Allocate<BlockStmt>();
|
||||
while (true)
|
||||
{
|
||||
@@ -35,24 +35,23 @@ namespace Fig
|
||||
}
|
||||
return stmt;
|
||||
}
|
||||
Result<VarDecl *, Error> Parser::parseVarDecl(
|
||||
bool isPublic) // 由 parseStatement调用, 当前token为 var
|
||||
|
||||
Result<VarDecl *, Error> Parser::parseVarDecl(bool isPublic)
|
||||
{
|
||||
StateProtector p(this, {State::ParsingVarDecl});
|
||||
|
||||
SourceLocation location = makeSourceLocation(consumeToken()); // consume `var`
|
||||
SourceLocation location = makeSourceLocation(consumeToken());
|
||||
|
||||
if (currentToken().type != TokenType::Identifier)
|
||||
{
|
||||
return std::unexpected(makeUnexpectTokenError("VarDecl", "var name", currentToken()));
|
||||
}
|
||||
const String &name = srcManager.GetSub(currentToken().index, currentToken().length);
|
||||
consumeToken(); // consume name
|
||||
consumeToken();
|
||||
|
||||
TypeExpr *typeSpeicifer = nullptr;
|
||||
if (match(TokenType::Colon)) // `:`
|
||||
if (match(TokenType::Colon))
|
||||
{
|
||||
// SET_STOP_AT(TokenType::Walrus, TokenType::Assign);
|
||||
auto result = parseTypeExpr();
|
||||
if (!result)
|
||||
{
|
||||
@@ -72,15 +71,14 @@ namespace Fig
|
||||
}
|
||||
initExpr = *result;
|
||||
}
|
||||
else if (match(TokenType::Walrus)) // :=
|
||||
else if (match(TokenType::Walrus))
|
||||
{
|
||||
if (typeSpeicifer) // 指定了类型同时使用 :=
|
||||
if (typeSpeicifer)
|
||||
{
|
||||
return std::unexpected(Error(ErrorType::SyntaxError,
|
||||
"used type infer but specifying the type",
|
||||
"change `:=` to '='",
|
||||
makeSourceLocation(prevToken()) // :=
|
||||
));
|
||||
makeSourceLocation(prevToken())));
|
||||
}
|
||||
auto result = parseExpression();
|
||||
if (!result)
|
||||
@@ -88,24 +86,25 @@ namespace Fig
|
||||
return std::unexpected(result.error());
|
||||
}
|
||||
initExpr = *result;
|
||||
isInfer = true; // 使用类型自动推断 :=
|
||||
isInfer = true;
|
||||
}
|
||||
if (!match(TokenType::Semicolon))
|
||||
{
|
||||
return std::unexpected(makeExpectSemicolonError());
|
||||
}
|
||||
VarDecl *varDecl = arena.Allocate<VarDecl>(isPublic, name, typeSpeicifer, isInfer, initExpr, location);
|
||||
VarDecl *varDecl =
|
||||
arena.Allocate<VarDecl>(isPublic, name, typeSpeicifer, isInfer, initExpr, location);
|
||||
return varDecl;
|
||||
}
|
||||
|
||||
Result<IfStmt *, Error> Parser::parseIfStmt() // 由 parseStatement调用, 当前token is if
|
||||
Result<IfStmt *, Error> Parser::parseIfStmt()
|
||||
{
|
||||
StateProtector p(this, {State::ParsingIf});
|
||||
|
||||
SourceLocation location = makeSourceLocation(consumeToken()); // consume `if`
|
||||
SourceLocation location = makeSourceLocation(consumeToken());
|
||||
|
||||
Expr *cond = nullptr;
|
||||
if (match(TokenType::LeftParen)) // match and consume `(`
|
||||
if (match(TokenType::LeftParen))
|
||||
{
|
||||
const Token &lpToken = prevToken();
|
||||
SET_STOP_AT(TokenType::RightParen, TokenType::LeftBrace);
|
||||
@@ -116,7 +115,6 @@ namespace Fig
|
||||
}
|
||||
if (!match(TokenType::RightParen))
|
||||
{
|
||||
delete *result;
|
||||
return std::unexpected(Error(ErrorType::SyntaxError,
|
||||
"unclosed parenthese in if condition",
|
||||
"insert `)`",
|
||||
@@ -155,7 +153,6 @@ namespace Fig
|
||||
SourceLocation elseLocation = makeSourceLocation(prevToken());
|
||||
if (match(TokenType::If))
|
||||
{
|
||||
// else if
|
||||
if (alternate)
|
||||
{
|
||||
return std::unexpected(Error(ErrorType::SyntaxError,
|
||||
@@ -166,7 +163,7 @@ namespace Fig
|
||||
|
||||
Expr *cond = nullptr;
|
||||
|
||||
if (match(TokenType::LeftParen)) // `(`
|
||||
if (match(TokenType::LeftParen))
|
||||
{
|
||||
const Token &lpToken = prevToken();
|
||||
|
||||
@@ -178,7 +175,6 @@ namespace Fig
|
||||
}
|
||||
if (!match(TokenType::RightParen))
|
||||
{
|
||||
delete *result;
|
||||
return std::unexpected(Error(ErrorType::SyntaxError,
|
||||
"unclosed parenthese in if condition",
|
||||
"insert `)`",
|
||||
@@ -212,7 +208,6 @@ namespace Fig
|
||||
}
|
||||
else
|
||||
{
|
||||
// else
|
||||
if (alternate)
|
||||
{
|
||||
return std::unexpected(Error(ErrorType::SyntaxError,
|
||||
@@ -237,11 +232,11 @@ namespace Fig
|
||||
return ifStmt;
|
||||
}
|
||||
|
||||
Result<WhileStmt *, Error> Parser::parseWhileStmt() // 由 parseStatement调用, 当前token为 while
|
||||
Result<WhileStmt *, Error> Parser::parseWhileStmt()
|
||||
{
|
||||
StateProtector p(this, {State::ParsingWhile});
|
||||
|
||||
SourceLocation location = makeSourceLocation(consumeToken()); // consume `while`
|
||||
SourceLocation location = makeSourceLocation(consumeToken());
|
||||
|
||||
Expr *cond = nullptr;
|
||||
if (match(TokenType::LeftParen))
|
||||
@@ -257,7 +252,6 @@ namespace Fig
|
||||
|
||||
if (!match(TokenType::RightParen))
|
||||
{
|
||||
delete *result;
|
||||
return std::unexpected(Error(ErrorType::SyntaxError,
|
||||
"unclosed parenthese in while condition",
|
||||
"insert ')'",
|
||||
@@ -278,7 +272,6 @@ namespace Fig
|
||||
|
||||
if (currentToken().type != TokenType::LeftBrace)
|
||||
{
|
||||
delete cond;
|
||||
return std::unexpected(
|
||||
makeUnexpectTokenError("while stmt", "left brace '{'", currentToken()));
|
||||
}
|
||||
@@ -286,7 +279,6 @@ namespace Fig
|
||||
auto result = parseBlockStmt();
|
||||
if (!result)
|
||||
{
|
||||
delete cond;
|
||||
return std::unexpected(result.error());
|
||||
}
|
||||
BlockStmt *body = *result;
|
||||
@@ -295,11 +287,11 @@ namespace Fig
|
||||
return whileStmt;
|
||||
}
|
||||
|
||||
Result<DynArray<Param *>, Error> Parser::parseFnParams() // 由 parseFnDefStmt或lambda调用
|
||||
Result<DynArray<Param *>, Error> Parser::parseFnParams()
|
||||
{
|
||||
StateProtector p(this, {State::ParsingFnDefStmt});
|
||||
|
||||
const Token &lpToken = consumeToken(); // consume `(`
|
||||
const Token &lpToken = consumeToken();
|
||||
DynArray<Param *> params;
|
||||
|
||||
while (true)
|
||||
@@ -320,10 +312,8 @@ namespace Fig
|
||||
SourceLocation location = makeSourceLocation(nToken);
|
||||
const String &name = srcManager.GetSub(nToken.index, nToken.length);
|
||||
|
||||
// TODO: 支持剩余参数解析...
|
||||
|
||||
TypeExpr *type = nullptr;
|
||||
if (match(TokenType::Colon)) // :
|
||||
if (match(TokenType::Colon))
|
||||
{
|
||||
auto result = parseTypeExpr();
|
||||
if (!result)
|
||||
@@ -335,16 +325,12 @@ namespace Fig
|
||||
|
||||
Expr *defaultValue = nullptr;
|
||||
|
||||
if (match(TokenType::Assign)) // =
|
||||
if (match(TokenType::Assign))
|
||||
{
|
||||
SET_STOP_AT(TokenType::Comma, TokenType::RightParen, TokenType::LeftBrace); // , ) {
|
||||
SET_STOP_AT(TokenType::Comma, TokenType::RightParen, TokenType::LeftBrace);
|
||||
auto result = parseExpression();
|
||||
if (!result)
|
||||
{
|
||||
if (type)
|
||||
{
|
||||
delete type;
|
||||
}
|
||||
return std::unexpected(result.error());
|
||||
}
|
||||
defaultValue = *result;
|
||||
@@ -365,18 +351,16 @@ namespace Fig
|
||||
return params;
|
||||
}
|
||||
|
||||
Result<FnDefStmt *, Error> Parser::parseFnDefStmt(
|
||||
bool isPublic) // 由 parseStatement调用, 当前token为 func
|
||||
Result<FnDefStmt *, Error> Parser::parseFnDefStmt(bool isPublic)
|
||||
{
|
||||
SourceLocation location = makeSourceLocation(
|
||||
consumeToken()); // 无论是否加了public, location都设置为 func token (我懒 :D)
|
||||
SourceLocation location = makeSourceLocation(consumeToken());
|
||||
|
||||
if (!currentToken().isIdentifier())
|
||||
{
|
||||
return std::unexpected(
|
||||
makeUnexpectTokenError("fn def stmt", "function name", currentToken()));
|
||||
}
|
||||
const Token &nameToken = consumeToken(); // consume name
|
||||
const Token &nameToken = consumeToken();
|
||||
const String &name = srcManager.GetSub(nameToken.index, nameToken.length);
|
||||
|
||||
if (currentToken().type != TokenType::LeftParen)
|
||||
@@ -395,7 +379,7 @@ namespace Fig
|
||||
params = *paraResult;
|
||||
|
||||
TypeExpr *returnType = nullptr;
|
||||
if (match(TokenType::RightArrow)) // ->
|
||||
if (match(TokenType::RightArrow))
|
||||
{
|
||||
auto result = parseTypeExpr();
|
||||
if (!result)
|
||||
@@ -415,24 +399,20 @@ namespace Fig
|
||||
|
||||
if (!bodyResult)
|
||||
{
|
||||
if (returnType)
|
||||
{
|
||||
delete returnType;
|
||||
}
|
||||
return std::unexpected(bodyResult.error());
|
||||
}
|
||||
body = *bodyResult;
|
||||
|
||||
FnDefStmt *fnDef = arena.Allocate<FnDefStmt>(isPublic, name, params, returnType, body, location);
|
||||
FnDefStmt *fnDef =
|
||||
arena.Allocate<FnDefStmt>(isPublic, name, params, returnType, body, location);
|
||||
return fnDef;
|
||||
}
|
||||
|
||||
Result<ReturnStmt *, Error>
|
||||
Parser::parseReturnStmt() // 由 parseStatement调用, 当前token为 return
|
||||
Result<ReturnStmt *, Error> Parser::parseReturnStmt()
|
||||
{
|
||||
StateProtector p(this, {State::ParsingReturn});
|
||||
|
||||
SourceLocation location = makeSourceLocation(consumeToken()); // consume `return`
|
||||
SourceLocation location = makeSourceLocation(consumeToken());
|
||||
auto result = parseExpression();
|
||||
if (!result)
|
||||
{
|
||||
@@ -455,7 +435,7 @@ namespace Fig
|
||||
|
||||
if (currentToken().type == TokenType::Public)
|
||||
{
|
||||
consumeToken(); // consume `public`
|
||||
consumeToken();
|
||||
if (currentToken().type == TokenType::Variable)
|
||||
{
|
||||
return parseVarDecl(true);
|
||||
|
||||
@@ -1,54 +1,73 @@
|
||||
/*!
|
||||
@file src/Parser/TypeExprParser.cpp
|
||||
@brief 类型表达式解析器实现
|
||||
@brief 类型表达式解析器实现:支持泛型与空安全
|
||||
@author PuqiAR (im@puqiar.top)
|
||||
@date 2026-02-25
|
||||
@date 2026-03-08
|
||||
*/
|
||||
|
||||
#include <Parser/Parser.hpp>
|
||||
|
||||
namespace Fig
|
||||
{
|
||||
Result<NamedTypeExpr *, Error> Parser::parseNamedTypeExpr() // 当前token为identifier
|
||||
// 解析基础命名类型与泛型: List<Int>
|
||||
Result<TypeExpr *, Error> Parser::parseNamedTypeExpr()
|
||||
{
|
||||
StateProtector p(this, {State::ParsingNamedTypeExpr});
|
||||
|
||||
SourceLocation location = makeSourceLocation(currentToken());
|
||||
|
||||
DynArray<String> path;
|
||||
while (true)
|
||||
{
|
||||
const Token &subPathTok = consumeToken();
|
||||
const String &subPath = srcManager.GetSub(subPathTok.index, subPathTok.length);
|
||||
path.push_back(subPath);
|
||||
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("named type expr", "identifier", currentToken()));
|
||||
}
|
||||
return std::unexpected(makeUnexpectTokenError("Type", "identifier", currentToken()));
|
||||
}
|
||||
else
|
||||
else break;
|
||||
}
|
||||
|
||||
DynArray<TypeExpr *> arguments;
|
||||
if (match(TokenType::Less)) // `<`
|
||||
{
|
||||
while (true)
|
||||
{
|
||||
break;
|
||||
auto result = parseTypeExpr();
|
||||
if (!result) return std::unexpected(result.error());
|
||||
arguments.push_back(*result);
|
||||
|
||||
if (match(TokenType::Greater)) break; // `>`
|
||||
if (!match(TokenType::Comma))
|
||||
return std::unexpected(makeUnexpectTokenError("TypeArgs", "'>' or ','", currentToken()));
|
||||
}
|
||||
}
|
||||
NamedTypeExpr *namedTypeExpr = arena.Allocate<NamedTypeExpr>(path, location);
|
||||
return namedTypeExpr;
|
||||
|
||||
return arena.Allocate<NamedTypeExpr>(path, arguments, location);
|
||||
}
|
||||
|
||||
// 解析主入口: 处理 `?` 后缀
|
||||
Result<TypeExpr *, Error> Parser::parseTypeExpr()
|
||||
{
|
||||
// TODO: 泛型表达式解析
|
||||
TypeExpr *base = nullptr;
|
||||
|
||||
// 目前只支持命名类型 (以后可以加函数类型 (Int)->Int)
|
||||
if (currentToken().isIdentifier())
|
||||
{
|
||||
return parseNamedTypeExpr();
|
||||
auto res = parseNamedTypeExpr();
|
||||
if (!res) return std::unexpected(res.error());
|
||||
base = *res;
|
||||
}
|
||||
else
|
||||
else return std::unexpected(makeUnexpectTokenError("TypeExpr", "name", currentToken()));
|
||||
|
||||
// 空安全处理: Int?? 也可以,但 Analyzer 会规范化它
|
||||
while (match(TokenType::Question))
|
||||
{
|
||||
return std::unexpected(makeUnexpectTokenError("type expr", "name/...", currentToken()));
|
||||
base = arena.Allocate<NullableTypeExpr>(base, makeSourceLocation(prevToken()));
|
||||
}
|
||||
|
||||
return base;
|
||||
}
|
||||
}; // namespace Fig
|
||||
}
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,100 +1,53 @@
|
||||
/*!
|
||||
@file src/Sema/Analyzer.hpp
|
||||
@brief 前端类型检查器定义
|
||||
@author PuqiAR (im@puqiar.top)
|
||||
@date 2026-02-23
|
||||
@brief 语义分析器定义
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <Sema/Environment.hpp>
|
||||
#include <Sema/Type.hpp>
|
||||
|
||||
#include <Ast/Ast.hpp>
|
||||
#include <Deps/Deps.hpp>
|
||||
#include <Sema/Type.hpp>
|
||||
#include <Sema/Environment.hpp>
|
||||
#include <Utils/Arena.hpp>
|
||||
#include <Error/Diagnostics.hpp>
|
||||
#include <SourceManager/SourceManager.hpp>
|
||||
|
||||
namespace Fig
|
||||
{
|
||||
class Analyzer
|
||||
{
|
||||
private:
|
||||
Environment env;
|
||||
Arena arena;
|
||||
SourceManager &manager;
|
||||
TypeContext typeCtx;
|
||||
Environment env;
|
||||
Diagnostics diag;
|
||||
|
||||
TypeContext typeCtx;
|
||||
HashMap<String, BaseType*> globalTypes;
|
||||
HashMap<String, Symbol*> globalSymbols;
|
||||
|
||||
TypeInfo *currentReturnType = nullptr; // 正在分析的函数,预期返回类型
|
||||
bool hasInit = false;
|
||||
bool hasMain = false;
|
||||
|
||||
struct ReturnTypeProtector
|
||||
{
|
||||
Analyzer *analyzer;
|
||||
TypeInfo *prevCurrentReturnType;
|
||||
// 核心递归查找:解决跨越函数边界的捕获问题
|
||||
Result<Symbol*, Error> resolveSymbolInternal(const String &name, const SourceLocation &loc, Scope* startScope);
|
||||
|
||||
[[nodiscard]]
|
||||
ReturnTypeProtector(Analyzer *_analyzer, TypeInfo *current) :
|
||||
analyzer(_analyzer), prevCurrentReturnType(_analyzer->currentReturnType)
|
||||
{
|
||||
analyzer->currentReturnType = current;
|
||||
}
|
||||
Result<Type, Error> resolveTypeExpr(TypeExpr *texpr);
|
||||
Result<void, Error> pass1(Program *prog);
|
||||
Result<void, Error> resolveTypes(Program *prog);
|
||||
Result<void, Error> checkBodies(Program *prog);
|
||||
|
||||
~ReturnTypeProtector()
|
||||
{
|
||||
analyzer->currentReturnType = prevCurrentReturnType;
|
||||
}
|
||||
|
||||
ReturnTypeProtector(const ReturnTypeProtector &) = delete;
|
||||
ReturnTypeProtector &operator=(const ReturnTypeProtector &) = delete;
|
||||
};
|
||||
|
||||
|
||||
SourceLocation makeSourceLocation(
|
||||
AstNode *ast, std::source_location loc = std::source_location::current())
|
||||
{
|
||||
return SourceLocation(ast->location.sp,
|
||||
ast->location.fileName,
|
||||
"[internal analyzer]",
|
||||
loc.function_name());
|
||||
}
|
||||
|
||||
bool isValidLvalue(Expr *expr)
|
||||
{
|
||||
if (expr->type == AstType::IdentiExpr)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
if (expr->type == AstType::InfixExpr)
|
||||
{
|
||||
InfixExpr *infix = static_cast<InfixExpr *>(expr);
|
||||
if (infix->op == BinaryOperator::MemberAccess)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
if (expr->type == AstType::IndexExpr)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
Result<TypeInfo *, Error> resolveType(TypeExpr *);
|
||||
|
||||
Result<void, Error> analyzeVarDecl(VarDecl *);
|
||||
Result<void, Error> analyzeIfStmt(IfStmt *);
|
||||
Result<void, Error> analyzeWhileStmt(WhileStmt *);
|
||||
Result<void, Error> analyzeFnDefStmt(FnDefStmt *);
|
||||
Result<void, Error> analyzeReturnStmt(ReturnStmt *);
|
||||
|
||||
Result<void, Error> analyzeIdentiExpr(IdentiExpr *);
|
||||
Result<void, Error> analyzeInfixExpr(InfixExpr *);
|
||||
Result<void, Error> analyzeCallExpr(CallExpr *);
|
||||
|
||||
Result<void, Error> analyzeStmt(Stmt *);
|
||||
Result<void, Error> analyzeExpr(Expr *);
|
||||
Result<void, Error> analyzeStmt(Stmt *stmt);
|
||||
Result<Type, Error> analyzeExpr(Expr *expr);
|
||||
|
||||
int addUpvalue(Scope *scope, Symbol *target, bool isLocal);
|
||||
|
||||
public:
|
||||
Result<void, Error> Analyze(Program *);
|
||||
Analyzer(SourceManager &m) : manager(m) {}
|
||||
|
||||
Analyzer(SourceManager &_manager) : manager(_manager), typeCtx() {}
|
||||
Result<void, Error> Analyze(Program *prog);
|
||||
|
||||
Diagnostics& GetDiagnostics() { return diag; }
|
||||
TypeContext& GetTypeContext() { return typeCtx; }
|
||||
};
|
||||
}; // namespace Fig
|
||||
}
|
||||
|
||||
@@ -1,50 +1,59 @@
|
||||
#include <Sema/Analyzer.hpp>
|
||||
|
||||
#include <Deps/Deps.hpp>
|
||||
#include <Error/Error.hpp>
|
||||
#include <Lexer/Lexer.hpp>
|
||||
#include <Parser/Parser.hpp>
|
||||
#include <SourceManager/SourceManager.hpp>
|
||||
|
||||
#include <Sema/Analyzer.hpp>
|
||||
#include <filesystem>
|
||||
#include <iostream>
|
||||
|
||||
|
||||
namespace fs = std::filesystem;
|
||||
|
||||
void runTest(const std::string &path)
|
||||
{
|
||||
using namespace Fig;
|
||||
std::cout << "\n[TEST] Testing: " << path << std::endl;
|
||||
|
||||
SourceManager srcManager{String(path)};
|
||||
String source = srcManager.Read();
|
||||
if (!srcManager.read)
|
||||
{
|
||||
std::cerr << "FAILED: Could not read file" << std::endl;
|
||||
return;
|
||||
}
|
||||
|
||||
Lexer lexer(source, String(path));
|
||||
Parser parser(lexer, srcManager, String(path));
|
||||
|
||||
auto pRes = parser.Parse();
|
||||
if (!pRes)
|
||||
{
|
||||
std::cerr << "FAILED: Parser Error" << std::endl;
|
||||
ReportError(pRes.error(), srcManager);
|
||||
return;
|
||||
}
|
||||
|
||||
// 修复:确保 analyzer 存活直到错误打印完成
|
||||
Analyzer analyzer(srcManager);
|
||||
auto aRes = analyzer.Analyze(*pRes);
|
||||
|
||||
if (!aRes)
|
||||
{
|
||||
std::cout << "SUCCESS: Analyzer correctly caught error:" << std::endl;
|
||||
ReportError(aRes.error(), srcManager);
|
||||
}
|
||||
else
|
||||
{
|
||||
std::cerr << "FAILED: Analyzer missed the semantic error!" << std::endl;
|
||||
}
|
||||
}
|
||||
|
||||
int main()
|
||||
{
|
||||
using namespace Fig;
|
||||
|
||||
const String &fileName = "test.fig";
|
||||
const String &filePath = "T:/Files/Maker/Code/MyCodingLanguage/The Fig Project/Fig/test.fig";
|
||||
|
||||
SourceManager manager(filePath);
|
||||
manager.Read();
|
||||
|
||||
if (!manager.read)
|
||||
std::string testDir = "T:/Files/Maker/Code/MyCodingLanguage/The Fig Project/Fig/tests/Sema";
|
||||
for (const auto &entry : fs::directory_iterator(testDir))
|
||||
{
|
||||
std::cerr << "Read file failed \n";
|
||||
return 1;
|
||||
if (entry.path().extension() == ".fig")
|
||||
{
|
||||
runTest(entry.path().string());
|
||||
}
|
||||
}
|
||||
|
||||
Lexer lexer(manager.GetSource(), fileName);
|
||||
Parser parser(lexer, manager, fileName);
|
||||
|
||||
auto result = parser.Parse();
|
||||
if (!result)
|
||||
{
|
||||
ReportError(result.error(), manager);
|
||||
return 1;
|
||||
}
|
||||
|
||||
Program *program = *result;
|
||||
|
||||
Analyzer analyzer(manager);
|
||||
|
||||
const auto &analyzeResult = analyzer.Analyze(program);
|
||||
if (!analyzeResult)
|
||||
{
|
||||
ReportError(analyzeResult.error(), manager);
|
||||
return 1;
|
||||
}
|
||||
|
||||
std::cout << "Analyze successfully, PROGRAM OK\n";
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,147 +1,74 @@
|
||||
/*!
|
||||
@file src/Sema/Environment.hpp
|
||||
@brief 符号和作用域环境定义
|
||||
@author PuqiAR (im@puqiar.top)
|
||||
@date 2026-02-23
|
||||
@brief 树状符号表定义
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <Deps/Deps.hpp>
|
||||
#include <Error/Error.hpp>
|
||||
#include <Sema/Type.hpp>
|
||||
|
||||
#include <cassert>
|
||||
#include <optional>
|
||||
|
||||
namespace Fig
|
||||
{
|
||||
// 记录在 Analyzer 中的符号元数据
|
||||
enum class SymbolLocation
|
||||
{
|
||||
Global,
|
||||
Local,
|
||||
Upvalue
|
||||
};
|
||||
|
||||
struct Symbol
|
||||
{
|
||||
String name;
|
||||
TypeInfo *type;
|
||||
bool isPublic;
|
||||
int depth; // 词法作用域深度
|
||||
bool isConstant; // 是否是 const 声明的不可变常量 (用于报错: 尝试修改常量)
|
||||
String name;
|
||||
Type type;
|
||||
SymbolLocation location;
|
||||
int index;
|
||||
bool isConst;
|
||||
|
||||
int localId = -1; // Analyzer 虚拟槽位分配
|
||||
Symbol(String n, Type t, SymbolLocation l, int i, bool c) :
|
||||
name(std::move(n)), type(t), location(l), index(i), isConst(c)
|
||||
{
|
||||
}
|
||||
};
|
||||
|
||||
// 作用域回档水位线
|
||||
struct ScopeWatermark
|
||||
struct UpvalueCapture
|
||||
{
|
||||
std::size_t symbolCount;
|
||||
int savedLocalId;
|
||||
Symbol *target;
|
||||
int index;
|
||||
bool isLocal;
|
||||
};
|
||||
|
||||
// 语义分析函数上下文 (隔离局部变量 ID 空间)
|
||||
struct SemaFuncState
|
||||
struct Scope
|
||||
{
|
||||
SemaFuncState *enclosing = nullptr;
|
||||
int currentDepth = 0;
|
||||
int nextLocalId = 0;
|
||||
DynArray<ScopeWatermark> scopeStack;
|
||||
Scope *parent = nullptr;
|
||||
bool isFunctionBoundary = false;
|
||||
|
||||
HashMap<String, Symbol *> locals;
|
||||
DynArray<UpvalueCapture> upvalues;
|
||||
|
||||
int nextLocalId = 0;
|
||||
|
||||
Scope(Scope *p, bool isFn) : parent(p), isFunctionBoundary(isFn)
|
||||
{
|
||||
if (p && !isFn)
|
||||
nextLocalId = p->nextLocalId;
|
||||
}
|
||||
};
|
||||
|
||||
class Environment
|
||||
{
|
||||
private:
|
||||
DynArray<Symbol> symbols;
|
||||
SemaFuncState *current = nullptr;
|
||||
|
||||
public:
|
||||
Environment()
|
||||
Scope *current = nullptr;
|
||||
|
||||
void Push(bool isFn)
|
||||
{
|
||||
current = new SemaFuncState();
|
||||
current = new Scope(current, isFn);
|
||||
}
|
||||
|
||||
~Environment()
|
||||
void Pop()
|
||||
{
|
||||
while (current)
|
||||
{
|
||||
SemaFuncState *prev = current->enclosing;
|
||||
delete current;
|
||||
current = prev;
|
||||
}
|
||||
}
|
||||
|
||||
// 函数边界控
|
||||
|
||||
void EnterFunction()
|
||||
{
|
||||
SemaFuncState *newState = new SemaFuncState();
|
||||
newState->enclosing = current;
|
||||
current = newState;
|
||||
}
|
||||
|
||||
void LeaveFunction()
|
||||
{
|
||||
assert(current && "Environment: Unmatched LeaveFunction");
|
||||
SemaFuncState *oldState = current;
|
||||
current = oldState->enclosing;
|
||||
delete oldState;
|
||||
}
|
||||
|
||||
// 词法作用域控制
|
||||
|
||||
void EnterScope()
|
||||
{
|
||||
current->currentDepth++;
|
||||
current->scopeStack.push_back({symbols.size(), current->nextLocalId});
|
||||
}
|
||||
|
||||
void LeaveScope()
|
||||
{
|
||||
assert(current->currentDepth > 0 && "Environment: Unmatched LeaveScope");
|
||||
current->currentDepth--;
|
||||
|
||||
assert(!current->scopeStack.empty());
|
||||
ScopeWatermark archive = current->scopeStack.back();
|
||||
current->scopeStack.pop_back();
|
||||
|
||||
// 物理截断符号表,回滚槽位发号器以复用物理寄存器
|
||||
while (symbols.size() > archive.symbolCount)
|
||||
{
|
||||
symbols.pop_back();
|
||||
}
|
||||
current->nextLocalId = archive.savedLocalId;
|
||||
}
|
||||
|
||||
// 符号操作
|
||||
|
||||
// 注册符号, 返回分配的 localId。调用前内部执行同级作用域重定义断言
|
||||
int Define(const String &name, TypeInfo *type, bool isPublic, bool isConst)
|
||||
{
|
||||
for (auto it = symbols.rbegin(); it != symbols.rend(); ++it)
|
||||
{
|
||||
if (it->depth < current->currentDepth)
|
||||
break;
|
||||
if (it->name == name)
|
||||
{
|
||||
assert(false && "Environment.Define: redefinition");
|
||||
}
|
||||
}
|
||||
|
||||
int allocatedId = current->nextLocalId++;
|
||||
symbols.push_back({name, type, isPublic, current->currentDepth, isConst, allocatedId});
|
||||
return allocatedId;
|
||||
}
|
||||
|
||||
// 解析符号。找不到返回 nullopt
|
||||
std::optional<Symbol> Resolve(const String &name)
|
||||
{
|
||||
for (auto it = symbols.rbegin(); it != symbols.rend(); ++it)
|
||||
{
|
||||
if (it->name == name)
|
||||
return *it;
|
||||
}
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
int GetDepth() const
|
||||
{
|
||||
return current->currentDepth;
|
||||
Scope *old = current;
|
||||
current = current->parent;
|
||||
delete old;
|
||||
}
|
||||
};
|
||||
} // namespace Fig
|
||||
} // namespace Fig
|
||||
|
||||
93
src/Sema/Type.cpp
Normal file
93
src/Sema/Type.cpp
Normal file
@@ -0,0 +1,93 @@
|
||||
/*!
|
||||
@file src/Sema/Type.cpp
|
||||
@brief 类型系统实现
|
||||
*/
|
||||
|
||||
#include <Sema/Type.hpp>
|
||||
|
||||
namespace Fig
|
||||
{
|
||||
bool Type::is(TypeTag t) const
|
||||
{
|
||||
return base && base->tag == t;
|
||||
}
|
||||
|
||||
String Type::toString() const
|
||||
{
|
||||
if (!base)
|
||||
return "Unknown";
|
||||
if (base->tag == TypeTag::Function)
|
||||
{
|
||||
auto *ft = static_cast<FuncType *>(base);
|
||||
String sig = "func(";
|
||||
for (size_t i = 0; i < ft->paramTypes.size(); ++i)
|
||||
{
|
||||
sig += ft->paramTypes[i].toString();
|
||||
if (i < ft->paramTypes.size() - 1)
|
||||
sig += ", ";
|
||||
}
|
||||
sig += ") -> " + ft->retType.toString();
|
||||
return sig;
|
||||
}
|
||||
|
||||
String res = base->name;
|
||||
if (isNullable && base->tag != TypeTag::Null)
|
||||
res += "?";
|
||||
return res;
|
||||
}
|
||||
|
||||
bool Type::isAssignableTo(const Type &target) const
|
||||
{
|
||||
if (target.is(TypeTag::Any) || this->is(TypeTag::Any))
|
||||
return true; // Any 逃逸通道
|
||||
if (this->is(TypeTag::Null) && target.isNullable)
|
||||
return true; // Null 安全赋值
|
||||
return this->base == target.base && (!this->isNullable || target.isNullable); // 严格匹配
|
||||
}
|
||||
|
||||
TypeContext::TypeContext()
|
||||
{
|
||||
intType = new BaseType(TypeTag::Int, "Int");
|
||||
doubleType = new BaseType(TypeTag::Double, "Double");
|
||||
stringType = new BaseType(TypeTag::String, "String");
|
||||
boolType = new BaseType(TypeTag::Bool, "Bool");
|
||||
anyType = new BaseType(TypeTag::Any, "Any");
|
||||
nullType = new BaseType(TypeTag::Null, "Null");
|
||||
|
||||
allTypes.push_back(intType);
|
||||
allTypes.push_back(doubleType);
|
||||
allTypes.push_back(stringType);
|
||||
allTypes.push_back(boolType);
|
||||
allTypes.push_back(anyType);
|
||||
allTypes.push_back(nullType);
|
||||
}
|
||||
|
||||
TypeContext::~TypeContext()
|
||||
{
|
||||
for (auto t : allTypes)
|
||||
delete t;
|
||||
}
|
||||
|
||||
Type TypeContext::GetBasic(TypeTag tag, bool nullable)
|
||||
{
|
||||
BaseType *b = nullptr;
|
||||
switch (tag)
|
||||
{
|
||||
case TypeTag::Int: b = intType; break;
|
||||
case TypeTag::Double: b = doubleType; break;
|
||||
case TypeTag::String: b = stringType; break;
|
||||
case TypeTag::Bool: b = boolType; break;
|
||||
case TypeTag::Any: b = anyType; break;
|
||||
case TypeTag::Null: b = nullType; break;
|
||||
default: break;
|
||||
}
|
||||
return {b, nullable};
|
||||
}
|
||||
|
||||
Type TypeContext::CreateFuncType(DynArray<Type> params, Type ret)
|
||||
{
|
||||
auto *ft = new FuncType(std::move(params), ret);
|
||||
allTypes.push_back(ft);
|
||||
return Type{ft, false};
|
||||
}
|
||||
} // namespace Fig
|
||||
@@ -1,171 +1,115 @@
|
||||
/*!
|
||||
@file src/Sema/Type.hpp
|
||||
@brief 前端类型检查的类型定义和类型驻留池
|
||||
@author PuqiAR (im@puqiar.top)
|
||||
@date 2026-02-23
|
||||
@brief 类型系统定义:对齐 NaN-boxing 物理布局
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <Deps/Deps.hpp>
|
||||
#include <cstdint>
|
||||
#include <Error/Error.hpp>
|
||||
|
||||
namespace Fig
|
||||
{
|
||||
enum class TypeTag : std::uint8_t
|
||||
{
|
||||
Any, // 动态类型底线
|
||||
Null, // 空值
|
||||
Int,
|
||||
Double,
|
||||
Bool,
|
||||
String,
|
||||
Bool,
|
||||
Null,
|
||||
Any,
|
||||
Function,
|
||||
Struct,
|
||||
Interface
|
||||
};
|
||||
|
||||
struct TypeInfo
|
||||
class BaseType;
|
||||
|
||||
struct Type
|
||||
{
|
||||
BaseType *base = nullptr;
|
||||
bool isNullable = false;
|
||||
|
||||
bool operator==(const Type &other) const
|
||||
{
|
||||
return base == other.base && isNullable == other.isNullable;
|
||||
}
|
||||
bool operator!=(const Type &other) const
|
||||
{
|
||||
return !(*this == other);
|
||||
}
|
||||
|
||||
bool is(TypeTag tag) const;
|
||||
String toString() const;
|
||||
|
||||
bool isAssignableTo(const Type &target) const;
|
||||
};
|
||||
|
||||
class BaseType
|
||||
{
|
||||
public:
|
||||
TypeTag tag;
|
||||
String name; // 完整路径序列化, 如 Int, std.file.File
|
||||
String name;
|
||||
BaseType(TypeTag t, String n) : tag(t), name(std::move(n)) {}
|
||||
virtual ~BaseType() = default;
|
||||
};
|
||||
|
||||
bool isAny() const
|
||||
class FuncType : public BaseType
|
||||
{
|
||||
public:
|
||||
DynArray<Type> paramTypes;
|
||||
Type retType;
|
||||
FuncType(DynArray<Type> params, Type ret) :
|
||||
BaseType(TypeTag::Function, "Function"), paramTypes(std::move(params)), retType(ret)
|
||||
{
|
||||
return tag == TypeTag::Any;
|
||||
}
|
||||
|
||||
bool isNull() const
|
||||
{
|
||||
return tag == TypeTag::Null;
|
||||
}
|
||||
|
||||
bool isInt() const
|
||||
{
|
||||
return tag == TypeTag::Int;
|
||||
}
|
||||
|
||||
bool isDouble() const
|
||||
{
|
||||
return tag == TypeTag::Double;
|
||||
}
|
||||
|
||||
bool isBool() const
|
||||
{
|
||||
return tag == TypeTag::Bool;
|
||||
}
|
||||
|
||||
bool isString() const
|
||||
{
|
||||
return tag == TypeTag::String;
|
||||
}
|
||||
|
||||
bool isFunction() const
|
||||
{
|
||||
return tag == TypeTag::Function;
|
||||
}
|
||||
|
||||
bool isStruct() const
|
||||
{
|
||||
return tag == TypeTag::Struct;
|
||||
}
|
||||
};
|
||||
|
||||
// 全局唯一类型驻留池
|
||||
class StructType : public BaseType
|
||||
{
|
||||
public:
|
||||
struct Field
|
||||
{
|
||||
String name;
|
||||
Type type;
|
||||
bool isPublic;
|
||||
int index;
|
||||
};
|
||||
DynArray<Field> fields;
|
||||
HashMap<String, size_t> fieldMap;
|
||||
HashMap<String, class FnDefStmt *> methods;
|
||||
|
||||
StructType(String n) : BaseType(TypeTag::Struct, std::move(n)) {}
|
||||
void AddField(String name, Type type, bool isPublic)
|
||||
{
|
||||
size_t idx = fields.size();
|
||||
fields.push_back({name, type, isPublic, (int) idx});
|
||||
fieldMap[name] = idx;
|
||||
}
|
||||
};
|
||||
|
||||
class InterfaceType : public BaseType
|
||||
{
|
||||
public:
|
||||
struct MethodSig
|
||||
{
|
||||
String name;
|
||||
DynArray<Type> params;
|
||||
Type retType;
|
||||
};
|
||||
HashMap<String, MethodSig> methods;
|
||||
InterfaceType(String n) : BaseType(TypeTag::Interface, std::move(n)) {}
|
||||
};
|
||||
|
||||
class TypeContext
|
||||
{
|
||||
private:
|
||||
DynArray<TypeInfo *> allTypes;
|
||||
|
||||
// 缓存
|
||||
TypeInfo *typeAny;
|
||||
TypeInfo *typeNull;
|
||||
TypeInfo *typeInt;
|
||||
TypeInfo *typeDouble;
|
||||
TypeInfo *typeBool;
|
||||
TypeInfo *typeString;
|
||||
TypeInfo *typeFunction;
|
||||
TypeInfo *typeStruct;
|
||||
|
||||
public:
|
||||
TypeInfo *GetAny()
|
||||
{
|
||||
return typeAny;
|
||||
}
|
||||
TypeInfo *GetNull()
|
||||
{
|
||||
return typeNull;
|
||||
}
|
||||
TypeInfo *GetInt()
|
||||
{
|
||||
return typeInt;
|
||||
}
|
||||
TypeInfo *GetDouble()
|
||||
{
|
||||
return typeDouble;
|
||||
}
|
||||
TypeInfo *GetBool()
|
||||
{
|
||||
return typeBool;
|
||||
}
|
||||
TypeInfo *GetString()
|
||||
{
|
||||
return typeString;
|
||||
}
|
||||
TypeInfo *GetFunction()
|
||||
{
|
||||
return typeFunction;
|
||||
}
|
||||
TypeInfo *GetStruct()
|
||||
{
|
||||
return typeStruct;
|
||||
}
|
||||
DynArray<BaseType *> allTypes;
|
||||
BaseType *intType, *doubleType, *stringType, *boolType, *anyType, *nullType;
|
||||
|
||||
TypeInfo *ResolveTypePath(const String &fullName)
|
||||
{
|
||||
for (auto *t : allTypes)
|
||||
{
|
||||
if (t->name == fullName)
|
||||
return t;
|
||||
}
|
||||
return nullptr; // 没找到该类型
|
||||
}
|
||||
|
||||
TypeInfo *ResolveTypePath(const DynArray<String> &path)
|
||||
{
|
||||
// TODO: 支持Module 系统, 查 Module 的导出表
|
||||
String fullName = path.empty() ? "" : path[0];
|
||||
for (size_t i = 1; i < path.size(); ++i)
|
||||
{
|
||||
fullName += "." + path[i];
|
||||
}
|
||||
|
||||
return ResolveTypePath(fullName);
|
||||
}
|
||||
|
||||
~TypeContext()
|
||||
{
|
||||
for (TypeInfo *t : allTypes)
|
||||
delete t;
|
||||
}
|
||||
|
||||
TypeContext()
|
||||
{
|
||||
typeAny = createBuiltin(TypeTag::Any, "Any");
|
||||
typeNull = createBuiltin(TypeTag::Null, "Null");
|
||||
typeInt = createBuiltin(TypeTag::Int, "Int");
|
||||
typeDouble = createBuiltin(TypeTag::Double, "Double");
|
||||
typeBool = createBuiltin(TypeTag::Bool, "Bool");
|
||||
typeString = createBuiltin(TypeTag::String, "String");
|
||||
typeFunction = createBuiltin(TypeTag::Function, "Function");
|
||||
typeStruct = createBuiltin(TypeTag::Struct, "Struct");
|
||||
}
|
||||
|
||||
private:
|
||||
TypeInfo *createBuiltin(TypeTag tag, String name)
|
||||
{
|
||||
TypeInfo *t = new TypeInfo{tag, std::move(name)};
|
||||
allTypes.push_back(t);
|
||||
return t;
|
||||
}
|
||||
TypeContext();
|
||||
~TypeContext();
|
||||
|
||||
Type GetBasic(TypeTag tag, bool nullable = false);
|
||||
Type CreateFuncType(DynArray<Type> params, Type ret);
|
||||
};
|
||||
}; // namespace Fig
|
||||
} // namespace Fig
|
||||
|
||||
@@ -36,7 +36,7 @@ namespace Fig
|
||||
|
||||
~Arena()
|
||||
{
|
||||
// 1. 逆序调用析构函数
|
||||
// 逆序调用析构函数
|
||||
DestructorNode *node = destructorHead;
|
||||
while (node)
|
||||
{
|
||||
@@ -44,7 +44,7 @@ namespace Fig
|
||||
node = node->next;
|
||||
}
|
||||
|
||||
// 2. 释放所有分配的内存块
|
||||
// 释放所有分配的内存块
|
||||
for (char *chunk : chunks)
|
||||
{
|
||||
delete[] chunk;
|
||||
|
||||
@@ -1,13 +1,11 @@
|
||||
/*!
|
||||
@file src/VM/VM.cpp
|
||||
@brief 虚拟机核心执行引擎实现
|
||||
@author PuqiAR (im@puqiar.top)
|
||||
@date 2026-02-19
|
||||
*/
|
||||
|
||||
#include <Core/Core.hpp>
|
||||
#include <VM/VM.hpp>
|
||||
|
||||
// Computed GOTO!!!
|
||||
#define BINARY_ARITHMETIC_OP(opName, op) \
|
||||
do_##opName: \
|
||||
{ \
|
||||
@@ -83,11 +81,11 @@ namespace Fig
|
||||
Result<Value, Error> VM::Execute(CompiledModule *compiledModule)
|
||||
{
|
||||
Proto *entry = compiledModule->protos[0];
|
||||
pushFrame(entry, registers);
|
||||
(void) pushFrame(entry, registers); // 刚开始执行寄存器不会溢出
|
||||
|
||||
// 🔥 必须与 Bytecode.hpp 中的 OpCode 枚举严格一一对应!
|
||||
static const void *dispatchTable[] = {
|
||||
&&do_Exit,
|
||||
// 对齐 Bytecode.hpp 中的 OpCode 顺序
|
||||
static const void *dispatchTable[] = {&&do_Exit,
|
||||
&&do_Exit_MaxRecursionDepthExceeded,
|
||||
|
||||
&&do_LoadK,
|
||||
&&do_LoadTrue,
|
||||
@@ -123,11 +121,17 @@ namespace Fig
|
||||
&&do_Less,
|
||||
&&do_GreaterEqual,
|
||||
&&do_LessEqual,
|
||||
|
||||
&&do_GetGlobal,
|
||||
&&do_SetGlobal,
|
||||
&&do_GetUpval,
|
||||
&&do_SetUpval,
|
||||
&&do_Copy,
|
||||
|
||||
&&do_Count};
|
||||
|
||||
Instruction inst;
|
||||
|
||||
// 取指 -> 直接查表并 Jump
|
||||
#define DISPATCH() \
|
||||
do \
|
||||
{ \
|
||||
@@ -139,7 +143,15 @@ namespace Fig
|
||||
DISPATCH();
|
||||
|
||||
do_Exit: {
|
||||
[[unlikely]] return Value::GetNullInstance();
|
||||
return Value::FromInt(decodeSBx(inst));
|
||||
}
|
||||
|
||||
do_Exit_MaxRecursionDepthExceeded: {
|
||||
CoreIO::GetStdErr() << std::format(
|
||||
"Oops! max recursion depth limit {} exceeded in Fn `{}` , exiting...\n",
|
||||
MAX_RECURSION_DEPTH,
|
||||
(currentFrame - 1)->proto->name); // pushFrame失败了,但currentFrame仍然移动,所以 (currentFrame - 1)是 lastFrame
|
||||
std::exit(static_cast<int>(MAX_RECURSION_DEPTH));
|
||||
}
|
||||
|
||||
do_LoadK: {
|
||||
@@ -171,7 +183,9 @@ namespace Fig
|
||||
std::uint8_t a = decodeA(inst);
|
||||
Proto *proto = compiledModule->protos[a];
|
||||
std::uint8_t baseReg = decodeB(inst);
|
||||
pushFrame(proto, currentFrame->registerBase + baseReg);
|
||||
|
||||
currentFrame->ip = pushFrame(proto, currentFrame->registerBase + baseReg);
|
||||
|
||||
DISPATCH();
|
||||
}
|
||||
|
||||
@@ -181,16 +195,18 @@ namespace Fig
|
||||
}
|
||||
|
||||
do_Return: {
|
||||
std::uint8_t a = decodeA(inst);
|
||||
*currentFrame->registerBase = currentFrame->registerBase[a];
|
||||
std::uint8_t a = decodeA(inst);
|
||||
Value retVal = currentFrame->registerBase[a];
|
||||
|
||||
// 此时 registerBase[0] 指向的是 Caller 的 baseReg 槽位
|
||||
|
||||
currentFrame->registerBase[0] = retVal;
|
||||
popFrame();
|
||||
|
||||
DISPATCH();
|
||||
}
|
||||
|
||||
do_LoadFn: {
|
||||
// std::uint8_t a = decodeA(inst);
|
||||
// std::uint16_t bx = decodeBx(inst);
|
||||
// TODO: R[a] = new FunctionObject(compiledModule->protos[bx])
|
||||
DISPATCH();
|
||||
}
|
||||
|
||||
@@ -272,7 +288,8 @@ namespace Fig
|
||||
Value l = currentFrame->registerBase[b];
|
||||
Value r = currentFrame->registerBase[c];
|
||||
|
||||
currentFrame->registerBase[a] = Value::FromDouble(l.AsInt() + r.AsInt());
|
||||
currentFrame->registerBase[a] =
|
||||
Value::FromDouble(static_cast<double>(l.AsInt()) / r.AsInt());
|
||||
DISPATCH();
|
||||
}
|
||||
|
||||
@@ -283,10 +300,40 @@ namespace Fig
|
||||
BINARY_COMPARE_OP(GreaterEqual, >=);
|
||||
BINARY_COMPARE_OP(LessEqual, <=);
|
||||
|
||||
do_GetGlobal: {
|
||||
std::uint8_t a = decodeA(inst);
|
||||
std::uint16_t bx = decodeBx(inst);
|
||||
currentFrame->registerBase[a] = globals[bx];
|
||||
DISPATCH();
|
||||
}
|
||||
|
||||
do_SetGlobal: {
|
||||
std::uint8_t a = decodeA(inst);
|
||||
std::uint16_t bx = decodeBx(inst);
|
||||
globals[bx] = currentFrame->registerBase[a];
|
||||
DISPATCH();
|
||||
}
|
||||
|
||||
do_GetUpval: {
|
||||
assert(false && "VM: GetUpval requires FunctionObject (Closure) implementation");
|
||||
DISPATCH();
|
||||
}
|
||||
|
||||
do_SetUpval: {
|
||||
assert(false && "VM: SetUpval requires FunctionObject (Closure) implementation");
|
||||
DISPATCH();
|
||||
}
|
||||
|
||||
do_Copy: {
|
||||
std::uint8_t a = decodeA(inst);
|
||||
std::uint8_t b = decodeB(inst);
|
||||
currentFrame->registerBase[a] = currentFrame->registerBase[b];
|
||||
DISPATCH();
|
||||
}
|
||||
|
||||
do_Count: {
|
||||
assert(false && "Hit Count sentinel!");
|
||||
return Value::GetNullInstance();
|
||||
}
|
||||
|
||||
}
|
||||
}; // namespace Fig
|
||||
}; // namespace Fig
|
||||
|
||||
@@ -31,13 +31,20 @@ namespace Fig
|
||||
class VM
|
||||
{
|
||||
private:
|
||||
static constexpr unsigned int MAX_REGISTERS = 1024;
|
||||
static constexpr unsigned int MAX_REGISTERS = 1024;
|
||||
static constexpr unsigned int MAX_GLOBALS = 65536;
|
||||
static constexpr unsigned int MAX_RECURSION_DEPTH = 2233;
|
||||
|
||||
Instruction POISON_MAX_RECURSION_DEPTH_EXCEED_INST;
|
||||
|
||||
// 一次性分配
|
||||
Value registers[MAX_REGISTERS];
|
||||
Value globals[MAX_GLOBALS];
|
||||
|
||||
DynArray<CallFrame> frames;
|
||||
CallFrame frames[MAX_RECURSION_DEPTH];
|
||||
CallFrame *currentFrame;
|
||||
CallFrame *frameLimit;
|
||||
|
||||
public:
|
||||
VM()
|
||||
{
|
||||
@@ -45,27 +52,36 @@ namespace Fig
|
||||
{
|
||||
registers[i] = Value::GetNullInstance();
|
||||
}
|
||||
for (unsigned int i = 0; i < MAX_GLOBALS; ++i)
|
||||
{
|
||||
globals[i] = Value::GetNullInstance();
|
||||
}
|
||||
|
||||
currentFrame = frames;
|
||||
frameLimit = frames + MAX_RECURSION_DEPTH - 1;
|
||||
|
||||
POISON_MAX_RECURSION_DEPTH_EXCEED_INST =
|
||||
Op::iAsBx(OpCode::Exit_MaxRecursionDepthExceeded, 0, 0);
|
||||
}
|
||||
|
||||
private:
|
||||
|
||||
void pushFrame(Proto *proto, Value *base)
|
||||
[[nodiscard]]
|
||||
inline Instruction *pushFrame(Proto *proto, Value *base)
|
||||
{
|
||||
frames.push_back({
|
||||
proto,
|
||||
proto->code.data(),
|
||||
base
|
||||
});
|
||||
currentFrame = &frames.back();
|
||||
if (++currentFrame >= frameLimit) [[unlikely]] // 达到最大递归层数
|
||||
{
|
||||
POISON_MAX_RECURSION_DEPTH_EXCEED_INST =
|
||||
Op::iAsBx(OpCode::Exit_MaxRecursionDepthExceeded, 0, 0);
|
||||
return &POISON_MAX_RECURSION_DEPTH_EXCEED_INST;
|
||||
}
|
||||
|
||||
*currentFrame = CallFrame{proto, proto->code.data(), base};
|
||||
return currentFrame->ip;
|
||||
}
|
||||
|
||||
void popFrame()
|
||||
inline void popFrame()
|
||||
{
|
||||
frames.pop_back();
|
||||
if (!frames.empty())
|
||||
{
|
||||
currentFrame = &frames.back();
|
||||
}
|
||||
--currentFrame;
|
||||
}
|
||||
|
||||
inline OpCode decodeOpCode(Instruction inst)
|
||||
|
||||
70
src/main.cpp
70
src/main.cpp
@@ -1,3 +1,4 @@
|
||||
#include <Bytecode/Disassembler.hpp>
|
||||
#include <Compiler/Compiler.hpp>
|
||||
#include <Core/Core.hpp>
|
||||
#include <Deps/Deps.hpp>
|
||||
@@ -7,12 +8,10 @@
|
||||
#include <SourceManager/SourceManager.hpp>
|
||||
#include <VM/VM.hpp>
|
||||
|
||||
|
||||
#include <chrono>
|
||||
#include <iostream>
|
||||
#include <print>
|
||||
|
||||
|
||||
int main()
|
||||
{
|
||||
using namespace Fig;
|
||||
@@ -25,68 +24,53 @@ int main()
|
||||
|
||||
if (!manager.read)
|
||||
{
|
||||
std::cerr << "Couldn't read file";
|
||||
std::cerr << "CRITICAL: Could not read source file: " << filePath << "\n";
|
||||
return 1;
|
||||
}
|
||||
|
||||
Lexer lexer(manager.GetSource(), fileName);
|
||||
Parser parser(lexer, manager, fileName);
|
||||
|
||||
const auto &program_result = parser.Parse();
|
||||
if (!program_result)
|
||||
auto pRes = parser.Parse();
|
||||
if (!pRes)
|
||||
{
|
||||
ReportError(program_result.error(), manager);
|
||||
ReportError(pRes.error(), manager);
|
||||
return 1;
|
||||
}
|
||||
Program *program = *program_result;
|
||||
Program *program = *pRes;
|
||||
|
||||
Analyzer analyzer(manager);
|
||||
const auto &analyzeResult = analyzer.Analyze(program);
|
||||
if (!analyzeResult)
|
||||
Analyzer analyzer(manager);
|
||||
auto aRes = analyzer.Analyze(program);
|
||||
if (!aRes)
|
||||
{
|
||||
ReportError(analyzeResult.error(), manager);
|
||||
ReportError(aRes.error(), manager);
|
||||
return 1;
|
||||
}
|
||||
std::cout << "analyzer: Program OK, PASSED\n";
|
||||
std::cout << "Analyzer: Program OK\n";
|
||||
|
||||
Compiler compiler(fileName, manager);
|
||||
const auto &comp_result = compiler.Compile(program);
|
||||
if (!comp_result)
|
||||
Diagnostics diag;
|
||||
Compiler compiler(manager, diag);
|
||||
auto cRes = compiler.Compile(program);
|
||||
if (!cRes)
|
||||
{
|
||||
ReportError(comp_result.error(), manager);
|
||||
ReportError(cRes.error(), manager);
|
||||
return 1;
|
||||
}
|
||||
|
||||
CompiledModule *compiledModule = *comp_result;
|
||||
|
||||
size_t cnt = 0;
|
||||
for (Proto *proto : compiledModule->protos)
|
||||
{
|
||||
std::cout << "\n"
|
||||
<< "Proto: " << cnt++ << '\n';
|
||||
std::cout << " Constant Pool" << '\n';
|
||||
for (size_t i = 0; i < proto->constants.size(); ++i)
|
||||
{
|
||||
std::print("[{}] {}\n", i, proto->constants[i].ToString());
|
||||
}
|
||||
CompiledModule *compiledModule = *cRes;
|
||||
|
||||
DumpCode(proto->code);
|
||||
Disassembler::DisassembleModule(compiledModule);
|
||||
|
||||
std::cout << "\nMax Stack Size: " << (int) proto->maxStack << std::endl;
|
||||
}
|
||||
|
||||
VM vm;
|
||||
|
||||
using Clock = std::chrono::high_resolution_clock;
|
||||
|
||||
Clock clock;
|
||||
|
||||
auto start = clock.now();
|
||||
|
||||
std::cout << "\n--- VM Execution Start ---\n";
|
||||
auto start = clock.now();
|
||||
auto result_ = vm.Execute(compiledModule);
|
||||
auto end = clock.now();
|
||||
|
||||
auto end = clock.now();
|
||||
auto duration = end - start;
|
||||
auto duration = std::chrono::duration_cast<std::chrono::milliseconds>(end - start);
|
||||
|
||||
if (!result_)
|
||||
{
|
||||
@@ -94,9 +78,9 @@ int main()
|
||||
return 1;
|
||||
}
|
||||
|
||||
Value result = *result_;
|
||||
std::cout << "result: " << result.ToString() << "\n";
|
||||
std::cout << "execution cost: " << std::chrono::duration_cast<std::chrono::milliseconds>(duration).count() << "ms\n";
|
||||
|
||||
std::cout << "Result: " << (*result_).ToString() << "\n";
|
||||
std::cout << "Execution Cost: " << duration.count() << "ms\n";
|
||||
|
||||
vm.PrintRegisters();
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
9
tests/Compiler/test_basic.fig
Normal file
9
tests/Compiler/test_basic.fig
Normal file
@@ -0,0 +1,9 @@
|
||||
var x = 1_000;
|
||||
var y = 0x20;
|
||||
var z = x + y;
|
||||
|
||||
func fib(n: Int) -> Int {
|
||||
if n < 2 { return n; }
|
||||
return fib(n - 1) + fib(n - 2);
|
||||
}
|
||||
|
||||
3
tests/Sema/err_control_flow.fig
Normal file
3
tests/Sema/err_control_flow.fig
Normal file
@@ -0,0 +1,3 @@
|
||||
func main() {
|
||||
break; // 错误:break 不在循环内
|
||||
}
|
||||
4
tests/Sema/err_redeclare.fig
Normal file
4
tests/Sema/err_redeclare.fig
Normal file
@@ -0,0 +1,4 @@
|
||||
func main() {
|
||||
var x = 10;
|
||||
var x = 20; // 错误:x 重复定义
|
||||
}
|
||||
4
tests/Sema/err_struct_field.fig
Normal file
4
tests/Sema/err_struct_field.fig
Normal file
@@ -0,0 +1,4 @@
|
||||
struct Point { x: Int, y: Int }
|
||||
func main() {
|
||||
var p = new Point{ x: 1, z: 2 }; // 错误:Point 没有字段 z
|
||||
}
|
||||
4
tests/Sema/err_undeclared.fig
Normal file
4
tests/Sema/err_undeclared.fig
Normal file
@@ -0,0 +1,4 @@
|
||||
func main() {
|
||||
var x = 10;
|
||||
io.println(y); // 错误:y 未定义
|
||||
}
|
||||
32
xmake.lua
32
xmake.lua
@@ -13,11 +13,6 @@ elseif is_plat("windows") then
|
||||
-- 2. local dev (Windows + llvm-mingw)
|
||||
set_toolchains("mingw") -- llvm-mingw
|
||||
add_ldflags("-Wl,--stack,268435456")
|
||||
-- set_toolchains("clang")
|
||||
-- static lib
|
||||
-- add_ldflags("-target x86_64-w64-mingw32", "-static")
|
||||
-- add_cxxflags("-stdlib=libc++")
|
||||
-- add_ldflags("-stdlib=libc++")
|
||||
end
|
||||
|
||||
set_languages("c++23")
|
||||
@@ -33,7 +28,6 @@ target("LexerTest")
|
||||
add_files("src/Token/Token.cpp")
|
||||
add_files("src/Error/Error.cpp")
|
||||
add_files("src/Lexer/Lexer.cpp")
|
||||
|
||||
add_files("src/Lexer/LexerTest.cpp")
|
||||
|
||||
target("ParserTest")
|
||||
@@ -41,13 +35,11 @@ target("ParserTest")
|
||||
add_files("src/Token/Token.cpp")
|
||||
add_files("src/Error/Error.cpp")
|
||||
add_files("src/Lexer/Lexer.cpp")
|
||||
|
||||
add_files("src/Ast/Operator.cpp")
|
||||
add_files("src/Parser/ExprParser.cpp")
|
||||
add_files("src/Parser/StmtParser.cpp")
|
||||
add_files("src/Parser/TypeExprParser.cpp")
|
||||
add_files("src/Parser/Parser.cpp")
|
||||
|
||||
add_files("src/Parser/ParserTest.cpp")
|
||||
|
||||
target("ObjectTest")
|
||||
@@ -59,13 +51,12 @@ target("AnalyzerTest")
|
||||
add_files("src/Token/Token.cpp")
|
||||
add_files("src/Error/Error.cpp")
|
||||
add_files("src/Lexer/Lexer.cpp")
|
||||
|
||||
add_files("src/Ast/Operator.cpp")
|
||||
add_files("src/Parser/ExprParser.cpp")
|
||||
add_files("src/Parser/StmtParser.cpp")
|
||||
add_files("src/Parser/TypeExprParser.cpp")
|
||||
add_files("src/Parser/Parser.cpp")
|
||||
|
||||
add_files("src/Sema/Type.cpp")
|
||||
add_files("src/Sema/Analyzer.cpp")
|
||||
add_files("src/Sema/AnalyzerTest.cpp")
|
||||
|
||||
@@ -74,21 +65,18 @@ target("CompilerTest")
|
||||
add_files("src/Token/Token.cpp")
|
||||
add_files("src/Error/Error.cpp")
|
||||
add_files("src/Lexer/Lexer.cpp")
|
||||
|
||||
add_files("src/Ast/Operator.cpp")
|
||||
add_files("src/Bytecode/Disassembler.cpp")
|
||||
add_files("src/Parser/ExprParser.cpp")
|
||||
add_files("src/Parser/StmtParser.cpp")
|
||||
add_files("src/Parser/TypeExprParser.cpp")
|
||||
add_files("src/Parser/Parser.cpp")
|
||||
|
||||
add_files("src/Object/Object.cpp")
|
||||
|
||||
add_files("src/Sema/Type.cpp")
|
||||
add_files("src/Sema/Analyzer.cpp")
|
||||
|
||||
add_files("src/Compiler/ExprCompiler.cpp")
|
||||
add_files("src/Compiler/StmtCompiler.cpp")
|
||||
add_files("src/Compiler/Compiler.cpp")
|
||||
|
||||
add_files("src/Compiler/CompileTest.cpp")
|
||||
|
||||
target("LSP")
|
||||
@@ -96,17 +84,14 @@ target("LSP")
|
||||
add_files("src/Token/Token.cpp")
|
||||
add_files("src/Error/Error.cpp")
|
||||
add_files("src/Lexer/Lexer.cpp")
|
||||
|
||||
add_files("src/Ast/Operator.cpp")
|
||||
add_files("src/Parser/ExprParser.cpp")
|
||||
add_files("src/Parser/StmtParser.cpp")
|
||||
add_files("src/Parser/TypeExprParser.cpp")
|
||||
add_files("src/Parser/Parser.cpp")
|
||||
|
||||
add_files("src/Sema/Type.cpp")
|
||||
add_files("src/Sema/Analyzer.cpp")
|
||||
|
||||
add_files("src/LSP/LSPServer.cpp")
|
||||
|
||||
set_filename("Fig-LSP")
|
||||
|
||||
target("Fig")
|
||||
@@ -114,20 +99,17 @@ target("Fig")
|
||||
add_files("src/Token/Token.cpp")
|
||||
add_files("src/Error/Error.cpp")
|
||||
add_files("src/Lexer/Lexer.cpp")
|
||||
|
||||
add_files("src/Ast/Operator.cpp")
|
||||
add_files("src/Bytecode/Disassembler.cpp")
|
||||
add_files("src/Parser/ExprParser.cpp")
|
||||
add_files("src/Parser/StmtParser.cpp")
|
||||
add_files("src/Parser/TypeExprParser.cpp")
|
||||
add_files("src/Parser/Parser.cpp")
|
||||
|
||||
add_files("src/Object/Object.cpp")
|
||||
|
||||
add_files("src/Sema/Type.cpp")
|
||||
add_files("src/Sema/Analyzer.cpp")
|
||||
|
||||
add_files("src/Compiler/ExprCompiler.cpp")
|
||||
add_files("src/Compiler/StmtCompiler.cpp")
|
||||
add_files("src/Compiler/Compiler.cpp")
|
||||
|
||||
add_files("src/VM/VM.cpp")
|
||||
add_files("src/main.cpp")
|
||||
add_files("src/main.cpp")
|
||||
|
||||
Reference in New Issue
Block a user