Compare commits
2 Commits
91e4eb734e
...
0f635ccf2b
| Author | SHA1 | Date | |
|---|---|---|---|
| 0f635ccf2b | |||
| 90448006ff |
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
|
@file src/Ast/Base.hpp
|
||||||
@brief AstNode基类定义
|
@brief AstNode基类定义
|
||||||
@author PuqiAR (im@puqiar.top)
|
@author PuqiAR (im@puqiar.top)
|
||||||
@date 2026-02-14
|
@date 2026-03-08
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
#include <Core/SourceLocations.hpp>
|
#include <Core/SourceLocations.hpp>
|
||||||
#include <Deps/Deps.hpp>
|
#include <Deps/Deps.hpp>
|
||||||
|
|
||||||
#include <Sema/Type.hpp>
|
#include <Sema/Type.hpp>
|
||||||
|
|
||||||
#include <cstdint>
|
#include <cstdint>
|
||||||
|
|
||||||
namespace Fig
|
namespace Fig
|
||||||
{
|
{
|
||||||
enum class AstType : std::uint8_t
|
enum class AstType : std::uint8_t
|
||||||
{
|
{
|
||||||
AstNode, // 基类
|
AstNode,
|
||||||
Program, // 程序
|
Program,
|
||||||
Expr, // 表达式
|
Expr,
|
||||||
Stmt, // 语句
|
Stmt,
|
||||||
BlockStmt, // 块语句
|
BlockStmt,
|
||||||
|
|
||||||
/* Expressions */
|
/* Expressions */
|
||||||
IdentiExpr, // 标识符表达式
|
IdentiExpr,
|
||||||
LiteralExpr, // 字面量表达式
|
LiteralExpr,
|
||||||
PrefixExpr, // 一元 前缀表达式
|
PrefixExpr,
|
||||||
InfixExpr, // 二元 中缀表达式
|
InfixExpr,
|
||||||
|
IndexExpr,
|
||||||
IndexExpr, // 后缀表达式,索引
|
CallExpr,
|
||||||
CallExpr, // 后缀表达式,函数调用
|
MemberExpr, // obj.prop
|
||||||
|
ObjectInitExpr, // new Point{}
|
||||||
|
|
||||||
/* Statements */
|
/* Statements */
|
||||||
ExprStmt, // 表达式语句,如 println(1)
|
ExprStmt,
|
||||||
VarDecl, // 变量声明
|
VarDecl,
|
||||||
IfStmt, // If语句
|
IfStmt,
|
||||||
ElseIfStmt, // ElseIf语句,不准悬空,平铺式else if
|
ElseIfStmt,
|
||||||
WhileStmt, // while语句
|
WhileStmt,
|
||||||
FnDefStmt, // func函数定义语句
|
FnDefStmt,
|
||||||
ReturnStmt, // 返回语句
|
StructDefStmt,
|
||||||
BreakStmt, // break语句
|
InterfaceDefStmt,
|
||||||
ContinueStmt, // continue语句
|
ImplStmt, // impl Document for File {}
|
||||||
|
ReturnStmt,
|
||||||
|
BreakStmt,
|
||||||
|
ContinueStmt,
|
||||||
|
|
||||||
/* Type Expressions */
|
/* Type Expressions */
|
||||||
TypeExpr, // 基类
|
TypeExpr,
|
||||||
NamedTypeExpr, // 命名类型,支持namespace, std.file这样的
|
NamedTypeExpr,
|
||||||
// 泛型等...
|
NullableTypeExpr
|
||||||
};
|
};
|
||||||
|
|
||||||
struct AstNode
|
struct AstNode
|
||||||
{
|
{
|
||||||
AstType type = AstType::AstNode;
|
AstType type = AstType::AstNode;
|
||||||
@@ -66,13 +69,10 @@ namespace Fig
|
|||||||
virtual ~TypeExpr() = default;
|
virtual ~TypeExpr() = default;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct Program;
|
|
||||||
|
|
||||||
struct Expr : public AstNode
|
struct Expr : public AstNode
|
||||||
{
|
{
|
||||||
TypeInfo *resolvedType = nullptr;
|
// 语义分析后填充
|
||||||
// TODO: 可选的常量折叠
|
Type resolvedType;
|
||||||
// 拓展 isConstExpr和 constValue槽位
|
|
||||||
|
|
||||||
Expr()
|
Expr()
|
||||||
{
|
{
|
||||||
@@ -82,7 +82,7 @@ namespace Fig
|
|||||||
|
|
||||||
struct Stmt : public AstNode
|
struct Stmt : public AstNode
|
||||||
{
|
{
|
||||||
bool isPublic;
|
bool isPublic = false;
|
||||||
Stmt()
|
Stmt()
|
||||||
{
|
{
|
||||||
type = AstType::Stmt;
|
type = AstType::Stmt;
|
||||||
@@ -92,22 +92,10 @@ namespace Fig
|
|||||||
struct Program final : public AstNode
|
struct Program final : public AstNode
|
||||||
{
|
{
|
||||||
DynArray<Stmt *> nodes;
|
DynArray<Stmt *> nodes;
|
||||||
|
|
||||||
Program()
|
Program()
|
||||||
{
|
{
|
||||||
type = AstType::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
|
virtual String toString() const override
|
||||||
{
|
{
|
||||||
return "<Program>";
|
return "<Program>";
|
||||||
@@ -121,36 +109,9 @@ namespace Fig
|
|||||||
{
|
{
|
||||||
type = AstType::BlockStmt;
|
type = AstType::BlockStmt;
|
||||||
}
|
}
|
||||||
BlockStmt(DynArray<Stmt *> _nodes)
|
|
||||||
{
|
|
||||||
type = AstType::BlockStmt;
|
|
||||||
nodes = std::move(_nodes);
|
|
||||||
if (!_nodes.empty())
|
|
||||||
{
|
|
||||||
location = std::move(_nodes.back()->location);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
virtual String toString() const override
|
virtual String toString() const override
|
||||||
{
|
{
|
||||||
return "<BlockStmt>";
|
return "<BlockStmt>";
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
}; // namespace Fig
|
} // 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
|
|
||||||
|
|||||||
@@ -1,48 +1,32 @@
|
|||||||
/*!
|
/*!
|
||||||
@file src/Ast/Expr/IdentiExpr.hpp
|
@file src/Ast/Expr/IdentiExpr.hpp
|
||||||
@brief IdentiExpr定义
|
@brief 标识符表达式定义
|
||||||
@author PuqiAR (im@puqiar.top)
|
|
||||||
@date 2026-02-14
|
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include <Ast/Base.hpp>
|
#include <Ast/Base.hpp>
|
||||||
#include <Deps/Deps.hpp>
|
#include <Sema/Environment.hpp>
|
||||||
|
|
||||||
namespace Fig
|
namespace Fig
|
||||||
{
|
{
|
||||||
struct IdentiExpr final : Expr
|
struct IdentiExpr final : public Expr
|
||||||
{
|
{
|
||||||
String name;
|
String name;
|
||||||
|
Symbol *resolvedSymbol = nullptr; // 语义分析后填充,Compiler 唯一的依赖
|
||||||
// Analyzer槽位
|
|
||||||
|
|
||||||
// 寻址空间
|
|
||||||
bool isGlobal = false; // 是否全局, 全局变量存哈希/堆
|
|
||||||
|
|
||||||
// 仅 isGlobal = false 有效
|
|
||||||
int resolvedDepth = -1; // 用于获取闭包上值, -1 代表未解析
|
|
||||||
|
|
||||||
// 栈内槽位
|
|
||||||
int localId = -1; // 局部变量id, -1 未解析
|
|
||||||
|
|
||||||
|
|
||||||
IdentiExpr()
|
IdentiExpr()
|
||||||
{
|
{
|
||||||
type = AstType::IdentiExpr;
|
type = AstType::IdentiExpr;
|
||||||
}
|
}
|
||||||
|
IdentiExpr(String _name, SourceLocation _location) : name(std::move(_name))
|
||||||
IdentiExpr(String _name, SourceLocation _loc)
|
|
||||||
{
|
{
|
||||||
type = AstType::IdentiExpr;
|
type = AstType::IdentiExpr;
|
||||||
name = std::move(_name);
|
location = std::move(_location);
|
||||||
location = std::move(_loc);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
virtual String toString() const override
|
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
|
@file src/Ast/Expr/LiteralExpr.hpp
|
||||||
@brief 字面量表达式定义
|
@brief 字面量表达式定义
|
||||||
@author PuqiAR (im@puqiar.top)
|
|
||||||
@date 2026-02-14
|
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include <Ast/Base.hpp>
|
#include <Ast/Base.hpp>
|
||||||
#include <Token/Token.hpp>
|
#include <Token/Token.hpp>
|
||||||
|
|
||||||
#include <Deps/Deps.hpp>
|
|
||||||
|
|
||||||
namespace Fig
|
namespace Fig
|
||||||
{
|
{
|
||||||
struct LiteralExpr final : Expr
|
struct LiteralExpr final : public Expr
|
||||||
{
|
{
|
||||||
Token token;
|
Token literal;
|
||||||
|
|
||||||
LiteralExpr()
|
LiteralExpr() { type = AstType::LiteralExpr; }
|
||||||
{
|
LiteralExpr(const Token &_literal, SourceLocation _location) : literal(_literal)
|
||||||
type = AstType::LiteralExpr;
|
|
||||||
}
|
|
||||||
LiteralExpr(const Token& token, SourceLocation _location) : token(token)
|
|
||||||
{
|
{
|
||||||
type = AstType::LiteralExpr;
|
type = AstType::LiteralExpr;
|
||||||
location = std::move(_location);
|
location = std::move(_location);
|
||||||
}
|
}
|
||||||
|
|
||||||
virtual String toString() const override
|
virtual String toString() const override {
|
||||||
{
|
return std::format("<LiteralExpr: {}>", magic_enum::enum_name(literal.type));
|
||||||
return std::format("<LiteralExpr: {}>", magic_enum::enum_name(token.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
|
@file src/Ast/Stmt/FnDefStmt.hpp
|
||||||
@brief FnDefStmt定义
|
@brief 函数定义 AST 节点
|
||||||
@author PuqiAR (im@puqiar.top)
|
|
||||||
@date 2026-02-25
|
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include <Ast/Base.hpp>
|
#include <Ast/Base.hpp>
|
||||||
|
#include <Sema/Environment.hpp>
|
||||||
|
|
||||||
namespace Fig
|
namespace Fig
|
||||||
{
|
{
|
||||||
struct Param
|
struct Param : public AstNode {
|
||||||
{
|
|
||||||
String name;
|
String name;
|
||||||
SourceLocation location;
|
TypeExpr *typeSpecifier;
|
||||||
|
|
||||||
TypeInfo *resolvedType = nullptr;
|
|
||||||
int localId = -1;
|
|
||||||
|
|
||||||
virtual String toString() const = 0;
|
|
||||||
};
|
|
||||||
|
|
||||||
struct PosParam final : public Param
|
|
||||||
{
|
|
||||||
TypeExpr *type;
|
|
||||||
Expr *defaultValue;
|
Expr *defaultValue;
|
||||||
|
Type resolvedType;
|
||||||
PosParam() {}
|
Param() { type = AstType::AstNode; }
|
||||||
PosParam(String _name, TypeExpr *_type, Expr *_defaultValue, SourceLocation _location) :
|
virtual ~Param() = default;
|
||||||
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() : ""));
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
|
|
||||||
/*
|
struct PosParam final : public Param {
|
||||||
(public) func foo([name: (type) (= default value)]) (-> return type)
|
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 {
|
||||||
|
|
||||||
struct FnDefStmt final : public Stmt
|
|
||||||
{
|
|
||||||
String name;
|
String name;
|
||||||
DynArray<Param *> params;
|
DynArray<Param *> params;
|
||||||
TypeExpr *returnType;
|
TypeExpr *returnTypeSpecifier;
|
||||||
BlockStmt *body;
|
BlockStmt *body;
|
||||||
|
Type resolvedReturnType;
|
||||||
|
Symbol *resolvedSymbol = nullptr; // 连接物理符号
|
||||||
|
|
||||||
TypeInfo *resolvedReturnType = nullptr;
|
FnDefStmt() { type = AstType::FnDefStmt; }
|
||||||
int localId = -1;
|
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)
|
||||||
FnDefStmt()
|
|
||||||
{
|
{
|
||||||
type = AstType::FnDefStmt;
|
type = AstType::FnDefStmt; isPublic = _p; location = std::move(_loc);
|
||||||
}
|
}
|
||||||
|
|
||||||
FnDefStmt(bool _isPublic,
|
virtual String toString() const override {
|
||||||
String _name,
|
return std::format("<FnDefStmt '{}'>", 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());
|
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
}; // 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
|
@file src/Ast/TypeExpr.hpp
|
||||||
@brief TypeExpr定义
|
@brief 类型表达式 AST 定义:支持泛型与空安全
|
||||||
@author PuqiAR (im@puqiar.top)
|
|
||||||
@date 2026-02-25
|
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
@@ -11,26 +9,59 @@
|
|||||||
|
|
||||||
namespace Fig
|
namespace Fig
|
||||||
{
|
{
|
||||||
|
|
||||||
struct NamedTypeExpr final : public TypeExpr
|
struct NamedTypeExpr final : public TypeExpr
|
||||||
{
|
{
|
||||||
DynArray<String> path; // {"std", "file"} etc.
|
DynArray<String> path;
|
||||||
|
DynArray<TypeExpr *> arguments;
|
||||||
|
|
||||||
NamedTypeExpr()
|
NamedTypeExpr()
|
||||||
{
|
{
|
||||||
type = AstType::NamedTypeExpr;
|
type = AstType::NamedTypeExpr;
|
||||||
}
|
}
|
||||||
|
NamedTypeExpr(DynArray<String> _p, DynArray<TypeExpr *> _args, SourceLocation _loc) :
|
||||||
NamedTypeExpr(DynArray<String> _path, SourceLocation _location) :
|
path(std::move(_p)), arguments(std::move(_args))
|
||||||
path(std::move(_path))
|
|
||||||
{
|
{
|
||||||
type = AstType::NamedTypeExpr;
|
type = AstType::NamedTypeExpr;
|
||||||
location = std::move(_location);
|
location = std::move(_loc);
|
||||||
}
|
}
|
||||||
|
|
||||||
virtual String toString() const override
|
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,77 +1,80 @@
|
|||||||
/*!
|
/*!
|
||||||
@file src/Bytecode/Bytecode.hpp
|
@file src/Bytecode/Bytecode.hpp
|
||||||
@brief 字节码Bytecode定义
|
@brief 字节码Bytecode定义
|
||||||
@author PuqiAR (im@puqiar.top)
|
|
||||||
@date 2026-02-18
|
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include <cstdint>
|
#include <cstdint>
|
||||||
|
|
||||||
#pragma once
|
|
||||||
#include <cstdint>
|
|
||||||
|
|
||||||
namespace Fig
|
namespace Fig
|
||||||
{
|
{
|
||||||
|
|
||||||
// 定长 32-bit
|
|
||||||
using Instruction = std::uint32_t;
|
using Instruction = std::uint32_t;
|
||||||
|
|
||||||
enum class OpCode : std::uint8_t
|
enum class OpCode : std::uint8_t
|
||||||
{
|
{
|
||||||
Exit, // 结束运行
|
Exit,
|
||||||
LoadK, // iABx 模式: R[A] = Constants[Bx]
|
Exit_MaxRecursionDepthExceeded,
|
||||||
LoadTrue, // iABC: R[A] = true
|
|
||||||
LoadFalse, // iABC: R[A] = false
|
|
||||||
LoadNull, // iABC: R[A] = null
|
|
||||||
|
|
||||||
FastCall, // iABC: A: ProtoIdx, B: 函数起始寄存器
|
LoadK,
|
||||||
Call, // 动态派发 iABC: A: 函数体对象寄存器 B: 函数起始寄存器
|
LoadTrue,
|
||||||
Return, // iABC 模式: 返回 R[A] 的值
|
LoadFalse,
|
||||||
|
LoadNull,
|
||||||
|
|
||||||
LoadFn, // 惰性装修, iABx: R[A] = new FunctionObject...
|
FastCall,
|
||||||
|
Call,
|
||||||
|
Return,
|
||||||
|
|
||||||
Jmp, // iAsBx: ip += sBx 无条件跳转
|
LoadFn,
|
||||||
JmpIfFalse, // iAsBx: 如果 R[A] 为假, ip += sBx
|
|
||||||
|
|
||||||
Mov, // iABx: R[A] = R[Bx]
|
Jmp,
|
||||||
Add, // iABC: R[A] = R[B] + R[C]
|
JmpIfFalse,
|
||||||
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]
|
|
||||||
|
|
||||||
Equal, // iABC: R[A] = R[B] == R[C]
|
Mov,
|
||||||
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]
|
|
||||||
|
|
||||||
Count, // 哨兵
|
Add,
|
||||||
|
Sub,
|
||||||
|
Mul,
|
||||||
|
Div,
|
||||||
|
Mod,
|
||||||
|
BitXor,
|
||||||
|
|
||||||
|
IntFastAdd,
|
||||||
|
IntFastSub,
|
||||||
|
IntFastMul,
|
||||||
|
IntFastDiv,
|
||||||
|
|
||||||
|
Equal,
|
||||||
|
NotEqual,
|
||||||
|
Greater,
|
||||||
|
Less,
|
||||||
|
GreaterEqual,
|
||||||
|
LessEqual,
|
||||||
|
|
||||||
|
GetGlobal,
|
||||||
|
SetGlobal,
|
||||||
|
GetUpval,
|
||||||
|
SetUpval,
|
||||||
|
Copy,
|
||||||
|
|
||||||
|
Count
|
||||||
};
|
};
|
||||||
|
|
||||||
namespace Op
|
namespace Op
|
||||||
{
|
{
|
||||||
// [OpCode: 8] [A: 8] [Bx: 16]
|
|
||||||
[[nodiscard]] inline constexpr Instruction iABx(OpCode op, std::uint8_t a, std::uint16_t bx)
|
[[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)
|
return static_cast<std::uint32_t>(op) | (static_cast<std::uint32_t>(a) << 8)
|
||||||
| (static_cast<std::uint32_t>(bx) << 16);
|
| (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)
|
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);
|
| (static_cast<std::uint32_t>(b) << 16) | (static_cast<std::uint32_t>(c) << 24);
|
||||||
}
|
}
|
||||||
|
|
||||||
[[nodiscard]]
|
[[nodiscard]] inline constexpr Instruction iAsBx(OpCode op, std::uint8_t a, std::int16_t sbx)
|
||||||
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)
|
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);
|
| (static_cast<std::uint32_t>(static_cast<std::uint16_t>(sbx)) << 16);
|
||||||
|
|||||||
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 <Parser/Parser.hpp>
|
||||||
#include <SourceManager/SourceManager.hpp>
|
#include <Sema/Analyzer.hpp>
|
||||||
|
#include <Compiler/Compiler.hpp>
|
||||||
|
#include <Bytecode/Disassembler.hpp>
|
||||||
#include <iostream>
|
#include <iostream>
|
||||||
#include <print>
|
#include <filesystem>
|
||||||
|
|
||||||
int main()
|
int main()
|
||||||
{
|
{
|
||||||
using namespace Fig;
|
using namespace Fig;
|
||||||
|
|
||||||
String fileName = "test.fig";
|
String filePath = "T:/Files/Maker/Code/MyCodingLanguage/The Fig Project/Fig/tests/Compiler/test_basic.fig";
|
||||||
String filePath = "T:/Files/Maker/Code/MyCodingLanguage/The Fig Project/Fig/test.fig";
|
|
||||||
|
|
||||||
SourceManager manager(filePath);
|
if (!std::filesystem::exists(filePath.toStdString()))
|
||||||
manager.Read();
|
|
||||||
|
|
||||||
if (!manager.read)
|
|
||||||
{
|
{
|
||||||
std::cerr << "Couldn't read file";
|
std::cerr << "CRITICAL: Test file not found at: " << filePath << "\n";
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
Lexer lexer(manager.GetSource(), fileName);
|
SourceManager sm{filePath};
|
||||||
Parser parser(lexer, manager, fileName);
|
String source = sm.Read();
|
||||||
|
|
||||||
const auto &program_result = parser.Parse();
|
if (!sm.read || source.length() == 0)
|
||||||
if (!program_result)
|
|
||||||
{
|
{
|
||||||
ReportError(program_result.error(), manager);
|
std::cerr << "CRITICAL: SourceManager failed to read: " << filePath << "\n";
|
||||||
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);
|
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
CompiledModule *compiledModule = *comp_result;
|
Lexer lexer(source, filePath);
|
||||||
|
Parser parser(lexer, sm, filePath);
|
||||||
|
|
||||||
size_t cnt = 0;
|
auto pRes = parser.Parse();
|
||||||
for (Proto *proto : compiledModule->protos)
|
if (!pRes)
|
||||||
{
|
{
|
||||||
std::cout << "=====================\n"
|
ReportError(pRes.error(), sm);
|
||||||
<< "Proto: " << cnt++ << '\n';
|
return 1;
|
||||||
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);
|
Program *program = *pRes;
|
||||||
|
std::cout << "Successfully parsed nodes: " << program->nodes.size() << "\n";
|
||||||
|
|
||||||
std::cout << "\nMax Stack Size: " << (int) proto->maxStack << std::endl;
|
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;
|
return 0;
|
||||||
}
|
}
|
||||||
@@ -1,36 +1,125 @@
|
|||||||
/*!
|
/*!
|
||||||
@file src/Compiler/Compiler.cpp
|
@file src/Compiler/Compiler.cpp
|
||||||
@brief 编译器实现
|
@brief 编译器主逻辑实现:物理 Bootstrapper 与双步扫描
|
||||||
@author PuqiAR (im@puqiar.top)
|
|
||||||
@date 2026-02-18
|
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include <Compiler/Compiler.hpp>
|
#include <Compiler/Compiler.hpp>
|
||||||
|
#include <Ast/Stmt/FnDefStmt.hpp>
|
||||||
|
|
||||||
namespace Fig
|
namespace Fig
|
||||||
{
|
{
|
||||||
Result<CompiledModule *, Error> Compiler::Compile(Program *program)
|
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 (stmt->type == AstType::FnDefStmt)
|
||||||
if (!result)
|
|
||||||
{
|
{
|
||||||
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;
|
||||||
|
|
||||||
if (mainFuncIndex != -1)
|
module->protos.push_back(p);
|
||||||
|
|
||||||
|
// 连接物理符号到索引
|
||||||
|
if (f->resolvedSymbol)
|
||||||
{
|
{
|
||||||
std::uint8_t baseReg = AllocReg();
|
f->resolvedSymbol->index = idx;
|
||||||
Emit(Op::iABC(OpCode::FastCall, mainFuncIndex, baseReg, 0));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Emit(Op::iABC(OpCode::Exit, 0, 0, 0)); // 一定要退出,这是虚拟机退出信号,否则ub
|
if (f->name == "init")
|
||||||
|
initIdx = idx;
|
||||||
CompiledModule *compiledModule = new CompiledModule(fileName, allProtos);
|
if (f->name == "main")
|
||||||
return compiledModule;
|
mainIdx = idx;
|
||||||
}
|
}
|
||||||
}; // namespace Fig
|
}
|
||||||
|
|
||||||
|
// 3. 第二步:在 Bootstrapper 环境中编译所有语句
|
||||||
|
FuncState bootState(bootProto, nullptr);
|
||||||
|
current = &bootState;
|
||||||
|
|
||||||
|
for (auto *stmt : program->nodes)
|
||||||
|
{
|
||||||
|
auto res = compileStmt(stmt);
|
||||||
|
if (!res)
|
||||||
|
{
|
||||||
|
return std::unexpected(res.error());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 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;
|
||||||
|
}
|
||||||
|
|
||||||
|
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,384 +1,72 @@
|
|||||||
/*!
|
/*!
|
||||||
@file src/Compiler/Compiler.hpp
|
@file src/Compiler/Compiler.hpp
|
||||||
@brief 编译器定义
|
@brief 编译器定义:物理直连 Bootstrapper
|
||||||
@author PuqiAR (im@puqiar.top)
|
|
||||||
@date 2026-02-19
|
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include <Ast/Ast.hpp>
|
#include <Ast/Ast.hpp>
|
||||||
#include <Bytecode/Bytecode.hpp>
|
#include <Bytecode/Bytecode.hpp>
|
||||||
#include <Deps/Deps.hpp>
|
#include <Error/Diagnostics.hpp>
|
||||||
#include <Error/Error.hpp>
|
|
||||||
#include <Object/Object.hpp>
|
#include <Object/Object.hpp>
|
||||||
#include <SourceManager/SourceManager.hpp>
|
|
||||||
|
|
||||||
#include <cassert>
|
|
||||||
#include <iostream>
|
|
||||||
|
|
||||||
namespace Fig
|
namespace Fig
|
||||||
{
|
{
|
||||||
// 编译产物-函数
|
using Register = std::uint8_t;
|
||||||
|
|
||||||
|
struct UpvalueInfo { uint8_t index; bool isLocal; };
|
||||||
|
|
||||||
struct Proto
|
struct Proto
|
||||||
{
|
{
|
||||||
|
String name;
|
||||||
DynArray<Instruction> code;
|
DynArray<Instruction> code;
|
||||||
DynArray<Value> constants;
|
DynArray<Value> constants;
|
||||||
std::uint8_t maxStack = 0; // 函数运行所需寄存器数量
|
DynArray<UpvalueInfo> upvalues;
|
||||||
};
|
uint8_t maxRegisters = 0;
|
||||||
|
uint8_t numParams = 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 是要作为编译产物吐出去的
|
|
||||||
};
|
};
|
||||||
|
|
||||||
struct CompiledModule
|
struct CompiledModule
|
||||||
{
|
{
|
||||||
String name; // 供调试/打印
|
DynArray<Proto *> protos;
|
||||||
DynArray<Proto *> protos; // 扁平化函数原型
|
|
||||||
|
|
||||||
CompiledModule(String _name, DynArray<Proto *> _protos) :
|
|
||||||
name(std::move(_name)), protos(std::move(_protos))
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
~CompiledModule()
|
|
||||||
{
|
|
||||||
for (auto *p : protos)
|
|
||||||
{
|
|
||||||
delete p;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
|
|
||||||
class Compiler
|
class Compiler
|
||||||
{
|
{
|
||||||
private:
|
private:
|
||||||
String fileName;
|
static constexpr Register MAX_REGISTERS = 250;
|
||||||
|
static constexpr Register NO_REG = 255;
|
||||||
|
|
||||||
|
struct FuncState
|
||||||
|
{
|
||||||
|
Proto *proto;
|
||||||
|
Register freereg;
|
||||||
|
FuncState *enclosing;
|
||||||
|
HashMap<Value, int> constantMap;
|
||||||
|
|
||||||
|
FuncState(Proto *p, FuncState *e)
|
||||||
|
: proto(p), freereg(p->numParams), enclosing(e) {}
|
||||||
|
};
|
||||||
|
|
||||||
|
FuncState *current = nullptr;
|
||||||
|
CompiledModule *module = nullptr;
|
||||||
SourceManager &manager;
|
SourceManager &manager;
|
||||||
FuncState *current = nullptr; // 永远指向当前正在编译的上下文
|
Diagnostics &diag;
|
||||||
|
|
||||||
int mainFuncIndex = -1;
|
HashMap<String, int> globalIDMap;
|
||||||
HashMap<int, int> globalFuncMap; // localid -> ProtoIdx
|
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:
|
public:
|
||||||
DynArray<Proto *> allProtos;
|
Compiler(SourceManager &m, Diagnostics &d) : manager(m), diag(d) {}
|
||||||
|
|
||||||
struct FuncStateProtector
|
|
||||||
{
|
|
||||||
Compiler *compiler;
|
|
||||||
FuncState *prevState;
|
|
||||||
|
|
||||||
[[nodiscard]]
|
|
||||||
FuncStateProtector(Compiler *comp, FuncState *newState) :
|
|
||||||
compiler(comp), prevState(comp->current)
|
|
||||||
{
|
|
||||||
compiler->current = newState;
|
|
||||||
}
|
|
||||||
|
|
||||||
~FuncStateProtector()
|
|
||||||
{
|
|
||||||
compiler->current = prevState;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
Compiler(String _fileName, SourceManager &_manager) :
|
|
||||||
fileName(std::move(_fileName)), manager(_manager)
|
|
||||||
{
|
|
||||||
// 初始化顶级作用域
|
|
||||||
current = new FuncState("global", nullptr);
|
|
||||||
allProtos.push_back(current->proto); // 最顶层, bootstrapper
|
|
||||||
}
|
|
||||||
|
|
||||||
~Compiler()
|
|
||||||
{
|
|
||||||
// 内存清理 (如果有异常中断)
|
|
||||||
while (current != nullptr)
|
|
||||||
{
|
|
||||||
FuncState *prev = current->enclosing;
|
|
||||||
delete current;
|
|
||||||
current = prev;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Result<CompiledModule *, Error> Compile(Program *program);
|
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: {
|
|
||||||
// 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,334 +1,313 @@
|
|||||||
/*!
|
/*!
|
||||||
@file src/Compiler/ExprCompiler.cpp
|
@file src/Compiler/ExprCompiler.cpp
|
||||||
@brief 编译器实现(表达式部分)
|
@brief 表达式编译器实现:引入水位线(Watermark)与零拷贝复用机制
|
||||||
@author PuqiAR (im@puqiar.top)
|
|
||||||
@date 2026-02-19
|
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
#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 <Compiler/Compiler.hpp>
|
||||||
|
#include <charconv>
|
||||||
|
#include <limits>
|
||||||
|
#include <system_error>
|
||||||
|
|
||||||
|
|
||||||
namespace Fig
|
namespace Fig
|
||||||
{
|
{
|
||||||
Result<std::uint8_t, Error> Compiler::compileIdentiExpr(IdentiExpr *ie)
|
static Result<Value, Error> parsePhysicalNumber(const String &raw, const SourceLocation &loc)
|
||||||
{
|
{
|
||||||
// TODO: 处理全局变量和闭包 Upvalue
|
char buffer[128];
|
||||||
std::uint8_t targetReg = current->fastRegMap[ie->localId];
|
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);
|
||||||
return targetReg;
|
if (ec != std::errc())
|
||||||
}
|
return std::unexpected(Error(ErrorType::SyntaxError, "float overflow", "", loc));
|
||||||
Result<std::uint8_t, Error> Compiler::compileLiteral(
|
return Value::FromDouble(dVal);
|
||||||
LiteralExpr *lit) // 编译字面量, 负责转换 token -> Value
|
|
||||||
{
|
|
||||||
const Token &token = lit->token;
|
|
||||||
String lexeme = manager.GetSub(token.index, token.length);
|
|
||||||
|
|
||||||
if (!token.isLiteral())
|
|
||||||
{
|
|
||||||
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'))
|
|
||||||
{
|
|
||||||
// 非整数
|
|
||||||
double d = std::stod(lexeme.toStdString());
|
|
||||||
v = Value::FromDouble(d);
|
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
std::int32_t i = std::stoi(lexeme.toStdString());
|
int base = 10;
|
||||||
v = Value::FromInt(i);
|
const char *start = buffer;
|
||||||
|
if (j > 2 && buffer[0] == '0')
|
||||||
|
{
|
||||||
|
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
|
else
|
||||||
{
|
{
|
||||||
assert("false" && "CompileLiteral: unsupport literal");
|
return Value::FromDouble(static_cast<double>(iVal));
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
std::uint8_t targetReg = AllocReg();
|
Result<Register, Error> Compiler::compileExpr(Expr *expr, Register target)
|
||||||
|
|
||||||
if (current->proto->constants.size() >= MAX_CONSTANTS)
|
|
||||||
{
|
{
|
||||||
return std::unexpected(Error(ErrorType::TooManyConstants,
|
if (expr == nullptr)
|
||||||
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调用
|
|
||||||
{
|
{
|
||||||
// op必须为 =
|
return std::unexpected(
|
||||||
const auto &_lhsReg = compileLeftValue(infix->left); // 必须为左值对象
|
Error(ErrorType::InternalError, "null expr in compiler", "", {}));
|
||||||
if (!_lhsReg)
|
|
||||||
{
|
|
||||||
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);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const auto &_lhsReg = compileExpr(infix->left);
|
|
||||||
if (!_lhsReg)
|
|
||||||
{
|
|
||||||
return _lhsReg;
|
|
||||||
}
|
|
||||||
std::uint8_t lhsReg = *_lhsReg;
|
|
||||||
const auto &_rhsReg = compileExpr(infix->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: {
|
|
||||||
Emit(Op::iABC(OpCode::Add, resultReg, lhsReg, rhsReg));
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
case BinaryOperator::Subtract: {
|
|
||||||
Emit(Op::iABC(OpCode::Sub, resultReg, lhsReg, rhsReg));
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
case BinaryOperator::Multiply: {
|
|
||||||
Emit(Op::iABC(OpCode::Mul, resultReg, lhsReg, rhsReg));
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
case BinaryOperator::Divide: {
|
|
||||||
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)
|
switch (expr->type)
|
||||||
{
|
{
|
||||||
case AstType::IdentiExpr:
|
case AstType::LiteralExpr: {
|
||||||
return compileIdentiExpr(static_cast<IdentiExpr *>(expr));
|
auto *l = static_cast<LiteralExpr *>(expr);
|
||||||
// TODO: 数组切片(a[0])或对象属性(a.b)
|
Register r = (target == NO_REG) ? *allocateReg(l->location) : target;
|
||||||
|
|
||||||
default:
|
const Token &tok = l->literal;
|
||||||
// Analyzer 有漏洞(编译器内部
|
if (tok.type == TokenType::LiteralNumber)
|
||||||
// 直接崩溃
|
|
||||||
assert(false && "Compiler Bug: Invalid L-value bypassed Analyzer!");
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Result<std::uint8_t, Error> Compiler::compileCallExpr(CallExpr *expr)
|
|
||||||
{
|
{
|
||||||
bool isStatic = false; // 是否为单纯的 fn(...) 静态函数调用
|
auto vRes =
|
||||||
int protoIdx = -1;
|
parsePhysicalNumber(manager.GetSub(tok.index, tok.length), l->location);
|
||||||
|
if (!vRes)
|
||||||
if (expr->callee->type == AstType::IdentiExpr)
|
return std::unexpected(vRes.error());
|
||||||
{
|
emit(Op::iABx(OpCode::LoadK, r, static_cast<uint16_t>(addConstant(*vRes))));
|
||||||
IdentiExpr *id = static_cast<IdentiExpr *>(expr->callee);
|
|
||||||
// 如果是函数名且深度为 0 (全局/扁平函数池)
|
|
||||||
if (id->resolvedType->tag == TypeTag::Function && id->resolvedDepth == 0)
|
|
||||||
{
|
|
||||||
if (globalFuncMap.contains(id->localId))
|
|
||||||
{
|
|
||||||
isStatic = true;
|
|
||||||
protoIdx = globalFuncMap[id->localId];
|
|
||||||
}
|
}
|
||||||
}
|
else if (tok.type == TokenType::LiteralString)
|
||||||
}
|
|
||||||
|
|
||||||
std::uint8_t baseReg = AllocReg();
|
|
||||||
|
|
||||||
if (!isStatic)
|
|
||||||
{
|
{
|
||||||
auto calleeRes = compileExpr(expr->callee);
|
int kIdx = addConstant(Value::GetNullInstance()); // TODO: String 支持
|
||||||
if (!calleeRes)
|
emit(Op::iABx(OpCode::LoadK, r, static_cast<uint16_t>(kIdx)));
|
||||||
{
|
|
||||||
return calleeRes;
|
|
||||||
}
|
}
|
||||||
|
else if (tok.type == TokenType::LiteralNull)
|
||||||
if (*calleeRes != baseReg)
|
|
||||||
{
|
{
|
||||||
Emit(Op::iABx(OpCode::Mov, baseReg, *calleeRes));
|
emit(Op::iABC(OpCode::LoadNull, r, 0, 0));
|
||||||
}
|
}
|
||||||
}
|
else if (tok.type == TokenType::LiteralTrue)
|
||||||
|
|
||||||
for (size_t i = 0; i < expr->args.size(); ++i)
|
|
||||||
{
|
{
|
||||||
std::uint8_t argTarget = AllocReg();
|
emit(Op::iABC(OpCode::LoadTrue, r, 0, 0));
|
||||||
auto argRes = compileExpr(expr->args.args[i]);
|
|
||||||
if (!argRes)
|
|
||||||
{
|
|
||||||
return argRes;
|
|
||||||
}
|
}
|
||||||
|
else if (tok.type == TokenType::LiteralFalse)
|
||||||
if (*argRes != argTarget)
|
|
||||||
{
|
{
|
||||||
Emit(Op::iABx(OpCode::Mov, argTarget, *argRes));
|
emit(Op::iABC(OpCode::LoadFalse, r, 0, 0));
|
||||||
}
|
}
|
||||||
|
return r;
|
||||||
}
|
}
|
||||||
|
|
||||||
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: {
|
case AstType::IdentiExpr: {
|
||||||
return compileLeftValue(expr); // 左值直接转换成右值
|
auto *i = static_cast<IdentiExpr *>(expr);
|
||||||
}
|
Symbol *sym = i->resolvedSymbol;
|
||||||
|
|
||||||
case AstType::LiteralExpr: {
|
if (sym->location == SymbolLocation::Local)
|
||||||
LiteralExpr *lit = static_cast<LiteralExpr *>(expr);
|
|
||||||
|
|
||||||
auto result = compileLiteral(lit);
|
|
||||||
if (!result)
|
|
||||||
{
|
{
|
||||||
return std::unexpected(result.error());
|
// 零拷贝直读:如果是临时求值,直接返回变量的物理槽位,禁止产生副本
|
||||||
|
if (target == NO_REG)
|
||||||
|
return static_cast<Register>(sym->index);
|
||||||
|
|
||||||
|
// 仅在被强制指定目标(如参数装填)时发射搬运指令
|
||||||
|
if (target != sym->index)
|
||||||
|
{
|
||||||
|
emit(Op::iABx(OpCode::Mov, target, static_cast<uint16_t>(sym->index)));
|
||||||
}
|
}
|
||||||
std::uint8_t targetReg = *result;
|
return target;
|
||||||
return targetReg;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
case AstType::InfixExpr: {
|
Register r = (target == NO_REG) ? *allocateReg(i->location) : target;
|
||||||
return compileInfixExpr(static_cast<InfixExpr *>(expr));
|
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: {
|
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
|
} // namespace Fig
|
||||||
@@ -1,282 +1,215 @@
|
|||||||
/*!
|
/*!
|
||||||
@file src/Compiler/StmtCompiler.cpp
|
@file src/Compiler/StmtCompiler.cpp
|
||||||
@brief 编译器实现(语句部分)
|
@brief 语句编译器实现:实装水位线机制,彻底消灭硬编码寄存器释放
|
||||||
@author PuqiAR (im@puqiar.top)
|
|
||||||
@date 2026-02-19
|
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
#include <Ast/Stmt/FnDefStmt.hpp>
|
||||||
|
#include <Ast/Stmt/IfStmt.hpp>
|
||||||
|
#include <Ast/Stmt/VarDecl.hpp>
|
||||||
|
#include <Ast/Stmt/WhileStmt.hpp>
|
||||||
#include <Compiler/Compiler.hpp>
|
#include <Compiler/Compiler.hpp>
|
||||||
|
|
||||||
|
|
||||||
namespace Fig
|
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)));
|
|
||||||
}
|
|
||||||
|
|
||||||
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 {};
|
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)
|
switch (stmt->type)
|
||||||
{
|
{
|
||||||
case AstType::ExprStmt: {
|
case AstType::BlockStmt: {
|
||||||
ExprStmt *exprStmt = static_cast<ExprStmt *>(stmt);
|
auto *b = static_cast<BlockStmt *>(stmt);
|
||||||
Expr *expr = exprStmt->expr;
|
for (auto *n : b->nodes)
|
||||||
auto result = compileExpr(expr);
|
|
||||||
if (!result)
|
|
||||||
{
|
{
|
||||||
return std::unexpected(result.error());
|
auto res = compileStmt(n);
|
||||||
|
if (!res)
|
||||||
|
return res;
|
||||||
}
|
}
|
||||||
FreeReg(*result);
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
case AstType::VarDecl: {
|
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());
|
||||||
|
|
||||||
|
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::BlockStmt: {
|
auto regRes = compileExpr(v->initExpr, targetReg);
|
||||||
return compileBlockStmt(static_cast<BlockStmt *>(stmt));
|
if (!regRes)
|
||||||
|
return std::unexpected(regRes.error());
|
||||||
}
|
}
|
||||||
|
break;
|
||||||
case AstType::IfStmt: {
|
|
||||||
return compileIfStmt(static_cast<IfStmt *>(stmt));
|
|
||||||
}
|
|
||||||
|
|
||||||
case AstType::WhileStmt: {
|
|
||||||
return compileWhileStmt(static_cast<WhileStmt *>(stmt));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
case AstType::FnDefStmt: {
|
case AstType::FnDefStmt: {
|
||||||
return compileFnDefStmt(static_cast<FnDefStmt *>(stmt));
|
auto *f = static_cast<FnDefStmt *>(stmt);
|
||||||
|
|
||||||
|
// 物理连线:对接 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: {
|
case AstType::ReturnStmt: {
|
||||||
return compileReturnStmt(static_cast<ReturnStmt *>(stmt));
|
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;
|
||||||
}
|
}
|
||||||
|
|
||||||
return Result<void, Error>();
|
emit(Op::iABC(OpCode::Return, retReg, 0, 0));
|
||||||
|
current->freereg = mark; // 回收返回值计算的占用
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
}; // namespace Fig
|
|
||||||
|
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
|
||||||
@@ -41,7 +41,9 @@ namespace Fig::CoreIO
|
|||||||
|
|
||||||
void InitConsoleIO()
|
void InitConsoleIO()
|
||||||
{
|
{
|
||||||
|
#ifdef _WIN32
|
||||||
SetConsoleCP(CP_UTF8);
|
SetConsoleCP(CP_UTF8);
|
||||||
SetConsoleOutputCP(CP_UTF8);
|
SetConsoleOutputCP(CP_UTF8);
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
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 TooManyLocals: return "TooManyLocals";
|
||||||
case TooManyConstants: return "TooManyConstants";
|
case TooManyConstants: return "TooManyConstants";
|
||||||
|
|
||||||
|
case RegisterOverflow: return "RegisterOverflow";
|
||||||
|
case InternalError: return "InternalError";
|
||||||
// default: return "Some one forgot to add case to `ErrorTypeToString`";
|
// default: return "Some one forgot to add case to `ErrorTypeToString`";
|
||||||
}
|
}
|
||||||
|
return "UnknownError";
|
||||||
}
|
}
|
||||||
|
|
||||||
void PrintSystemInfos()
|
void PrintSystemInfos()
|
||||||
|
|||||||
@@ -11,7 +11,6 @@
|
|||||||
#include <Deps/Deps.hpp>
|
#include <Deps/Deps.hpp>
|
||||||
#include <SourceManager/SourceManager.hpp>
|
#include <SourceManager/SourceManager.hpp>
|
||||||
|
|
||||||
|
|
||||||
#include <source_location>
|
#include <source_location>
|
||||||
|
|
||||||
namespace Fig
|
namespace Fig
|
||||||
@@ -51,6 +50,10 @@ namespace Fig
|
|||||||
// compile errors
|
// compile errors
|
||||||
TooManyLocals,
|
TooManyLocals,
|
||||||
TooManyConstants,
|
TooManyConstants,
|
||||||
|
|
||||||
|
// --- 新增:编译器内部与VM约束 ---
|
||||||
|
RegisterOverflow,
|
||||||
|
InternalError,
|
||||||
};
|
};
|
||||||
|
|
||||||
const char *ErrorTypeToString(ErrorType type);
|
const char *ErrorTypeToString(ErrorType type);
|
||||||
@@ -77,6 +80,9 @@ namespace Fig
|
|||||||
location = _location;
|
location = _location;
|
||||||
thrower_loc = _throwerloc;
|
thrower_loc = _throwerloc;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 新增:适配诊断系统的辅助判定
|
||||||
|
bool IsWarning() const { return static_cast<unsigned int>(type) < 2000; }
|
||||||
};
|
};
|
||||||
|
|
||||||
namespace TerminalColors
|
namespace TerminalColors
|
||||||
|
|||||||
@@ -9,7 +9,6 @@
|
|||||||
|
|
||||||
#include <Object/ObjectBase.hpp>
|
#include <Object/ObjectBase.hpp>
|
||||||
|
|
||||||
|
|
||||||
namespace Fig
|
namespace Fig
|
||||||
{
|
{
|
||||||
// 运行时闭包对象 (24字节 Base + 8字节 Proto指针 = 32 bytes)
|
// 运行时闭包对象 (24字节 Base + 8字节 Proto指针 = 32 bytes)
|
||||||
@@ -17,7 +16,9 @@ namespace Fig
|
|||||||
struct Proto;
|
struct Proto;
|
||||||
struct FunctionObject final : public Object
|
struct FunctionObject final : public Object
|
||||||
{
|
{
|
||||||
|
String name; // 调试使用
|
||||||
Proto *proto; // 指向编译器生成的只读字节码与常量池
|
Proto *proto; // 指向编译器生成的只读字节码与常量池
|
||||||
|
std::uint8_t paraCount;
|
||||||
|
|
||||||
// TODO: 实现闭包时 加一个 Upvalue 指针数组
|
// TODO: 实现闭包时 加一个 Upvalue 指针数组
|
||||||
// Value* upvalues;
|
// Value* upvalues;
|
||||||
|
|||||||
@@ -187,7 +187,7 @@ namespace Fig
|
|||||||
|
|
||||||
/*
|
/*
|
||||||
C风格继承 + 手动分发
|
C风格继承 + 手动分发
|
||||||
禁止任何 virtual 达到最高效率
|
禁止核心使用任何 virtual 达到最高效率
|
||||||
*/
|
*/
|
||||||
enum class ObjectType : uint8_t
|
enum class ObjectType : uint8_t
|
||||||
{
|
{
|
||||||
@@ -227,5 +227,23 @@ namespace Fig
|
|||||||
{
|
{
|
||||||
return type == ObjectType::Instance;
|
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
|
struct StringObject final : public Object
|
||||||
{
|
{
|
||||||
String data; // 40 bytes
|
String data; // 40 bytes
|
||||||
|
|
||||||
|
virtual String toString() const override
|
||||||
|
{
|
||||||
|
return data;
|
||||||
|
}
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
@@ -39,6 +39,10 @@ namespace Fig
|
|||||||
0 - UnaryOperators::Count BinaryOperators::Count
|
0 - UnaryOperators::Count BinaryOperators::Count
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
Value fields[];
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
Object *GetUnaryOperator(UnaryOperator _op)
|
Object *GetUnaryOperator(UnaryOperator _op)
|
||||||
{
|
{
|
||||||
std::uint8_t idx = static_cast<std::uint8_t>(_op);
|
std::uint8_t idx = static_cast<std::uint8_t>(_op);
|
||||||
|
|||||||
@@ -9,25 +9,25 @@
|
|||||||
|
|
||||||
namespace Fig
|
namespace Fig
|
||||||
{
|
{
|
||||||
Result<LiteralExpr *, Error> Parser::parseLiteralExpr() // 当前token为literal时调用
|
Result<Expr *, Error> Parser::parseLiteralExpr() // 当前token为literal时调用
|
||||||
{
|
{
|
||||||
StateProtector p(this, {State::ParsingLiteralExpr});
|
StateProtector p(this, {State::ParsingLiteralExpr});
|
||||||
|
|
||||||
const Token &literal_token = consumeToken();
|
const Token &literal_token = consumeToken();
|
||||||
LiteralExpr *node = new LiteralExpr(literal_token, makeSourceLocation(literal_token));
|
LiteralExpr *node = arena.Allocate<LiteralExpr>(literal_token, makeSourceLocation(literal_token));
|
||||||
return node;
|
return node;
|
||||||
}
|
}
|
||||||
Result<IdentiExpr *, Error> Parser::parseIdentiExpr() // 当前token为Identifier调用
|
Result<Expr *, Error> Parser::parseIdentiExpr() // 当前token为Identifier调用
|
||||||
{
|
{
|
||||||
StateProtector p(this, {State::ParsingIdentiExpr});
|
StateProtector p(this, {State::ParsingIdentiExpr});
|
||||||
|
|
||||||
const Token &identifier = consumeToken();
|
const Token &identifier = consumeToken();
|
||||||
IdentiExpr *node = new IdentiExpr(
|
IdentiExpr *node = arena.Allocate<IdentiExpr>(
|
||||||
srcManager.GetSub(identifier.index, identifier.length), makeSourceLocation(identifier));
|
srcManager.GetSub(identifier.index, identifier.length), makeSourceLocation(identifier));
|
||||||
return node;
|
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});
|
StateProtector p(this, {State::ParsingInfixExpr});
|
||||||
|
|
||||||
@@ -42,11 +42,11 @@ namespace Fig
|
|||||||
}
|
}
|
||||||
Expr *rhs = *rhs_result;
|
Expr *rhs = *rhs_result;
|
||||||
|
|
||||||
InfixExpr *node = new InfixExpr(lhs, op, rhs);
|
InfixExpr *node = arena.Allocate<InfixExpr>(lhs, op, rhs);
|
||||||
return node;
|
return node;
|
||||||
}
|
}
|
||||||
|
|
||||||
Result<PrefixExpr *, Error> Parser::parsePrefixExpr() // 当前token为op
|
Result<Expr *, Error> Parser::parsePrefixExpr() // 当前token为op
|
||||||
{
|
{
|
||||||
StateProtector p(this, {State::ParsingPrefixExpr});
|
StateProtector p(this, {State::ParsingPrefixExpr});
|
||||||
|
|
||||||
@@ -61,11 +61,11 @@ namespace Fig
|
|||||||
}
|
}
|
||||||
|
|
||||||
Expr *rhs = *rhs_result;
|
Expr *rhs = *rhs_result;
|
||||||
PrefixExpr *node = new PrefixExpr(op, rhs);
|
PrefixExpr *node = arena.Allocate<PrefixExpr>(op, rhs);
|
||||||
return node;
|
return node;
|
||||||
}
|
}
|
||||||
|
|
||||||
Result<IndexExpr *, Error> Parser::parseIndexExpr(
|
Result<Expr *, Error> Parser::parseIndexExpr(
|
||||||
Expr *base) // 由 parseExpression调用, 当前token为 `[`
|
Expr *base) // 由 parseExpression调用, 当前token为 `[`
|
||||||
{
|
{
|
||||||
StateProtector p(this, {State::ParsingIndexExpr});
|
StateProtector p(this, {State::ParsingIndexExpr});
|
||||||
@@ -87,11 +87,11 @@ namespace Fig
|
|||||||
}
|
}
|
||||||
consumeToken(); // consume `]`
|
consumeToken(); // consume `]`
|
||||||
|
|
||||||
IndexExpr *indexExpr = new IndexExpr(base, *index_result);
|
IndexExpr *indexExpr = arena.Allocate<IndexExpr>(base, *index_result);
|
||||||
return indexExpr;
|
return indexExpr;
|
||||||
}
|
}
|
||||||
|
|
||||||
Result<CallExpr *, Error> Parser::parseCallExpr(
|
Result<Expr *, Error> Parser::parseCallExpr(
|
||||||
Expr *callee) // 由 parseExpression调用, 当前token为 `(`
|
Expr *callee) // 由 parseExpression调用, 当前token为 `(`
|
||||||
{
|
{
|
||||||
StateProtector p(this, {State::ParsingCallExpr});
|
StateProtector p(this, {State::ParsingCallExpr});
|
||||||
@@ -104,7 +104,7 @@ namespace Fig
|
|||||||
if (currentToken().type == TokenType::RightParen)
|
if (currentToken().type == TokenType::RightParen)
|
||||||
{
|
{
|
||||||
consumeToken(); // consume `)`
|
consumeToken(); // consume `)`
|
||||||
return new CallExpr(callee, callArgs);
|
return arena.Allocate<CallExpr>(callee, callArgs);
|
||||||
}
|
}
|
||||||
|
|
||||||
while (true)
|
while (true)
|
||||||
@@ -140,7 +140,7 @@ namespace Fig
|
|||||||
consumeToken(); // consume `,`
|
consumeToken(); // consume `,`
|
||||||
}
|
}
|
||||||
|
|
||||||
return new CallExpr(callee, callArgs);
|
return arena.Allocate<CallExpr>(callee, callArgs);
|
||||||
}
|
}
|
||||||
|
|
||||||
Result<Expr *, Error> Parser::parseExpression(BindingPower rbp)
|
Result<Expr *, Error> Parser::parseExpression(BindingPower rbp)
|
||||||
|
|||||||
@@ -1,8 +1,8 @@
|
|||||||
/*!
|
/*!
|
||||||
@file src/Parser/Parser.cpp
|
@file src/Parser/Parser.cpp
|
||||||
@brief 语法分析器(Pratt + 手动递归下降) 实现
|
@brief 语法分析器实现
|
||||||
@author PuqiAR (im@puqiar.top)
|
@author PuqiAR (im@puqiar.top)
|
||||||
@date 2026-02-14
|
@date 2026-03-08
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include <Parser/Parser.hpp>
|
#include <Parser/Parser.hpp>
|
||||||
@@ -11,21 +11,23 @@ namespace Fig
|
|||||||
{
|
{
|
||||||
Result<Program *, Error> Parser::Parse()
|
Result<Program *, Error> Parser::Parse()
|
||||||
{
|
{
|
||||||
Program *program = new Program;
|
Program *program = arena.Allocate<Program>();
|
||||||
while (!isEOF)
|
|
||||||
|
while (currentToken().type != TokenType::EndOfFile)
|
||||||
{
|
{
|
||||||
auto result = parseStatement();
|
auto result = parseStatement();
|
||||||
if (!result)
|
if (!result)
|
||||||
{
|
{
|
||||||
return std::unexpected(result.error());
|
return std::unexpected(result.error());
|
||||||
}
|
}
|
||||||
|
|
||||||
Stmt *stmt = *result;
|
Stmt *stmt = *result;
|
||||||
if (!stmt)
|
if (stmt)
|
||||||
{
|
{
|
||||||
continue;
|
|
||||||
}
|
|
||||||
program->nodes.push_back(stmt);
|
program->nodes.push_back(stmt);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return program;
|
return program;
|
||||||
}
|
}
|
||||||
}; // namespace Fig
|
}; // namespace Fig
|
||||||
@@ -2,7 +2,7 @@
|
|||||||
@file src/Parser/Parser.hpp
|
@file src/Parser/Parser.hpp
|
||||||
@brief 语法分析器(Pratt + 手动递归下降) 定义
|
@brief 语法分析器(Pratt + 手动递归下降) 定义
|
||||||
@author PuqiAR (im@puqiar.top)
|
@author PuqiAR (im@puqiar.top)
|
||||||
@date 2026-02-14
|
@date 2026-03-08
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
@@ -12,35 +12,37 @@
|
|||||||
#include <Error/Error.hpp>
|
#include <Error/Error.hpp>
|
||||||
#include <Lexer/Lexer.hpp>
|
#include <Lexer/Lexer.hpp>
|
||||||
#include <Token/Token.hpp>
|
#include <Token/Token.hpp>
|
||||||
|
#include <Utils/Arena.hpp>
|
||||||
|
|
||||||
#include <cstddef>
|
#include <cstddef>
|
||||||
#include <cstdlib>
|
#include <cstdlib>
|
||||||
|
|
||||||
#include <unordered_set>
|
#include <unordered_set>
|
||||||
|
|
||||||
namespace Fig
|
namespace Fig
|
||||||
{
|
{
|
||||||
|
|
||||||
class Parser
|
class Parser
|
||||||
{
|
{
|
||||||
private:
|
private:
|
||||||
|
Arena arena;
|
||||||
Lexer &lexer;
|
Lexer &lexer;
|
||||||
SourceManager &srcManager;
|
SourceManager &srcManager;
|
||||||
|
|
||||||
size_t index = 0; // token在buffer下标
|
size_t index = 0; // 当前 Token 在 buffer 中的下标
|
||||||
DynArray<Token> buffer;
|
DynArray<Token> buffer; // 已从 Lexer 读取的 Token 缓存
|
||||||
|
|
||||||
String fileName;
|
String fileName;
|
||||||
|
|
||||||
bool isEOF = false;
|
bool isEOF = false;
|
||||||
|
|
||||||
|
// 惰性获取下一个 Token,跳过注释
|
||||||
Token nextToken()
|
Token nextToken()
|
||||||
{
|
{
|
||||||
assert(!isEOF && "nextToken: eof but called nextToken");
|
|
||||||
if (index + 1 < buffer.size())
|
if (index + 1 < buffer.size())
|
||||||
{
|
|
||||||
return buffer[++index];
|
return buffer[++index];
|
||||||
}
|
if (isEOF)
|
||||||
|
return buffer[index];
|
||||||
|
|
||||||
|
while (true)
|
||||||
|
{
|
||||||
auto result = lexer.NextToken();
|
auto result = lexer.NextToken();
|
||||||
if (!result)
|
if (!result)
|
||||||
{
|
{
|
||||||
@@ -48,39 +50,33 @@ namespace Fig
|
|||||||
std::exit(-1);
|
std::exit(-1);
|
||||||
}
|
}
|
||||||
const Token &token = result.value();
|
const Token &token = result.value();
|
||||||
|
if (token.type == TokenType::Comments)
|
||||||
|
continue; // 惰性跳过注释
|
||||||
|
|
||||||
if (token.type == TokenType::EndOfFile)
|
if (token.type == TokenType::EndOfFile)
|
||||||
{
|
|
||||||
isEOF = true;
|
isEOF = true;
|
||||||
}
|
|
||||||
buffer.push_back(token);
|
buffer.push_back(token);
|
||||||
index++;
|
index = buffer.size() - 1;
|
||||||
return token;
|
return buffer[index];
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
inline Token prevToken()
|
inline Token prevToken()
|
||||||
{
|
{
|
||||||
if (buffer.size() < 2)
|
return (index > 0) ? buffer[index - 1] : buffer[0];
|
||||||
{
|
|
||||||
return currentToken();
|
|
||||||
}
|
}
|
||||||
return buffer[buffer.size() - 2];
|
|
||||||
}
|
|
||||||
|
|
||||||
inline Token currentToken()
|
inline Token currentToken()
|
||||||
{
|
{
|
||||||
if (buffer.empty())
|
if (buffer.empty())
|
||||||
{
|
|
||||||
return nextToken();
|
return nextToken();
|
||||||
}
|
return buffer[index];
|
||||||
return buffer.back();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 惰性窥视后续 Token
|
||||||
Token peekToken(size_t lookahead = 1)
|
Token peekToken(size_t lookahead = 1)
|
||||||
{
|
{
|
||||||
assert(!isEOF && "peekToken: eof but called peekToken");
|
size_t targetIndex = index + lookahead;
|
||||||
|
while (targetIndex >= buffer.size() && !isEOF)
|
||||||
size_t peekIndex = index + lookahead;
|
|
||||||
while (peekIndex >= buffer.size() && !isEOF)
|
|
||||||
{
|
{
|
||||||
auto result = lexer.NextToken();
|
auto result = lexer.NextToken();
|
||||||
if (!result)
|
if (!result)
|
||||||
@@ -88,29 +84,22 @@ namespace Fig
|
|||||||
ReportError(result.error(), srcManager);
|
ReportError(result.error(), srcManager);
|
||||||
std::abort();
|
std::abort();
|
||||||
}
|
}
|
||||||
const Token &token = result.value();
|
if (result->type == TokenType::Comments)
|
||||||
if (token.type == TokenType::EndOfFile)
|
continue;
|
||||||
{
|
if (result->type == TokenType::EndOfFile)
|
||||||
isEOF = true;
|
isEOF = true;
|
||||||
|
buffer.push_back(*result);
|
||||||
}
|
}
|
||||||
buffer.push_back(token);
|
return (targetIndex >= buffer.size()) ? buffer.back() : buffer[targetIndex];
|
||||||
}
|
|
||||||
if (peekIndex >= buffer.size()) // 没有那么多token
|
|
||||||
{
|
|
||||||
return buffer.back(); // back是EOF Token
|
|
||||||
}
|
|
||||||
return buffer[peekIndex];
|
|
||||||
}
|
}
|
||||||
|
|
||||||
inline Token consumeToken()
|
inline Token consumeToken()
|
||||||
{
|
{
|
||||||
if (isEOF)
|
|
||||||
return buffer.back();
|
|
||||||
Token current = currentToken();
|
Token current = currentToken();
|
||||||
|
if (current.type != TokenType::EndOfFile)
|
||||||
nextToken();
|
nextToken();
|
||||||
return current;
|
return current;
|
||||||
}
|
}
|
||||||
|
|
||||||
inline bool match(TokenType type)
|
inline bool match(TokenType type)
|
||||||
{
|
{
|
||||||
if (currentToken().type == type)
|
if (currentToken().type == type)
|
||||||
@@ -121,47 +110,18 @@ namespace Fig
|
|||||||
return false;
|
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:
|
public:
|
||||||
struct State
|
struct State
|
||||||
{
|
{
|
||||||
enum StateType : std::uint8_t
|
enum StateType : std::uint8_t
|
||||||
{
|
{
|
||||||
Standby,
|
Standby,
|
||||||
|
|
||||||
ParsingLiteralExpr,
|
ParsingLiteralExpr,
|
||||||
ParsingIdentiExpr,
|
ParsingIdentiExpr,
|
||||||
|
|
||||||
ParsingInfixExpr,
|
ParsingInfixExpr,
|
||||||
ParsingPrefixExpr,
|
ParsingPrefixExpr,
|
||||||
|
|
||||||
ParsingIndexExpr,
|
ParsingIndexExpr,
|
||||||
ParsingCallExpr,
|
ParsingCallExpr,
|
||||||
|
|
||||||
ParsingVarDecl,
|
ParsingVarDecl,
|
||||||
ParsingIf,
|
ParsingIf,
|
||||||
ParsingWhile,
|
ParsingWhile,
|
||||||
@@ -169,9 +129,7 @@ namespace Fig
|
|||||||
ParsingReturn,
|
ParsingReturn,
|
||||||
ParsingBreak,
|
ParsingBreak,
|
||||||
ParsingContinue,
|
ParsingContinue,
|
||||||
|
|
||||||
ParsingNamedTypeExpr,
|
ParsingNamedTypeExpr,
|
||||||
|
|
||||||
} type = StateType::Standby;
|
} type = StateType::Standby;
|
||||||
std::unordered_set<TokenType> stopAt = {};
|
std::unordered_set<TokenType> stopAt = {};
|
||||||
};
|
};
|
||||||
@@ -188,134 +146,121 @@ namespace Fig
|
|||||||
return baseTerminators;
|
return baseTerminators;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::unordered_set<TokenType> &getTerminators() // 返回固定的终止符
|
std::unordered_set<TokenType> &getTerminators()
|
||||||
{
|
{
|
||||||
/*
|
|
||||||
Syntax terminators:
|
|
||||||
; ) ] } , EOF
|
|
||||||
*/
|
|
||||||
|
|
||||||
static std::unordered_set<TokenType> terminators(getBaseTerminators());
|
static std::unordered_set<TokenType> terminators(getBaseTerminators());
|
||||||
return terminators;
|
return terminators;
|
||||||
}
|
}
|
||||||
|
|
||||||
void resetTermintors()
|
void resetTermintors()
|
||||||
{
|
{
|
||||||
getTerminators() = getBaseTerminators();
|
getTerminators() = getBaseTerminators();
|
||||||
}
|
}
|
||||||
bool shouldTerminate() // 判断是否终结
|
|
||||||
|
bool shouldTerminate()
|
||||||
{
|
{
|
||||||
const Token &token = currentToken();
|
const Token &token = currentToken();
|
||||||
const auto &terminators = getTerminators();
|
if (getTerminators().contains(token.type))
|
||||||
|
|
||||||
if (terminators.contains(token.type))
|
|
||||||
{
|
|
||||||
return true;
|
return true;
|
||||||
}
|
|
||||||
for (auto it = stateStack.rbegin(); it < stateStack.rend(); ++it)
|
for (auto it = stateStack.rbegin(); it < stateStack.rend(); ++it)
|
||||||
{
|
{
|
||||||
if (it->stopAt.contains(token.type))
|
if (it->stopAt.contains(token.type))
|
||||||
{
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
}
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
DynArray<State> stateStack;
|
DynArray<State> stateStack;
|
||||||
|
|
||||||
State ¤tState()
|
State ¤tState()
|
||||||
{
|
{
|
||||||
return stateStack.back();
|
return stateStack.back();
|
||||||
}
|
}
|
||||||
|
|
||||||
void pushState(State _state)
|
void pushState(State _state)
|
||||||
{
|
{
|
||||||
stateStack.push_back(std::move(_state));
|
stateStack.push_back(std::move(_state));
|
||||||
}
|
}
|
||||||
|
|
||||||
void popState()
|
void popState()
|
||||||
{
|
{
|
||||||
if (!stateStack.empty())
|
if (!stateStack.empty())
|
||||||
{
|
|
||||||
stateStack.pop_back();
|
stateStack.pop_back();
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
class StateProtector
|
struct StateProtector
|
||||||
{
|
{
|
||||||
Parser *parser;
|
Parser *p;
|
||||||
|
StateProtector(Parser *_p, State _s) : p(_p)
|
||||||
public:
|
|
||||||
StateProtector(Parser *p, const State &newState) : parser(p)
|
|
||||||
{
|
{
|
||||||
parser->pushState(newState);
|
p->pushState(_s);
|
||||||
}
|
}
|
||||||
|
|
||||||
~StateProtector()
|
~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)
|
SourceLocation makeSourceLocation(const Token &tok)
|
||||||
{
|
{
|
||||||
auto [line, column] = srcManager.GetLineColumn(tok.index);
|
auto [line, column] = srcManager.GetLineColumn(tok.index);
|
||||||
|
// 物理防爆盾:防止因解析错位导致的异常列号引起终端 OOM
|
||||||
|
if (column > 5000)
|
||||||
|
column = 1;
|
||||||
return SourceLocation(SourcePosition(line, column, tok.length),
|
return SourceLocation(SourcePosition(line, column, tok.length),
|
||||||
fileName,
|
fileName,
|
||||||
"[internal parser]",
|
"[internal parser]",
|
||||||
magic_enum::enum_name(currentState().type).data());
|
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();
|
Result<TypeExpr *, Error> parseTypeExpr();
|
||||||
|
Result<TypeExpr *, Error> parseNamedTypeExpr();
|
||||||
/* 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<Expr *, Error> parseExpression(BindingPower = 0);
|
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();
|
||||||
Result<BlockStmt *, Error> parseBlockStmt(); // 当前token为 {
|
Result<VarDecl *, Error> parseVarDecl(bool);
|
||||||
Result<VarDecl *, Error> parseVarDecl(bool); // 由 parseStatement调用, 当前token为 var
|
Result<IfStmt *, Error> parseIfStmt();
|
||||||
Result<IfStmt *, Error> parseIfStmt(); // 由 parseStatement调用, 当前token为 if
|
Result<WhileStmt *, Error> parseWhileStmt();
|
||||||
Result<WhileStmt *, Error> parseWhileStmt(); // 由 parseStatement调用, 当前token为 while
|
Result<DynArray<Param *>, Error> parseFnParams();
|
||||||
|
Result<FnDefStmt *, Error> parseFnDefStmt(bool);
|
||||||
|
Result<ReturnStmt *, Error> parseReturnStmt();
|
||||||
|
|
||||||
Result<DynArray<Param *>, Error> parseFnParams(); // 由 parseFnDefStmt或lambda调用
|
Result<Stmt *, Error> parseStructDef(bool);
|
||||||
Result<FnDefStmt *, Error> parseFnDefStmt(bool); // 由 parseStatement调用, 当前token为 func
|
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:
|
public:
|
||||||
|
Parser(Lexer &_lexer, SourceManager &_src, String _file) :
|
||||||
|
lexer(_lexer), srcManager(_src), fileName(std::move(_file))
|
||||||
|
{
|
||||||
|
pushState(State());
|
||||||
|
}
|
||||||
|
|
||||||
Result<Program *, Error> Parse();
|
Result<Program *, Error> Parse();
|
||||||
};
|
};
|
||||||
|
|
||||||
#define SET_STOP_AT(...) currentState().stopAt = {__VA_ARGS__};
|
#define SET_STOP_AT(...) currentState().stopAt = {__VA_ARGS__};
|
||||||
}; // namespace Fig
|
} // namespace Fig
|
||||||
|
|||||||
@@ -7,6 +7,7 @@ int main()
|
|||||||
|
|
||||||
String fileName = "test.fig";
|
String fileName = "test.fig";
|
||||||
String filePath = "T:/Files/Maker/Code/MyCodingLanguage/The Fig Project/Fig/test.fig";
|
String filePath = "T:/Files/Maker/Code/MyCodingLanguage/The Fig Project/Fig/test.fig";
|
||||||
|
|
||||||
SourceManager srcManager(filePath);
|
SourceManager srcManager(filePath);
|
||||||
|
|
||||||
String source = srcManager.Read();
|
String source = srcManager.Read();
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
/*!
|
/*!
|
||||||
@file src/Parser/StmtParser.hpp
|
@file src/Parser/StmtParser.cpp
|
||||||
@brief 语法分析器(Pratt + 手动递归下降) 语句解析实现
|
@brief 语法分析器(Pratt + 手动递归下降) 语句解析实现
|
||||||
@author PuqiAR (im@puqiar.top)
|
@author PuqiAR (im@puqiar.top)
|
||||||
@date 2026-02-19
|
@date 2026-02-19
|
||||||
@@ -9,10 +9,10 @@
|
|||||||
|
|
||||||
namespace Fig
|
namespace Fig
|
||||||
{
|
{
|
||||||
Result<BlockStmt *, Error> Parser::parseBlockStmt() // 当前token为 {
|
Result<BlockStmt *, Error> Parser::parseBlockStmt()
|
||||||
{
|
{
|
||||||
SourceLocation location = makeSourceLocation(consumeToken()); // consume `{`
|
SourceLocation location = makeSourceLocation(consumeToken());
|
||||||
BlockStmt *stmt = new BlockStmt();
|
BlockStmt *stmt = arena.Allocate<BlockStmt>();
|
||||||
while (true)
|
while (true)
|
||||||
{
|
{
|
||||||
if (isEOF)
|
if (isEOF)
|
||||||
@@ -35,24 +35,23 @@ namespace Fig
|
|||||||
}
|
}
|
||||||
return stmt;
|
return stmt;
|
||||||
}
|
}
|
||||||
Result<VarDecl *, Error> Parser::parseVarDecl(
|
|
||||||
bool isPublic) // 由 parseStatement调用, 当前token为 var
|
Result<VarDecl *, Error> Parser::parseVarDecl(bool isPublic)
|
||||||
{
|
{
|
||||||
StateProtector p(this, {State::ParsingVarDecl});
|
StateProtector p(this, {State::ParsingVarDecl});
|
||||||
|
|
||||||
SourceLocation location = makeSourceLocation(consumeToken()); // consume `var`
|
SourceLocation location = makeSourceLocation(consumeToken());
|
||||||
|
|
||||||
if (currentToken().type != TokenType::Identifier)
|
if (currentToken().type != TokenType::Identifier)
|
||||||
{
|
{
|
||||||
return std::unexpected(makeUnexpectTokenError("VarDecl", "var name", currentToken()));
|
return std::unexpected(makeUnexpectTokenError("VarDecl", "var name", currentToken()));
|
||||||
}
|
}
|
||||||
const String &name = srcManager.GetSub(currentToken().index, currentToken().length);
|
const String &name = srcManager.GetSub(currentToken().index, currentToken().length);
|
||||||
consumeToken(); // consume name
|
consumeToken();
|
||||||
|
|
||||||
TypeExpr *typeSpeicifer = nullptr;
|
TypeExpr *typeSpeicifer = nullptr;
|
||||||
if (match(TokenType::Colon)) // `:`
|
if (match(TokenType::Colon))
|
||||||
{
|
{
|
||||||
// SET_STOP_AT(TokenType::Walrus, TokenType::Assign);
|
|
||||||
auto result = parseTypeExpr();
|
auto result = parseTypeExpr();
|
||||||
if (!result)
|
if (!result)
|
||||||
{
|
{
|
||||||
@@ -72,15 +71,14 @@ namespace Fig
|
|||||||
}
|
}
|
||||||
initExpr = *result;
|
initExpr = *result;
|
||||||
}
|
}
|
||||||
else if (match(TokenType::Walrus)) // :=
|
else if (match(TokenType::Walrus))
|
||||||
{
|
{
|
||||||
if (typeSpeicifer) // 指定了类型同时使用 :=
|
if (typeSpeicifer)
|
||||||
{
|
{
|
||||||
return std::unexpected(Error(ErrorType::SyntaxError,
|
return std::unexpected(Error(ErrorType::SyntaxError,
|
||||||
"used type infer but specifying the type",
|
"used type infer but specifying the type",
|
||||||
"change `:=` to '='",
|
"change `:=` to '='",
|
||||||
makeSourceLocation(prevToken()) // :=
|
makeSourceLocation(prevToken())));
|
||||||
));
|
|
||||||
}
|
}
|
||||||
auto result = parseExpression();
|
auto result = parseExpression();
|
||||||
if (!result)
|
if (!result)
|
||||||
@@ -88,24 +86,25 @@ namespace Fig
|
|||||||
return std::unexpected(result.error());
|
return std::unexpected(result.error());
|
||||||
}
|
}
|
||||||
initExpr = *result;
|
initExpr = *result;
|
||||||
isInfer = true; // 使用类型自动推断 :=
|
isInfer = true;
|
||||||
}
|
}
|
||||||
if (!match(TokenType::Semicolon))
|
if (!match(TokenType::Semicolon))
|
||||||
{
|
{
|
||||||
return std::unexpected(makeExpectSemicolonError());
|
return std::unexpected(makeExpectSemicolonError());
|
||||||
}
|
}
|
||||||
VarDecl *varDecl = new VarDecl(isPublic, name, typeSpeicifer, isInfer, initExpr, location);
|
VarDecl *varDecl =
|
||||||
|
arena.Allocate<VarDecl>(isPublic, name, typeSpeicifer, isInfer, initExpr, location);
|
||||||
return varDecl;
|
return varDecl;
|
||||||
}
|
}
|
||||||
|
|
||||||
Result<IfStmt *, Error> Parser::parseIfStmt() // 由 parseStatement调用, 当前token is if
|
Result<IfStmt *, Error> Parser::parseIfStmt()
|
||||||
{
|
{
|
||||||
StateProtector p(this, {State::ParsingIf});
|
StateProtector p(this, {State::ParsingIf});
|
||||||
|
|
||||||
SourceLocation location = makeSourceLocation(consumeToken()); // consume `if`
|
SourceLocation location = makeSourceLocation(consumeToken());
|
||||||
|
|
||||||
Expr *cond = nullptr;
|
Expr *cond = nullptr;
|
||||||
if (match(TokenType::LeftParen)) // match and consume `(`
|
if (match(TokenType::LeftParen))
|
||||||
{
|
{
|
||||||
const Token &lpToken = prevToken();
|
const Token &lpToken = prevToken();
|
||||||
SET_STOP_AT(TokenType::RightParen, TokenType::LeftBrace);
|
SET_STOP_AT(TokenType::RightParen, TokenType::LeftBrace);
|
||||||
@@ -116,7 +115,6 @@ namespace Fig
|
|||||||
}
|
}
|
||||||
if (!match(TokenType::RightParen))
|
if (!match(TokenType::RightParen))
|
||||||
{
|
{
|
||||||
delete *result;
|
|
||||||
return std::unexpected(Error(ErrorType::SyntaxError,
|
return std::unexpected(Error(ErrorType::SyntaxError,
|
||||||
"unclosed parenthese in if condition",
|
"unclosed parenthese in if condition",
|
||||||
"insert `)`",
|
"insert `)`",
|
||||||
@@ -155,7 +153,6 @@ namespace Fig
|
|||||||
SourceLocation elseLocation = makeSourceLocation(prevToken());
|
SourceLocation elseLocation = makeSourceLocation(prevToken());
|
||||||
if (match(TokenType::If))
|
if (match(TokenType::If))
|
||||||
{
|
{
|
||||||
// else if
|
|
||||||
if (alternate)
|
if (alternate)
|
||||||
{
|
{
|
||||||
return std::unexpected(Error(ErrorType::SyntaxError,
|
return std::unexpected(Error(ErrorType::SyntaxError,
|
||||||
@@ -166,7 +163,7 @@ namespace Fig
|
|||||||
|
|
||||||
Expr *cond = nullptr;
|
Expr *cond = nullptr;
|
||||||
|
|
||||||
if (match(TokenType::LeftParen)) // `(`
|
if (match(TokenType::LeftParen))
|
||||||
{
|
{
|
||||||
const Token &lpToken = prevToken();
|
const Token &lpToken = prevToken();
|
||||||
|
|
||||||
@@ -178,7 +175,6 @@ namespace Fig
|
|||||||
}
|
}
|
||||||
if (!match(TokenType::RightParen))
|
if (!match(TokenType::RightParen))
|
||||||
{
|
{
|
||||||
delete *result;
|
|
||||||
return std::unexpected(Error(ErrorType::SyntaxError,
|
return std::unexpected(Error(ErrorType::SyntaxError,
|
||||||
"unclosed parenthese in if condition",
|
"unclosed parenthese in if condition",
|
||||||
"insert `)`",
|
"insert `)`",
|
||||||
@@ -207,12 +203,11 @@ namespace Fig
|
|||||||
return std::unexpected(result.error());
|
return std::unexpected(result.error());
|
||||||
}
|
}
|
||||||
BlockStmt *consequent = *result;
|
BlockStmt *consequent = *result;
|
||||||
ElseIfStmt *elif = new ElseIfStmt(cond, consequent, elseLocation);
|
ElseIfStmt *elif = arena.Allocate<ElseIfStmt>(cond, consequent, elseLocation);
|
||||||
elifs.push_back(elif);
|
elifs.push_back(elif);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
// else
|
|
||||||
if (alternate)
|
if (alternate)
|
||||||
{
|
{
|
||||||
return std::unexpected(Error(ErrorType::SyntaxError,
|
return std::unexpected(Error(ErrorType::SyntaxError,
|
||||||
@@ -233,15 +228,15 @@ namespace Fig
|
|||||||
alternate = *result;
|
alternate = *result;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
IfStmt *ifStmt = new IfStmt(cond, consequent, elifs, alternate, location);
|
IfStmt *ifStmt = arena.Allocate<IfStmt>(cond, consequent, elifs, alternate, location);
|
||||||
return ifStmt;
|
return ifStmt;
|
||||||
}
|
}
|
||||||
|
|
||||||
Result<WhileStmt *, Error> Parser::parseWhileStmt() // 由 parseStatement调用, 当前token为 while
|
Result<WhileStmt *, Error> Parser::parseWhileStmt()
|
||||||
{
|
{
|
||||||
StateProtector p(this, {State::ParsingWhile});
|
StateProtector p(this, {State::ParsingWhile});
|
||||||
|
|
||||||
SourceLocation location = makeSourceLocation(consumeToken()); // consume `while`
|
SourceLocation location = makeSourceLocation(consumeToken());
|
||||||
|
|
||||||
Expr *cond = nullptr;
|
Expr *cond = nullptr;
|
||||||
if (match(TokenType::LeftParen))
|
if (match(TokenType::LeftParen))
|
||||||
@@ -257,7 +252,6 @@ namespace Fig
|
|||||||
|
|
||||||
if (!match(TokenType::RightParen))
|
if (!match(TokenType::RightParen))
|
||||||
{
|
{
|
||||||
delete *result;
|
|
||||||
return std::unexpected(Error(ErrorType::SyntaxError,
|
return std::unexpected(Error(ErrorType::SyntaxError,
|
||||||
"unclosed parenthese in while condition",
|
"unclosed parenthese in while condition",
|
||||||
"insert ')'",
|
"insert ')'",
|
||||||
@@ -278,7 +272,6 @@ namespace Fig
|
|||||||
|
|
||||||
if (currentToken().type != TokenType::LeftBrace)
|
if (currentToken().type != TokenType::LeftBrace)
|
||||||
{
|
{
|
||||||
delete cond;
|
|
||||||
return std::unexpected(
|
return std::unexpected(
|
||||||
makeUnexpectTokenError("while stmt", "left brace '{'", currentToken()));
|
makeUnexpectTokenError("while stmt", "left brace '{'", currentToken()));
|
||||||
}
|
}
|
||||||
@@ -286,20 +279,19 @@ namespace Fig
|
|||||||
auto result = parseBlockStmt();
|
auto result = parseBlockStmt();
|
||||||
if (!result)
|
if (!result)
|
||||||
{
|
{
|
||||||
delete cond;
|
|
||||||
return std::unexpected(result.error());
|
return std::unexpected(result.error());
|
||||||
}
|
}
|
||||||
BlockStmt *body = *result;
|
BlockStmt *body = *result;
|
||||||
|
|
||||||
WhileStmt *whileStmt = new WhileStmt(cond, body, location);
|
WhileStmt *whileStmt = arena.Allocate<WhileStmt>(cond, body, location);
|
||||||
return whileStmt;
|
return whileStmt;
|
||||||
}
|
}
|
||||||
|
|
||||||
Result<DynArray<Param *>, Error> Parser::parseFnParams() // 由 parseFnDefStmt或lambda调用
|
Result<DynArray<Param *>, Error> Parser::parseFnParams()
|
||||||
{
|
{
|
||||||
StateProtector p(this, {State::ParsingFnDefStmt});
|
StateProtector p(this, {State::ParsingFnDefStmt});
|
||||||
|
|
||||||
const Token &lpToken = consumeToken(); // consume `(`
|
const Token &lpToken = consumeToken();
|
||||||
DynArray<Param *> params;
|
DynArray<Param *> params;
|
||||||
|
|
||||||
while (true)
|
while (true)
|
||||||
@@ -320,10 +312,8 @@ namespace Fig
|
|||||||
SourceLocation location = makeSourceLocation(nToken);
|
SourceLocation location = makeSourceLocation(nToken);
|
||||||
const String &name = srcManager.GetSub(nToken.index, nToken.length);
|
const String &name = srcManager.GetSub(nToken.index, nToken.length);
|
||||||
|
|
||||||
// TODO: 支持剩余参数解析...
|
|
||||||
|
|
||||||
TypeExpr *type = nullptr;
|
TypeExpr *type = nullptr;
|
||||||
if (match(TokenType::Colon)) // :
|
if (match(TokenType::Colon))
|
||||||
{
|
{
|
||||||
auto result = parseTypeExpr();
|
auto result = parseTypeExpr();
|
||||||
if (!result)
|
if (!result)
|
||||||
@@ -335,22 +325,18 @@ namespace Fig
|
|||||||
|
|
||||||
Expr *defaultValue = nullptr;
|
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();
|
auto result = parseExpression();
|
||||||
if (!result)
|
if (!result)
|
||||||
{
|
{
|
||||||
if (type)
|
|
||||||
{
|
|
||||||
delete type;
|
|
||||||
}
|
|
||||||
return std::unexpected(result.error());
|
return std::unexpected(result.error());
|
||||||
}
|
}
|
||||||
defaultValue = *result;
|
defaultValue = *result;
|
||||||
}
|
}
|
||||||
|
|
||||||
PosParam *posParam = new PosParam(name, type, defaultValue, location);
|
PosParam *posParam = arena.Allocate<PosParam>(name, type, defaultValue, location);
|
||||||
params.push_back(posParam);
|
params.push_back(posParam);
|
||||||
|
|
||||||
if (match(TokenType::Comma))
|
if (match(TokenType::Comma))
|
||||||
@@ -365,18 +351,16 @@ namespace Fig
|
|||||||
return params;
|
return params;
|
||||||
}
|
}
|
||||||
|
|
||||||
Result<FnDefStmt *, Error> Parser::parseFnDefStmt(
|
Result<FnDefStmt *, Error> Parser::parseFnDefStmt(bool isPublic)
|
||||||
bool isPublic) // 由 parseStatement调用, 当前token为 func
|
|
||||||
{
|
{
|
||||||
SourceLocation location = makeSourceLocation(
|
SourceLocation location = makeSourceLocation(consumeToken());
|
||||||
consumeToken()); // 无论是否加了public, location都设置为 func token (我懒 :D)
|
|
||||||
|
|
||||||
if (!currentToken().isIdentifier())
|
if (!currentToken().isIdentifier())
|
||||||
{
|
{
|
||||||
return std::unexpected(
|
return std::unexpected(
|
||||||
makeUnexpectTokenError("fn def stmt", "function name", currentToken()));
|
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);
|
const String &name = srcManager.GetSub(nameToken.index, nameToken.length);
|
||||||
|
|
||||||
if (currentToken().type != TokenType::LeftParen)
|
if (currentToken().type != TokenType::LeftParen)
|
||||||
@@ -395,7 +379,7 @@ namespace Fig
|
|||||||
params = *paraResult;
|
params = *paraResult;
|
||||||
|
|
||||||
TypeExpr *returnType = nullptr;
|
TypeExpr *returnType = nullptr;
|
||||||
if (match(TokenType::RightArrow)) // ->
|
if (match(TokenType::RightArrow))
|
||||||
{
|
{
|
||||||
auto result = parseTypeExpr();
|
auto result = parseTypeExpr();
|
||||||
if (!result)
|
if (!result)
|
||||||
@@ -415,24 +399,20 @@ namespace Fig
|
|||||||
|
|
||||||
if (!bodyResult)
|
if (!bodyResult)
|
||||||
{
|
{
|
||||||
if (returnType)
|
|
||||||
{
|
|
||||||
delete returnType;
|
|
||||||
}
|
|
||||||
return std::unexpected(bodyResult.error());
|
return std::unexpected(bodyResult.error());
|
||||||
}
|
}
|
||||||
body = *bodyResult;
|
body = *bodyResult;
|
||||||
|
|
||||||
FnDefStmt *fnDef = new FnDefStmt(isPublic, name, params, returnType, body, location);
|
FnDefStmt *fnDef =
|
||||||
|
arena.Allocate<FnDefStmt>(isPublic, name, params, returnType, body, location);
|
||||||
return fnDef;
|
return fnDef;
|
||||||
}
|
}
|
||||||
|
|
||||||
Result<ReturnStmt *, Error>
|
Result<ReturnStmt *, Error> Parser::parseReturnStmt()
|
||||||
Parser::parseReturnStmt() // 由 parseStatement调用, 当前token为 return
|
|
||||||
{
|
{
|
||||||
StateProtector p(this, {State::ParsingReturn});
|
StateProtector p(this, {State::ParsingReturn});
|
||||||
|
|
||||||
SourceLocation location = makeSourceLocation(consumeToken()); // consume `return`
|
SourceLocation location = makeSourceLocation(consumeToken());
|
||||||
auto result = parseExpression();
|
auto result = parseExpression();
|
||||||
if (!result)
|
if (!result)
|
||||||
{
|
{
|
||||||
@@ -440,7 +420,7 @@ namespace Fig
|
|||||||
}
|
}
|
||||||
|
|
||||||
Expr *value = *result;
|
Expr *value = *result;
|
||||||
ReturnStmt *returnStmt = new ReturnStmt(value, location);
|
ReturnStmt *returnStmt = arena.Allocate<ReturnStmt>(value, location);
|
||||||
|
|
||||||
if (!match(TokenType::Semicolon))
|
if (!match(TokenType::Semicolon))
|
||||||
{
|
{
|
||||||
@@ -455,7 +435,7 @@ namespace Fig
|
|||||||
|
|
||||||
if (currentToken().type == TokenType::Public)
|
if (currentToken().type == TokenType::Public)
|
||||||
{
|
{
|
||||||
consumeToken(); // consume `public`
|
consumeToken();
|
||||||
if (currentToken().type == TokenType::Variable)
|
if (currentToken().type == TokenType::Variable)
|
||||||
{
|
{
|
||||||
return parseVarDecl(true);
|
return parseVarDecl(true);
|
||||||
@@ -507,7 +487,7 @@ namespace Fig
|
|||||||
{
|
{
|
||||||
return std::unexpected(makeExpectSemicolonError());
|
return std::unexpected(makeExpectSemicolonError());
|
||||||
}
|
}
|
||||||
BreakStmt *breakStmt = new BreakStmt(location);
|
BreakStmt *breakStmt = arena.Allocate<BreakStmt>(location);
|
||||||
return breakStmt;
|
return breakStmt;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -518,7 +498,7 @@ namespace Fig
|
|||||||
{
|
{
|
||||||
return std::unexpected(makeExpectSemicolonError());
|
return std::unexpected(makeExpectSemicolonError());
|
||||||
}
|
}
|
||||||
ContinueStmt *continueStmt = new ContinueStmt(location);
|
ContinueStmt *continueStmt = arena.Allocate<ContinueStmt>(location);
|
||||||
return continueStmt;
|
return continueStmt;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -532,7 +512,7 @@ namespace Fig
|
|||||||
{
|
{
|
||||||
return std::unexpected(expr_result.error());
|
return std::unexpected(expr_result.error());
|
||||||
}
|
}
|
||||||
ExprStmt *exprStmt = new ExprStmt(*expr_result);
|
ExprStmt *exprStmt = arena.Allocate<ExprStmt>(*expr_result);
|
||||||
if (!match(TokenType::Semicolon))
|
if (!match(TokenType::Semicolon))
|
||||||
{
|
{
|
||||||
return std::unexpected(makeExpectSemicolonError());
|
return std::unexpected(makeExpectSemicolonError());
|
||||||
|
|||||||
@@ -1,56 +1,73 @@
|
|||||||
/*!
|
/*!
|
||||||
@file src/Parser/TypeExprParser.cpp
|
@file src/Parser/TypeExprParser.cpp
|
||||||
@brief 类型表达式解析器实现
|
@brief 类型表达式解析器实现:支持泛型与空安全
|
||||||
@author PuqiAR (im@puqiar.top)
|
@author PuqiAR (im@puqiar.top)
|
||||||
@date 2026-02-25
|
@date 2026-03-08
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#pragma once
|
|
||||||
|
|
||||||
#include <Parser/Parser.hpp>
|
#include <Parser/Parser.hpp>
|
||||||
|
|
||||||
namespace Fig
|
namespace Fig
|
||||||
{
|
{
|
||||||
Result<NamedTypeExpr *, Error> Parser::parseNamedTypeExpr() // 当前token为identifier
|
// 解析基础命名类型与泛型: List<Int>
|
||||||
|
Result<TypeExpr *, Error> Parser::parseNamedTypeExpr()
|
||||||
{
|
{
|
||||||
StateProtector p(this, {State::ParsingNamedTypeExpr});
|
StateProtector p(this, {State::ParsingNamedTypeExpr});
|
||||||
|
|
||||||
SourceLocation location = makeSourceLocation(currentToken());
|
SourceLocation location = makeSourceLocation(currentToken());
|
||||||
|
|
||||||
DynArray<String> path;
|
DynArray<String> path;
|
||||||
while (true)
|
while (true)
|
||||||
{
|
{
|
||||||
const Token &subPathTok = consumeToken();
|
const Token &tok = consumeToken();
|
||||||
const String &subPath = srcManager.GetSub(subPathTok.index, subPathTok.length);
|
const String &name = srcManager.GetSub(tok.index, tok.length);
|
||||||
path.push_back(subPath);
|
path.push_back(name);
|
||||||
|
|
||||||
if (match(TokenType::Dot))
|
if (match(TokenType::Dot))
|
||||||
{
|
{
|
||||||
if (!currentToken().isIdentifier())
|
if (!currentToken().isIdentifier())
|
||||||
{
|
return std::unexpected(makeUnexpectTokenError("Type", "identifier", currentToken()));
|
||||||
return std::unexpected(
|
|
||||||
makeUnexpectTokenError("named type expr", "identifier", currentToken()));
|
|
||||||
}
|
}
|
||||||
}
|
else break;
|
||||||
else
|
|
||||||
{
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
NamedTypeExpr *namedTypeExpr = new NamedTypeExpr(path, location);
|
|
||||||
return namedTypeExpr;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
DynArray<TypeExpr *> arguments;
|
||||||
|
if (match(TokenType::Less)) // `<`
|
||||||
|
{
|
||||||
|
while (true)
|
||||||
|
{
|
||||||
|
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()));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return arena.Allocate<NamedTypeExpr>(path, arguments, location);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 解析主入口: 处理 `?` 后缀
|
||||||
Result<TypeExpr *, Error> Parser::parseTypeExpr()
|
Result<TypeExpr *, Error> Parser::parseTypeExpr()
|
||||||
{
|
{
|
||||||
// TODO: 泛型表达式解析
|
TypeExpr *base = nullptr;
|
||||||
|
|
||||||
|
// 目前只支持命名类型 (以后可以加函数类型 (Int)->Int)
|
||||||
if (currentToken().isIdentifier())
|
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
|
@file src/Sema/Analyzer.hpp
|
||||||
@brief 前端类型检查器定义
|
@brief 语义分析器定义
|
||||||
@author PuqiAR (im@puqiar.top)
|
|
||||||
@date 2026-02-23
|
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include <Sema/Environment.hpp>
|
|
||||||
#include <Sema/Type.hpp>
|
|
||||||
|
|
||||||
#include <Ast/Ast.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
|
namespace Fig
|
||||||
{
|
{
|
||||||
class Analyzer
|
class Analyzer
|
||||||
{
|
{
|
||||||
private:
|
private:
|
||||||
Environment env;
|
Arena arena;
|
||||||
SourceManager &manager;
|
SourceManager &manager;
|
||||||
|
|
||||||
TypeContext typeCtx;
|
TypeContext typeCtx;
|
||||||
|
Environment env;
|
||||||
|
Diagnostics diag;
|
||||||
|
|
||||||
TypeInfo *currentReturnType = nullptr; // 正在分析的函数,预期返回类型
|
HashMap<String, BaseType*> globalTypes;
|
||||||
|
HashMap<String, Symbol*> globalSymbols;
|
||||||
|
|
||||||
struct ReturnTypeProtector
|
bool hasInit = false;
|
||||||
{
|
bool hasMain = false;
|
||||||
Analyzer *analyzer;
|
|
||||||
TypeInfo *prevCurrentReturnType;
|
|
||||||
|
|
||||||
[[nodiscard]]
|
// 核心递归查找:解决跨越函数边界的捕获问题
|
||||||
ReturnTypeProtector(Analyzer *_analyzer, TypeInfo *current) :
|
Result<Symbol*, Error> resolveSymbolInternal(const String &name, const SourceLocation &loc, Scope* startScope);
|
||||||
analyzer(_analyzer), prevCurrentReturnType(_analyzer->currentReturnType)
|
|
||||||
{
|
|
||||||
analyzer->currentReturnType = current;
|
|
||||||
}
|
|
||||||
|
|
||||||
~ReturnTypeProtector()
|
Result<Type, Error> resolveTypeExpr(TypeExpr *texpr);
|
||||||
{
|
Result<void, Error> pass1(Program *prog);
|
||||||
analyzer->currentReturnType = prevCurrentReturnType;
|
Result<void, Error> resolveTypes(Program *prog);
|
||||||
}
|
Result<void, Error> checkBodies(Program *prog);
|
||||||
|
|
||||||
ReturnTypeProtector(const ReturnTypeProtector &) = delete;
|
Result<void, Error> analyzeStmt(Stmt *stmt);
|
||||||
ReturnTypeProtector &operator=(const ReturnTypeProtector &) = delete;
|
Result<Type, Error> analyzeExpr(Expr *expr);
|
||||||
};
|
|
||||||
|
|
||||||
|
int addUpvalue(Scope *scope, Symbol *target, bool isLocal);
|
||||||
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 *);
|
|
||||||
|
|
||||||
public:
|
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 <Parser/Parser.hpp>
|
||||||
#include <SourceManager/SourceManager.hpp>
|
#include <Sema/Analyzer.hpp>
|
||||||
|
#include <filesystem>
|
||||||
#include <iostream>
|
#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()
|
int main()
|
||||||
{
|
{
|
||||||
using namespace Fig;
|
std::string testDir = "T:/Files/Maker/Code/MyCodingLanguage/The Fig Project/Fig/tests/Sema";
|
||||||
|
for (const auto &entry : fs::directory_iterator(testDir))
|
||||||
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::cerr << "Read file failed \n";
|
if (entry.path().extension() == ".fig")
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
Lexer lexer(manager.GetSource(), fileName);
|
|
||||||
Parser parser(lexer, manager, fileName);
|
|
||||||
|
|
||||||
auto result = parser.Parse();
|
|
||||||
if (!result)
|
|
||||||
{
|
{
|
||||||
ReportError(result.error(), manager);
|
runTest(entry.path().string());
|
||||||
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;
|
return 0;
|
||||||
}
|
}
|
||||||
@@ -1,147 +1,74 @@
|
|||||||
/*!
|
/*!
|
||||||
@file src/Sema/Environment.hpp
|
@file src/Sema/Environment.hpp
|
||||||
@brief 符号和作用域环境定义
|
@brief 树状符号表定义
|
||||||
@author PuqiAR (im@puqiar.top)
|
|
||||||
@date 2026-02-23
|
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include <Deps/Deps.hpp>
|
#include <Deps/Deps.hpp>
|
||||||
#include <Error/Error.hpp>
|
|
||||||
#include <Sema/Type.hpp>
|
#include <Sema/Type.hpp>
|
||||||
|
|
||||||
#include <cassert>
|
|
||||||
#include <optional>
|
|
||||||
|
|
||||||
namespace Fig
|
namespace Fig
|
||||||
{
|
{
|
||||||
// 记录在 Analyzer 中的符号元数据
|
enum class SymbolLocation
|
||||||
|
{
|
||||||
|
Global,
|
||||||
|
Local,
|
||||||
|
Upvalue
|
||||||
|
};
|
||||||
|
|
||||||
struct Symbol
|
struct Symbol
|
||||||
{
|
{
|
||||||
String name;
|
String name;
|
||||||
TypeInfo *type;
|
Type type;
|
||||||
bool isPublic;
|
SymbolLocation location;
|
||||||
int depth; // 词法作用域深度
|
int index;
|
||||||
bool isConstant; // 是否是 const 声明的不可变常量 (用于报错: 尝试修改常量)
|
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 UpvalueCapture
|
||||||
struct ScopeWatermark
|
|
||||||
{
|
{
|
||||||
std::size_t symbolCount;
|
Symbol *target;
|
||||||
int savedLocalId;
|
int index;
|
||||||
|
bool isLocal;
|
||||||
};
|
};
|
||||||
|
|
||||||
// 语义分析函数上下文 (隔离局部变量 ID 空间)
|
struct Scope
|
||||||
struct SemaFuncState
|
|
||||||
{
|
{
|
||||||
SemaFuncState *enclosing = nullptr;
|
Scope *parent = nullptr;
|
||||||
int currentDepth = 0;
|
bool isFunctionBoundary = false;
|
||||||
|
|
||||||
|
HashMap<String, Symbol *> locals;
|
||||||
|
DynArray<UpvalueCapture> upvalues;
|
||||||
|
|
||||||
int nextLocalId = 0;
|
int nextLocalId = 0;
|
||||||
DynArray<ScopeWatermark> scopeStack;
|
|
||||||
|
Scope(Scope *p, bool isFn) : parent(p), isFunctionBoundary(isFn)
|
||||||
|
{
|
||||||
|
if (p && !isFn)
|
||||||
|
nextLocalId = p->nextLocalId;
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
class Environment
|
class Environment
|
||||||
{
|
{
|
||||||
private:
|
|
||||||
DynArray<Symbol> symbols;
|
|
||||||
SemaFuncState *current = nullptr;
|
|
||||||
|
|
||||||
public:
|
public:
|
||||||
Environment()
|
Scope *current = nullptr;
|
||||||
|
|
||||||
|
void Push(bool isFn)
|
||||||
{
|
{
|
||||||
current = new SemaFuncState();
|
current = new Scope(current, isFn);
|
||||||
}
|
}
|
||||||
|
void Pop()
|
||||||
~Environment()
|
|
||||||
{
|
{
|
||||||
while (current)
|
Scope *old = current;
|
||||||
{
|
current = current->parent;
|
||||||
SemaFuncState *prev = current->enclosing;
|
delete old;
|
||||||
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;
|
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
} // 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,136 +1,115 @@
|
|||||||
/*!
|
/*!
|
||||||
@file src/Sema/Type.hpp
|
@file src/Sema/Type.hpp
|
||||||
@brief 前端类型检查的类型定义和类型驻留池
|
@brief 类型系统定义:对齐 NaN-boxing 物理布局
|
||||||
@author PuqiAR (im@puqiar.top)
|
|
||||||
@date 2026-02-23
|
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include <Deps/Deps.hpp>
|
#include <Deps/Deps.hpp>
|
||||||
#include <cstdint>
|
#include <Error/Error.hpp>
|
||||||
|
|
||||||
namespace Fig
|
namespace Fig
|
||||||
{
|
{
|
||||||
enum class TypeTag : std::uint8_t
|
enum class TypeTag : std::uint8_t
|
||||||
{
|
{
|
||||||
Any, // 动态类型底线
|
|
||||||
Null, // 空值
|
|
||||||
Int,
|
Int,
|
||||||
Double,
|
Double,
|
||||||
Bool,
|
|
||||||
String,
|
String,
|
||||||
|
Bool,
|
||||||
|
Null,
|
||||||
|
Any,
|
||||||
Function,
|
Function,
|
||||||
Struct,
|
Struct,
|
||||||
|
Interface
|
||||||
};
|
};
|
||||||
|
|
||||||
struct TypeInfo
|
class BaseType;
|
||||||
{
|
|
||||||
TypeTag tag;
|
|
||||||
String name; // 完整路径序列化, 如 Int, std.file.File
|
|
||||||
|
|
||||||
bool isAny() const
|
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;
|
||||||
|
BaseType(TypeTag t, String n) : tag(t), name(std::move(n)) {}
|
||||||
|
virtual ~BaseType() = default;
|
||||||
|
};
|
||||||
|
|
||||||
|
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;
|
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
// 全局唯一类型驻留池
|
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
|
class TypeContext
|
||||||
{
|
{
|
||||||
private:
|
|
||||||
DynArray<TypeInfo *> allTypes;
|
|
||||||
|
|
||||||
// 缓存
|
|
||||||
TypeInfo *typeAny;
|
|
||||||
TypeInfo *typeNull;
|
|
||||||
TypeInfo *typeInt;
|
|
||||||
TypeInfo *typeDouble;
|
|
||||||
TypeInfo *typeBool;
|
|
||||||
TypeInfo *typeString;
|
|
||||||
TypeInfo *typeFunction;
|
|
||||||
TypeInfo *typeStruct;
|
|
||||||
|
|
||||||
public:
|
public:
|
||||||
TypeInfo *GetAny()
|
DynArray<BaseType *> allTypes;
|
||||||
{
|
BaseType *intType, *doubleType, *stringType, *boolType, *anyType, *nullType;
|
||||||
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;
|
|
||||||
}
|
|
||||||
|
|
||||||
TypeInfo *ResolveTypePath(const String &fullName)
|
TypeContext();
|
||||||
{
|
~TypeContext();
|
||||||
for (auto *t : allTypes)
|
|
||||||
{
|
|
||||||
if (t->name == fullName)
|
|
||||||
return t;
|
|
||||||
}
|
|
||||||
return nullptr; // 没找到该类型
|
|
||||||
}
|
|
||||||
|
|
||||||
TypeInfo *ResolveTypePath(const DynArray<String> &path)
|
Type GetBasic(TypeTag tag, bool nullable = false);
|
||||||
{
|
Type CreateFuncType(DynArray<Type> params, Type ret);
|
||||||
// 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;
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
}; // namespace Fig
|
} // namespace Fig
|
||||||
|
|||||||
115
src/Utils/Arena.hpp
Normal file
115
src/Utils/Arena.hpp
Normal file
@@ -0,0 +1,115 @@
|
|||||||
|
/*!
|
||||||
|
@file src/Utils/Arena.hpp
|
||||||
|
@brief 线性分配内存池,支持非平凡析构对象的自动清理
|
||||||
|
@author PuqiAR (im@puqiar.top)
|
||||||
|
@date 2026-03-08
|
||||||
|
*/
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <cstddef>
|
||||||
|
#include <vector>
|
||||||
|
#include <memory>
|
||||||
|
#include <type_traits>
|
||||||
|
|
||||||
|
namespace Fig
|
||||||
|
{
|
||||||
|
class Arena
|
||||||
|
{
|
||||||
|
private:
|
||||||
|
struct DestructorNode
|
||||||
|
{
|
||||||
|
void (*destructor)(void *);
|
||||||
|
void *object;
|
||||||
|
DestructorNode *next;
|
||||||
|
};
|
||||||
|
|
||||||
|
static constexpr std::size_t CHUNK_SIZE = 64 * 1024; // 64KB 块大小
|
||||||
|
|
||||||
|
std::vector<char *> chunks;
|
||||||
|
char *currentPtr = nullptr;
|
||||||
|
std::size_t remaining = 0;
|
||||||
|
DestructorNode *destructorHead = nullptr;
|
||||||
|
|
||||||
|
public:
|
||||||
|
Arena() = default;
|
||||||
|
|
||||||
|
~Arena()
|
||||||
|
{
|
||||||
|
// 逆序调用析构函数
|
||||||
|
DestructorNode *node = destructorHead;
|
||||||
|
while (node)
|
||||||
|
{
|
||||||
|
node->destructor(node->object);
|
||||||
|
node = node->next;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 释放所有分配的内存块
|
||||||
|
for (char *chunk : chunks)
|
||||||
|
{
|
||||||
|
delete[] chunk;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 禁止拷贝和移动,防止内存所有权混乱
|
||||||
|
Arena(const Arena &) = delete;
|
||||||
|
Arena &operator=(const Arena &) = delete;
|
||||||
|
|
||||||
|
template <typename T, typename... Args>
|
||||||
|
T *Allocate(Args &&...args)
|
||||||
|
{
|
||||||
|
std::size_t size = sizeof(T);
|
||||||
|
std::size_t alignment = alignof(T);
|
||||||
|
|
||||||
|
// 在当前块中尝试对齐并分配
|
||||||
|
void *ptr = allocateRaw(size, alignment);
|
||||||
|
|
||||||
|
// 在分配的内存上构造对象
|
||||||
|
T *obj = new (ptr) T(std::forward<Args>(args)...);
|
||||||
|
|
||||||
|
// 如果 T 需要析构(如包含 String),注册到销毁链表
|
||||||
|
if constexpr (!std::is_trivially_destructible_v<T>)
|
||||||
|
{
|
||||||
|
// 注意: DestructorNode 本身是 POD,直接在 Arena 里分配,不需要注册析构
|
||||||
|
void *nodeRaw = allocateRaw(sizeof(DestructorNode), alignof(DestructorNode));
|
||||||
|
DestructorNode *node = new (nodeRaw) DestructorNode();
|
||||||
|
|
||||||
|
node->object = obj;
|
||||||
|
node->destructor = [](void *p) { static_cast<T *>(p)->~T(); };
|
||||||
|
node->next = destructorHead;
|
||||||
|
destructorHead = node;
|
||||||
|
}
|
||||||
|
|
||||||
|
return obj;
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
void *allocateRaw(std::size_t size, std::size_t alignment)
|
||||||
|
{
|
||||||
|
// 对齐计算
|
||||||
|
std::size_t adjustment = 0;
|
||||||
|
std::size_t currentAddr = reinterpret_cast<std::size_t>(currentPtr);
|
||||||
|
if (alignment > 0 && (currentAddr % alignment) != 0)
|
||||||
|
{
|
||||||
|
adjustment = alignment - (currentAddr % alignment);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (remaining < (size + adjustment))
|
||||||
|
{
|
||||||
|
// 当前块空间不足,分配新块
|
||||||
|
std::size_t nextChunkSize = (size > CHUNK_SIZE) ? size : CHUNK_SIZE;
|
||||||
|
currentPtr = new char[nextChunkSize];
|
||||||
|
chunks.push_back(currentPtr);
|
||||||
|
remaining = nextChunkSize;
|
||||||
|
adjustment = 0; // 新分配的块通常是最大对齐的
|
||||||
|
}
|
||||||
|
|
||||||
|
currentPtr += adjustment;
|
||||||
|
void *res = currentPtr;
|
||||||
|
currentPtr += size;
|
||||||
|
remaining -= (size + adjustment);
|
||||||
|
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
} // namespace Fig
|
||||||
135
src/VM/VM.cpp
135
src/VM/VM.cpp
@@ -1,13 +1,11 @@
|
|||||||
/*!
|
/*!
|
||||||
@file src/VM/VM.cpp
|
@file src/VM/VM.cpp
|
||||||
@brief 虚拟机核心执行引擎实现
|
@brief 虚拟机核心执行引擎实现
|
||||||
@author PuqiAR (im@puqiar.top)
|
|
||||||
@date 2026-02-19
|
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
#include <Core/Core.hpp>
|
||||||
#include <VM/VM.hpp>
|
#include <VM/VM.hpp>
|
||||||
|
|
||||||
// Computed GOTO!!!
|
|
||||||
#define BINARY_ARITHMETIC_OP(opName, op) \
|
#define BINARY_ARITHMETIC_OP(opName, op) \
|
||||||
do_##opName: \
|
do_##opName: \
|
||||||
{ \
|
{ \
|
||||||
@@ -83,38 +81,57 @@ namespace Fig
|
|||||||
Result<Value, Error> VM::Execute(CompiledModule *compiledModule)
|
Result<Value, Error> VM::Execute(CompiledModule *compiledModule)
|
||||||
{
|
{
|
||||||
Proto *entry = compiledModule->protos[0];
|
Proto *entry = compiledModule->protos[0];
|
||||||
pushFrame(entry, registers);
|
(void) pushFrame(entry, registers); // 刚开始执行寄存器不会溢出
|
||||||
|
|
||||||
// 🔥 必须与 Bytecode.hpp 中的 OpCode 枚举严格一一对应!
|
// 对齐 Bytecode.hpp 中的 OpCode 顺序
|
||||||
static const void *dispatchTable[] = {&&do_Exit,
|
static const void *dispatchTable[] = {&&do_Exit,
|
||||||
|
&&do_Exit_MaxRecursionDepthExceeded,
|
||||||
|
|
||||||
&&do_LoadK,
|
&&do_LoadK,
|
||||||
&&do_LoadTrue,
|
&&do_LoadTrue,
|
||||||
&&do_LoadFalse,
|
&&do_LoadFalse,
|
||||||
&&do_LoadNull,
|
&&do_LoadNull,
|
||||||
|
|
||||||
&&do_FastCall,
|
&&do_FastCall,
|
||||||
&&do_Call,
|
&&do_Call,
|
||||||
&&do_Return,
|
&&do_Return,
|
||||||
|
|
||||||
&&do_LoadFn,
|
&&do_LoadFn,
|
||||||
|
|
||||||
&&do_Jmp,
|
&&do_Jmp,
|
||||||
&&do_JmpIfFalse,
|
&&do_JmpIfFalse,
|
||||||
|
|
||||||
&&do_Mov,
|
&&do_Mov,
|
||||||
|
|
||||||
&&do_Add,
|
&&do_Add,
|
||||||
&&do_Sub,
|
&&do_Sub,
|
||||||
&&do_Mul,
|
&&do_Mul,
|
||||||
&&do_Div,
|
&&do_Div,
|
||||||
&&do_Mod,
|
&&do_Mod,
|
||||||
&&do_BitXor,
|
&&do_BitXor,
|
||||||
|
|
||||||
|
&&do_IntFastAdd,
|
||||||
|
&&do_IntFastSub,
|
||||||
|
&&do_IntFastMul,
|
||||||
|
&&do_IntFastDiv,
|
||||||
|
|
||||||
&&do_Equal,
|
&&do_Equal,
|
||||||
&&do_NotEqual,
|
&&do_NotEqual,
|
||||||
&&do_Greater,
|
&&do_Greater,
|
||||||
&&do_Less,
|
&&do_Less,
|
||||||
&&do_GreaterEqual,
|
&&do_GreaterEqual,
|
||||||
&&do_LessEqual,
|
&&do_LessEqual,
|
||||||
|
|
||||||
|
&&do_GetGlobal,
|
||||||
|
&&do_SetGlobal,
|
||||||
|
&&do_GetUpval,
|
||||||
|
&&do_SetUpval,
|
||||||
|
&&do_Copy,
|
||||||
|
|
||||||
&&do_Count};
|
&&do_Count};
|
||||||
|
|
||||||
Instruction inst;
|
Instruction inst;
|
||||||
|
|
||||||
// 🔥 核心分发引擎:取指 -> 直接查表并 Jump
|
|
||||||
#define DISPATCH() \
|
#define DISPATCH() \
|
||||||
do \
|
do \
|
||||||
{ \
|
{ \
|
||||||
@@ -122,11 +139,19 @@ namespace Fig
|
|||||||
goto *dispatchTable[inst & 0xFF]; \
|
goto *dispatchTable[inst & 0xFF]; \
|
||||||
} while (0)
|
} while (0)
|
||||||
|
|
||||||
// 引擎点火!
|
// 引擎点火!! :3
|
||||||
DISPATCH();
|
DISPATCH();
|
||||||
|
|
||||||
do_Exit: {
|
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: {
|
do_LoadK: {
|
||||||
@@ -158,7 +183,9 @@ namespace Fig
|
|||||||
std::uint8_t a = decodeA(inst);
|
std::uint8_t a = decodeA(inst);
|
||||||
Proto *proto = compiledModule->protos[a];
|
Proto *proto = compiledModule->protos[a];
|
||||||
std::uint8_t baseReg = decodeB(inst);
|
std::uint8_t baseReg = decodeB(inst);
|
||||||
pushFrame(proto, currentFrame->registerBase + baseReg);
|
|
||||||
|
currentFrame->ip = pushFrame(proto, currentFrame->registerBase + baseReg);
|
||||||
|
|
||||||
DISPATCH();
|
DISPATCH();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -169,15 +196,17 @@ namespace Fig
|
|||||||
|
|
||||||
do_Return: {
|
do_Return: {
|
||||||
std::uint8_t a = decodeA(inst);
|
std::uint8_t a = decodeA(inst);
|
||||||
*currentFrame->registerBase = currentFrame->registerBase[a];
|
Value retVal = currentFrame->registerBase[a];
|
||||||
|
|
||||||
|
// 此时 registerBase[0] 指向的是 Caller 的 baseReg 槽位
|
||||||
|
|
||||||
|
currentFrame->registerBase[0] = retVal;
|
||||||
popFrame();
|
popFrame();
|
||||||
|
|
||||||
DISPATCH();
|
DISPATCH();
|
||||||
}
|
}
|
||||||
|
|
||||||
do_LoadFn: {
|
do_LoadFn: {
|
||||||
// std::uint8_t a = decodeA(inst);
|
|
||||||
// std::uint16_t bx = decodeBx(inst);
|
|
||||||
// TODO: R[a] = new FunctionObject(compiledModule->protos[bx])
|
|
||||||
DISPATCH();
|
DISPATCH();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -215,6 +244,55 @@ namespace Fig
|
|||||||
assert(false && "VM: Mod and BitXor not fully implemented yet!");
|
assert(false && "VM: Mod and BitXor not fully implemented yet!");
|
||||||
DISPATCH();
|
DISPATCH();
|
||||||
|
|
||||||
|
do_IntFastAdd: {
|
||||||
|
std::uint8_t a = decodeA(inst);
|
||||||
|
std::uint8_t b = decodeB(inst);
|
||||||
|
std::uint8_t c = decodeC(inst);
|
||||||
|
|
||||||
|
Value l = currentFrame->registerBase[b];
|
||||||
|
Value r = currentFrame->registerBase[c];
|
||||||
|
|
||||||
|
currentFrame->registerBase[a] = Value::FromInt(l.AsInt() + r.AsInt());
|
||||||
|
DISPATCH();
|
||||||
|
}
|
||||||
|
|
||||||
|
do_IntFastSub: {
|
||||||
|
std::uint8_t a = decodeA(inst);
|
||||||
|
std::uint8_t b = decodeB(inst);
|
||||||
|
std::uint8_t c = decodeC(inst);
|
||||||
|
|
||||||
|
Value l = currentFrame->registerBase[b];
|
||||||
|
Value r = currentFrame->registerBase[c];
|
||||||
|
|
||||||
|
currentFrame->registerBase[a] = Value::FromInt(l.AsInt() - r.AsInt());
|
||||||
|
DISPATCH();
|
||||||
|
}
|
||||||
|
|
||||||
|
do_IntFastMul: {
|
||||||
|
std::uint8_t a = decodeA(inst);
|
||||||
|
std::uint8_t b = decodeB(inst);
|
||||||
|
std::uint8_t c = decodeC(inst);
|
||||||
|
|
||||||
|
Value l = currentFrame->registerBase[b];
|
||||||
|
Value r = currentFrame->registerBase[c];
|
||||||
|
|
||||||
|
currentFrame->registerBase[a] = Value::FromInt(l.AsInt() * r.AsInt());
|
||||||
|
DISPATCH();
|
||||||
|
}
|
||||||
|
|
||||||
|
do_IntFastDiv: {
|
||||||
|
std::uint8_t a = decodeA(inst);
|
||||||
|
std::uint8_t b = decodeB(inst);
|
||||||
|
std::uint8_t c = decodeC(inst);
|
||||||
|
|
||||||
|
Value l = currentFrame->registerBase[b];
|
||||||
|
Value r = currentFrame->registerBase[c];
|
||||||
|
|
||||||
|
currentFrame->registerBase[a] =
|
||||||
|
Value::FromDouble(static_cast<double>(l.AsInt()) / r.AsInt());
|
||||||
|
DISPATCH();
|
||||||
|
}
|
||||||
|
|
||||||
BINARY_COMPARE_OP(Equal, ==);
|
BINARY_COMPARE_OP(Equal, ==);
|
||||||
BINARY_COMPARE_OP(NotEqual, !=);
|
BINARY_COMPARE_OP(NotEqual, !=);
|
||||||
BINARY_COMPARE_OP(Greater, >);
|
BINARY_COMPARE_OP(Greater, >);
|
||||||
@@ -222,6 +300,37 @@ namespace Fig
|
|||||||
BINARY_COMPARE_OP(GreaterEqual, >=);
|
BINARY_COMPARE_OP(GreaterEqual, >=);
|
||||||
BINARY_COMPARE_OP(LessEqual, <=);
|
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: {
|
do_Count: {
|
||||||
assert(false && "Hit Count sentinel!");
|
assert(false && "Hit Count sentinel!");
|
||||||
return Value::GetNullInstance();
|
return Value::GetNullInstance();
|
||||||
|
|||||||
@@ -32,12 +32,19 @@ namespace Fig
|
|||||||
{
|
{
|
||||||
private:
|
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 registers[MAX_REGISTERS];
|
||||||
|
Value globals[MAX_GLOBALS];
|
||||||
|
|
||||||
DynArray<CallFrame> frames;
|
CallFrame frames[MAX_RECURSION_DEPTH];
|
||||||
CallFrame *currentFrame;
|
CallFrame *currentFrame;
|
||||||
|
CallFrame *frameLimit;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
VM()
|
VM()
|
||||||
{
|
{
|
||||||
@@ -45,27 +52,36 @@ namespace Fig
|
|||||||
{
|
{
|
||||||
registers[i] = Value::GetNullInstance();
|
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:
|
private:
|
||||||
|
[[nodiscard]]
|
||||||
void pushFrame(Proto *proto, Value *base)
|
inline Instruction *pushFrame(Proto *proto, Value *base)
|
||||||
{
|
{
|
||||||
frames.push_back({
|
if (++currentFrame >= frameLimit) [[unlikely]] // 达到最大递归层数
|
||||||
proto,
|
{
|
||||||
proto->code.data(),
|
POISON_MAX_RECURSION_DEPTH_EXCEED_INST =
|
||||||
base
|
Op::iAsBx(OpCode::Exit_MaxRecursionDepthExceeded, 0, 0);
|
||||||
});
|
return &POISON_MAX_RECURSION_DEPTH_EXCEED_INST;
|
||||||
currentFrame = &frames.back();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void popFrame()
|
*currentFrame = CallFrame{proto, proto->code.data(), base};
|
||||||
{
|
return currentFrame->ip;
|
||||||
frames.pop_back();
|
|
||||||
if (!frames.empty())
|
|
||||||
{
|
|
||||||
currentFrame = &frames.back();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
inline void popFrame()
|
||||||
|
{
|
||||||
|
--currentFrame;
|
||||||
}
|
}
|
||||||
|
|
||||||
inline OpCode decodeOpCode(Instruction inst)
|
inline OpCode decodeOpCode(Instruction inst)
|
||||||
|
|||||||
62
src/main.cpp
62
src/main.cpp
@@ -1,3 +1,4 @@
|
|||||||
|
#include <Bytecode/Disassembler.hpp>
|
||||||
#include <Compiler/Compiler.hpp>
|
#include <Compiler/Compiler.hpp>
|
||||||
#include <Core/Core.hpp>
|
#include <Core/Core.hpp>
|
||||||
#include <Deps/Deps.hpp>
|
#include <Deps/Deps.hpp>
|
||||||
@@ -7,12 +8,10 @@
|
|||||||
#include <SourceManager/SourceManager.hpp>
|
#include <SourceManager/SourceManager.hpp>
|
||||||
#include <VM/VM.hpp>
|
#include <VM/VM.hpp>
|
||||||
|
|
||||||
|
|
||||||
#include <chrono>
|
#include <chrono>
|
||||||
#include <iostream>
|
#include <iostream>
|
||||||
#include <print>
|
#include <print>
|
||||||
|
|
||||||
|
|
||||||
int main()
|
int main()
|
||||||
{
|
{
|
||||||
using namespace Fig;
|
using namespace Fig;
|
||||||
@@ -25,68 +24,53 @@ int main()
|
|||||||
|
|
||||||
if (!manager.read)
|
if (!manager.read)
|
||||||
{
|
{
|
||||||
std::cerr << "Couldn't read file";
|
std::cerr << "CRITICAL: Could not read source file: " << filePath << "\n";
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
Lexer lexer(manager.GetSource(), fileName);
|
Lexer lexer(manager.GetSource(), fileName);
|
||||||
Parser parser(lexer, manager, fileName);
|
Parser parser(lexer, manager, fileName);
|
||||||
|
|
||||||
const auto &program_result = parser.Parse();
|
auto pRes = parser.Parse();
|
||||||
if (!program_result)
|
if (!pRes)
|
||||||
{
|
{
|
||||||
ReportError(program_result.error(), manager);
|
ReportError(pRes.error(), manager);
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
Program *program = *program_result;
|
Program *program = *pRes;
|
||||||
|
|
||||||
Analyzer analyzer(manager);
|
Analyzer analyzer(manager);
|
||||||
const auto &analyzeResult = analyzer.Analyze(program);
|
auto aRes = analyzer.Analyze(program);
|
||||||
if (!analyzeResult)
|
if (!aRes)
|
||||||
{
|
{
|
||||||
ReportError(analyzeResult.error(), manager);
|
ReportError(aRes.error(), manager);
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
std::cout << "analyzer: Program OK, PASSED\n";
|
std::cout << "Analyzer: Program OK\n";
|
||||||
|
|
||||||
Compiler compiler(fileName, manager);
|
Diagnostics diag;
|
||||||
const auto &comp_result = compiler.Compile(program);
|
Compiler compiler(manager, diag);
|
||||||
if (!comp_result)
|
auto cRes = compiler.Compile(program);
|
||||||
|
if (!cRes)
|
||||||
{
|
{
|
||||||
ReportError(comp_result.error(), manager);
|
ReportError(cRes.error(), manager);
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
CompiledModule *compiledModule = *comp_result;
|
CompiledModule *compiledModule = *cRes;
|
||||||
|
|
||||||
size_t cnt = 0;
|
Disassembler::DisassembleModule(compiledModule);
|
||||||
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());
|
|
||||||
}
|
|
||||||
|
|
||||||
DumpCode(proto->code);
|
|
||||||
|
|
||||||
std::cout << "\nMax Stack Size: " << (int) proto->maxStack << std::endl;
|
|
||||||
}
|
|
||||||
|
|
||||||
VM vm;
|
VM vm;
|
||||||
|
|
||||||
using Clock = std::chrono::high_resolution_clock;
|
using Clock = std::chrono::high_resolution_clock;
|
||||||
|
|
||||||
Clock clock;
|
Clock clock;
|
||||||
|
|
||||||
|
std::cout << "\n--- VM Execution Start ---\n";
|
||||||
auto start = clock.now();
|
auto start = clock.now();
|
||||||
|
|
||||||
auto result_ = vm.Execute(compiledModule);
|
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_)
|
if (!result_)
|
||||||
{
|
{
|
||||||
@@ -94,9 +78,9 @@ int main()
|
|||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
Value result = *result_;
|
std::cout << "Result: " << (*result_).ToString() << "\n";
|
||||||
std::cout << "result: " << result.ToString() << "\n";
|
std::cout << "Execution Cost: " << duration.count() << "ms\n";
|
||||||
std::cout << "execution cost: " << std::chrono::duration_cast<std::chrono::milliseconds>(duration).count() << "ms\n";
|
|
||||||
|
|
||||||
vm.PrintRegisters();
|
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 未定义
|
||||||
|
}
|
||||||
30
xmake.lua
30
xmake.lua
@@ -13,11 +13,6 @@ elseif is_plat("windows") then
|
|||||||
-- 2. local dev (Windows + llvm-mingw)
|
-- 2. local dev (Windows + llvm-mingw)
|
||||||
set_toolchains("mingw") -- llvm-mingw
|
set_toolchains("mingw") -- llvm-mingw
|
||||||
add_ldflags("-Wl,--stack,268435456")
|
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
|
end
|
||||||
|
|
||||||
set_languages("c++23")
|
set_languages("c++23")
|
||||||
@@ -33,7 +28,6 @@ target("LexerTest")
|
|||||||
add_files("src/Token/Token.cpp")
|
add_files("src/Token/Token.cpp")
|
||||||
add_files("src/Error/Error.cpp")
|
add_files("src/Error/Error.cpp")
|
||||||
add_files("src/Lexer/Lexer.cpp")
|
add_files("src/Lexer/Lexer.cpp")
|
||||||
|
|
||||||
add_files("src/Lexer/LexerTest.cpp")
|
add_files("src/Lexer/LexerTest.cpp")
|
||||||
|
|
||||||
target("ParserTest")
|
target("ParserTest")
|
||||||
@@ -41,13 +35,11 @@ target("ParserTest")
|
|||||||
add_files("src/Token/Token.cpp")
|
add_files("src/Token/Token.cpp")
|
||||||
add_files("src/Error/Error.cpp")
|
add_files("src/Error/Error.cpp")
|
||||||
add_files("src/Lexer/Lexer.cpp")
|
add_files("src/Lexer/Lexer.cpp")
|
||||||
|
|
||||||
add_files("src/Ast/Operator.cpp")
|
add_files("src/Ast/Operator.cpp")
|
||||||
add_files("src/Parser/ExprParser.cpp")
|
add_files("src/Parser/ExprParser.cpp")
|
||||||
add_files("src/Parser/StmtParser.cpp")
|
add_files("src/Parser/StmtParser.cpp")
|
||||||
add_files("src/Parser/TypeExprParser.cpp")
|
add_files("src/Parser/TypeExprParser.cpp")
|
||||||
add_files("src/Parser/Parser.cpp")
|
add_files("src/Parser/Parser.cpp")
|
||||||
|
|
||||||
add_files("src/Parser/ParserTest.cpp")
|
add_files("src/Parser/ParserTest.cpp")
|
||||||
|
|
||||||
target("ObjectTest")
|
target("ObjectTest")
|
||||||
@@ -59,13 +51,12 @@ target("AnalyzerTest")
|
|||||||
add_files("src/Token/Token.cpp")
|
add_files("src/Token/Token.cpp")
|
||||||
add_files("src/Error/Error.cpp")
|
add_files("src/Error/Error.cpp")
|
||||||
add_files("src/Lexer/Lexer.cpp")
|
add_files("src/Lexer/Lexer.cpp")
|
||||||
|
|
||||||
add_files("src/Ast/Operator.cpp")
|
add_files("src/Ast/Operator.cpp")
|
||||||
add_files("src/Parser/ExprParser.cpp")
|
add_files("src/Parser/ExprParser.cpp")
|
||||||
add_files("src/Parser/StmtParser.cpp")
|
add_files("src/Parser/StmtParser.cpp")
|
||||||
add_files("src/Parser/TypeExprParser.cpp")
|
add_files("src/Parser/TypeExprParser.cpp")
|
||||||
add_files("src/Parser/Parser.cpp")
|
add_files("src/Parser/Parser.cpp")
|
||||||
|
add_files("src/Sema/Type.cpp")
|
||||||
add_files("src/Sema/Analyzer.cpp")
|
add_files("src/Sema/Analyzer.cpp")
|
||||||
add_files("src/Sema/AnalyzerTest.cpp")
|
add_files("src/Sema/AnalyzerTest.cpp")
|
||||||
|
|
||||||
@@ -74,21 +65,18 @@ target("CompilerTest")
|
|||||||
add_files("src/Token/Token.cpp")
|
add_files("src/Token/Token.cpp")
|
||||||
add_files("src/Error/Error.cpp")
|
add_files("src/Error/Error.cpp")
|
||||||
add_files("src/Lexer/Lexer.cpp")
|
add_files("src/Lexer/Lexer.cpp")
|
||||||
|
|
||||||
add_files("src/Ast/Operator.cpp")
|
add_files("src/Ast/Operator.cpp")
|
||||||
|
add_files("src/Bytecode/Disassembler.cpp")
|
||||||
add_files("src/Parser/ExprParser.cpp")
|
add_files("src/Parser/ExprParser.cpp")
|
||||||
add_files("src/Parser/StmtParser.cpp")
|
add_files("src/Parser/StmtParser.cpp")
|
||||||
add_files("src/Parser/TypeExprParser.cpp")
|
add_files("src/Parser/TypeExprParser.cpp")
|
||||||
add_files("src/Parser/Parser.cpp")
|
add_files("src/Parser/Parser.cpp")
|
||||||
|
|
||||||
add_files("src/Object/Object.cpp")
|
add_files("src/Object/Object.cpp")
|
||||||
|
add_files("src/Sema/Type.cpp")
|
||||||
add_files("src/Sema/Analyzer.cpp")
|
add_files("src/Sema/Analyzer.cpp")
|
||||||
|
|
||||||
add_files("src/Compiler/ExprCompiler.cpp")
|
add_files("src/Compiler/ExprCompiler.cpp")
|
||||||
add_files("src/Compiler/StmtCompiler.cpp")
|
add_files("src/Compiler/StmtCompiler.cpp")
|
||||||
add_files("src/Compiler/Compiler.cpp")
|
add_files("src/Compiler/Compiler.cpp")
|
||||||
|
|
||||||
add_files("src/Compiler/CompileTest.cpp")
|
add_files("src/Compiler/CompileTest.cpp")
|
||||||
|
|
||||||
target("LSP")
|
target("LSP")
|
||||||
@@ -96,17 +84,14 @@ target("LSP")
|
|||||||
add_files("src/Token/Token.cpp")
|
add_files("src/Token/Token.cpp")
|
||||||
add_files("src/Error/Error.cpp")
|
add_files("src/Error/Error.cpp")
|
||||||
add_files("src/Lexer/Lexer.cpp")
|
add_files("src/Lexer/Lexer.cpp")
|
||||||
|
|
||||||
add_files("src/Ast/Operator.cpp")
|
add_files("src/Ast/Operator.cpp")
|
||||||
add_files("src/Parser/ExprParser.cpp")
|
add_files("src/Parser/ExprParser.cpp")
|
||||||
add_files("src/Parser/StmtParser.cpp")
|
add_files("src/Parser/StmtParser.cpp")
|
||||||
add_files("src/Parser/TypeExprParser.cpp")
|
add_files("src/Parser/TypeExprParser.cpp")
|
||||||
add_files("src/Parser/Parser.cpp")
|
add_files("src/Parser/Parser.cpp")
|
||||||
|
add_files("src/Sema/Type.cpp")
|
||||||
add_files("src/Sema/Analyzer.cpp")
|
add_files("src/Sema/Analyzer.cpp")
|
||||||
|
|
||||||
add_files("src/LSP/LSPServer.cpp")
|
add_files("src/LSP/LSPServer.cpp")
|
||||||
|
|
||||||
set_filename("Fig-LSP")
|
set_filename("Fig-LSP")
|
||||||
|
|
||||||
target("Fig")
|
target("Fig")
|
||||||
@@ -114,20 +99,17 @@ target("Fig")
|
|||||||
add_files("src/Token/Token.cpp")
|
add_files("src/Token/Token.cpp")
|
||||||
add_files("src/Error/Error.cpp")
|
add_files("src/Error/Error.cpp")
|
||||||
add_files("src/Lexer/Lexer.cpp")
|
add_files("src/Lexer/Lexer.cpp")
|
||||||
|
|
||||||
add_files("src/Ast/Operator.cpp")
|
add_files("src/Ast/Operator.cpp")
|
||||||
|
add_files("src/Bytecode/Disassembler.cpp")
|
||||||
add_files("src/Parser/ExprParser.cpp")
|
add_files("src/Parser/ExprParser.cpp")
|
||||||
add_files("src/Parser/StmtParser.cpp")
|
add_files("src/Parser/StmtParser.cpp")
|
||||||
add_files("src/Parser/TypeExprParser.cpp")
|
add_files("src/Parser/TypeExprParser.cpp")
|
||||||
add_files("src/Parser/Parser.cpp")
|
add_files("src/Parser/Parser.cpp")
|
||||||
|
|
||||||
add_files("src/Object/Object.cpp")
|
add_files("src/Object/Object.cpp")
|
||||||
|
add_files("src/Sema/Type.cpp")
|
||||||
add_files("src/Sema/Analyzer.cpp")
|
add_files("src/Sema/Analyzer.cpp")
|
||||||
|
|
||||||
add_files("src/Compiler/ExprCompiler.cpp")
|
add_files("src/Compiler/ExprCompiler.cpp")
|
||||||
add_files("src/Compiler/StmtCompiler.cpp")
|
add_files("src/Compiler/StmtCompiler.cpp")
|
||||||
add_files("src/Compiler/Compiler.cpp")
|
add_files("src/Compiler/Compiler.cpp")
|
||||||
|
|
||||||
add_files("src/VM/VM.cpp")
|
add_files("src/VM/VM.cpp")
|
||||||
add_files("src/main.cpp")
|
add_files("src/main.cpp")
|
||||||
Reference in New Issue
Block a user