重构类型系统并改进诊断功能

- 更新了类型系统,新增了类型并优化了结构。
- 引入了基类型和派生类,用于函数、结构体和接口类型。
- 实现了类型上下文,用于管理内置类型和类型解析。
- 添加了诊断类,用于收集和报告警告和错误。
- 通过改进错误处理增强了虚拟机执行,以应对递归限制问题。
- 实现了反汇编器,将字节码转换为代码,以改善调试和分析。
- 添加了新的抽象语法树节点,用于成员表达式、对象初始化、接口和结构体定义。
- 引入了语义错误测试,包括重定义、未声明的变量和无效的结构字段。
This commit is contained in:
2026-03-10 12:33:17 +08:00
parent 90448006ff
commit 0f635ccf2b
47 changed files with 2365 additions and 2541 deletions

View File

View File

@@ -2,52 +2,55 @@
@file src/Ast/Base.hpp
@brief AstNode基类定义
@author PuqiAR (im@puqiar.top)
@date 2026-02-14
@date 2026-03-08
*/
#pragma once
#include <Core/SourceLocations.hpp>
#include <Deps/Deps.hpp>
#include <Sema/Type.hpp>
#include <cstdint>
namespace Fig
{
enum class AstType : std::uint8_t
{
AstNode, // 基类
Program, // 程序
Expr, // 表达式
Stmt, // 语句
BlockStmt, // 块语句
AstNode,
Program,
Expr,
Stmt,
BlockStmt,
/* Expressions */
IdentiExpr, // 标识符表达式
LiteralExpr, // 字面量表达式
PrefixExpr, // 一元 前缀表达式
InfixExpr, // 二元 中缀表达式
IndexExpr, // 后缀表达式,索引
CallExpr, // 后缀表达式,函数调用
IdentiExpr,
LiteralExpr,
PrefixExpr,
InfixExpr,
IndexExpr,
CallExpr,
MemberExpr, // obj.prop
ObjectInitExpr, // new Point{}
/* Statements */
ExprStmt, // 表达式语句,如 println(1)
VarDecl, // 变量声明
IfStmt, // If语句
ElseIfStmt, // ElseIf语句不准悬空平铺式else if
WhileStmt, // while语句
FnDefStmt, // func函数定义语句
ReturnStmt, // 返回语句
BreakStmt, // break语句
ContinueStmt, // continue语句
ExprStmt,
VarDecl,
IfStmt,
ElseIfStmt,
WhileStmt,
FnDefStmt,
StructDefStmt,
InterfaceDefStmt,
ImplStmt, // impl Document for File {}
ReturnStmt,
BreakStmt,
ContinueStmt,
/* Type Expressions */
TypeExpr, // 基类
NamedTypeExpr, // 命名类型支持namespace, std.file这样的
// 泛型等...
TypeExpr,
NamedTypeExpr,
NullableTypeExpr
};
struct AstNode
{
AstType type = AstType::AstNode;
@@ -66,13 +69,10 @@ namespace Fig
virtual ~TypeExpr() = default;
};
struct Program;
struct Expr : public AstNode
{
TypeInfo *resolvedType = nullptr;
// TODO: 可选的常量折叠
// 拓展 isConstExpr和 constValue槽位
// 语义分析后填充
Type resolvedType;
Expr()
{
@@ -82,7 +82,7 @@ namespace Fig
struct Stmt : public AstNode
{
bool isPublic;
bool isPublic = false;
Stmt()
{
type = AstType::Stmt;
@@ -92,22 +92,10 @@ namespace Fig
struct Program final : public AstNode
{
DynArray<Stmt *> nodes;
Program()
{
type = AstType::Program;
}
Program(DynArray<Stmt *> _nodes)
{
type = AstType::Program;
nodes = std::move(_nodes);
if (!_nodes.empty())
{
location = std::move(_nodes.back()->location);
}
}
virtual String toString() const override
{
return "<Program>";
@@ -121,36 +109,9 @@ namespace Fig
{
type = AstType::BlockStmt;
}
BlockStmt(DynArray<Stmt *> _nodes)
{
type = AstType::BlockStmt;
nodes = std::move(_nodes);
if (!_nodes.empty())
{
location = std::move(_nodes.back()->location);
}
}
virtual String toString() const override
{
return "<BlockStmt>";
}
};
}; // namespace Fig
namespace std
{
template <>
struct std::formatter<Fig::AstNode *, char>
{
constexpr auto parse(std::format_parse_context &ctx)
{
return ctx.begin();
}
template <typename FormatContext>
auto format(const Fig::AstNode *_node, FormatContext &ctx) const
{
return std::format_to(ctx.out(), "{}", _node->toString().toStdString());
}
};
}; // namespace std
} // namespace Fig

View File

@@ -1,48 +1,32 @@
/*!
@file src/Ast/Expr/IdentiExpr.hpp
@brief IdentiExpr定义
@author PuqiAR (im@puqiar.top)
@date 2026-02-14
@brief 标识符表达式定义
*/
#pragma once
#include <Ast/Base.hpp>
#include <Deps/Deps.hpp>
#include <Sema/Environment.hpp>
namespace Fig
{
struct IdentiExpr final : Expr
struct IdentiExpr final : public Expr
{
String name;
// Analyzer槽位
// 寻址空间
bool isGlobal = false; // 是否全局, 全局变量存哈希/堆
// 仅 isGlobal = false 有效
int resolvedDepth = -1; // 用于获取闭包上值, -1 代表未解析
// 栈内槽位
int localId = -1; // 局部变量id, -1 未解析
String name;
Symbol *resolvedSymbol = nullptr; // 语义分析后填充Compiler 唯一的依赖
IdentiExpr()
{
type = AstType::IdentiExpr;
}
IdentiExpr(String _name, SourceLocation _loc)
IdentiExpr(String _name, SourceLocation _location) : name(std::move(_name))
{
type = AstType::IdentiExpr;
name = std::move(_name);
location = std::move(_loc);
type = AstType::IdentiExpr;
location = std::move(_location);
}
virtual String toString() const override
{
return std::format("<IdentiExpr: {}>", name);
return std::format("<IdentiExpr '{}'>", name);
}
};
};
} // namespace Fig

View File

@@ -1,36 +1,27 @@
/*!
@file src/Ast/Expr/LiteralExpr.hpp
@brief 字面量表达式定义
@author PuqiAR (im@puqiar.top)
@date 2026-02-14
*/
#pragma once
#include <Ast/Base.hpp>
#include <Token/Token.hpp>
#include <Deps/Deps.hpp>
namespace Fig
{
struct LiteralExpr final : Expr
struct LiteralExpr final : public Expr
{
Token token;
Token literal;
LiteralExpr()
{
type = AstType::LiteralExpr;
}
LiteralExpr(const Token& token, SourceLocation _location) : token(token)
LiteralExpr() { type = AstType::LiteralExpr; }
LiteralExpr(const Token &_literal, SourceLocation _location) : literal(_literal)
{
type = AstType::LiteralExpr;
location = std::move(_location);
}
virtual String toString() const override
{
return std::format("<LiteralExpr: {}>", magic_enum::enum_name(token.type));
virtual String toString() const override {
return std::format("<LiteralExpr: {}>", magic_enum::enum_name(literal.type));
}
};
}; // namespace Fig
}

View 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

View 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

View File

@@ -1,102 +1,47 @@
/*!
@file src/Ast/Stmt/FnDefStmt.hpp
@brief FnDefStmt定义
@author PuqiAR (im@puqiar.top)
@date 2026-02-25
@brief 函数定义 AST 节点
*/
#pragma once
#include <Ast/Base.hpp>
#include <Sema/Environment.hpp>
namespace Fig
{
struct Param
{
String name;
SourceLocation location;
TypeInfo *resolvedType = nullptr;
int localId = -1;
virtual String toString() const = 0;
};
struct PosParam final : public Param
{
TypeExpr *type;
struct Param : public AstNode {
String name;
TypeExpr *typeSpecifier;
Expr *defaultValue;
PosParam() {}
PosParam(String _name, TypeExpr *_type, Expr *_defaultValue, SourceLocation _location) :
type(_type), defaultValue(_defaultValue)
{
name = std::move(_name);
location = std::move(_location);
}
virtual String toString() const override
{
return std::format("<Pos {}: {}{}>",
name,
(type ? type->toString() : "Any"),
(defaultValue ? " =" + defaultValue->toString() : ""));
}
Type resolvedType;
Param() { type = AstType::AstNode; }
virtual ~Param() = default;
};
/*
(public) func foo([name: (type) (= default value)]) (-> return type)
{
...
struct PosParam final : public Param {
PosParam(String _n, TypeExpr *_ts, Expr *_dv, SourceLocation _loc) {
name = std::move(_n); typeSpecifier = _ts; defaultValue = _dv; location = std::move(_loc);
}
virtual String toString() const override { return name; }
};
*/
struct FnDefStmt final : public Stmt
{
String name;
struct FnDefStmt final : public Stmt {
String name;
DynArray<Param *> params;
TypeExpr *returnType;
BlockStmt *body;
TypeExpr *returnTypeSpecifier;
BlockStmt *body;
Type resolvedReturnType;
Symbol *resolvedSymbol = nullptr; // 连接物理符号
TypeInfo *resolvedReturnType = nullptr;
int localId = -1;
FnDefStmt()
FnDefStmt() { type = AstType::FnDefStmt; }
FnDefStmt(bool _p, String _n, DynArray<Param *> _pa, TypeExpr *_rt, BlockStmt *_b, SourceLocation _loc)
: name(std::move(_n)), params(std::move(_pa)), returnTypeSpecifier(_rt), body(_b)
{
type = AstType::FnDefStmt;
type = AstType::FnDefStmt; isPublic = _p; location = std::move(_loc);
}
FnDefStmt(bool _isPublic,
String _name,
DynArray<Param *> _params,
TypeExpr *_returnType,
BlockStmt *_body,
SourceLocation _location) :
name(std::move(_name)), params(std::move(_params)), returnType(_returnType), body(_body)
{
type = AstType::FnDefStmt;
isPublic = _isPublic;
location = std::move(_location);
}
virtual String toString() const override
{
String pStr;
for (const Param *p : params)
{
if (p != *params.begin())
{
pStr += ", ";
}
pStr += p->toString();
}
return std::format("<FnDefStmt {}{}({}) -> {} {{{}}}>",
(isPublic ? "public " : ""),
name,
pStr,
(returnType ? returnType->toString() : "Any"),
body->toString());
virtual String toString() const override {
return std::format("<FnDefStmt '{}'>", name);
}
};
}; // namespace Fig
}

32
src/Ast/Stmt/ImplStmt.hpp Normal file
View 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

View 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

View 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

View File

@@ -1,8 +1,6 @@
/*!
@file src/Ast/TypeExpr.hpp
@brief TypeExpr定义
@author PuqiAR (im@puqiar.top)
@date 2026-02-25
@brief 类型表达式 AST 定义:支持泛型与空安全
*/
#pragma once
@@ -11,26 +9,59 @@
namespace Fig
{
struct NamedTypeExpr final : public TypeExpr
{
DynArray<String> path; // {"std", "file"} etc.
DynArray<String> path;
DynArray<TypeExpr *> arguments;
NamedTypeExpr()
{
type = AstType::NamedTypeExpr;
}
NamedTypeExpr(DynArray<String> _path, SourceLocation _location) :
path(std::move(_path))
NamedTypeExpr(DynArray<String> _p, DynArray<TypeExpr *> _args, SourceLocation _loc) :
path(std::move(_p)), arguments(std::move(_args))
{
type = AstType::NamedTypeExpr;
location = std::move(_location);
type = AstType::NamedTypeExpr;
location = std::move(_loc);
}
virtual String toString() const override
{
return std::format("<NamedTypeExpr '{}'>", path);
String detail = "";
for (size_t i = 0; i < path.size(); ++i)
{
detail += path[i];
if (i < path.size() - 1)
detail += ".";
}
if (!arguments.empty())
{
detail += "<";
for (size_t i = 0; i < arguments.size(); ++i)
{
detail += arguments[i]->toString();
if (i < arguments.size() - 1)
detail += ", ";
}
detail += ">";
}
return std::format("<NamedTypeExpr '{}'>", detail);
}
};
};
struct NullableTypeExpr final : public TypeExpr
{
TypeExpr *inner;
NullableTypeExpr(TypeExpr *_inner, SourceLocation _loc) : inner(_inner)
{
type = AstType::NullableTypeExpr;
location = std::move(_loc);
}
virtual String toString() const override
{
return std::format("<NullableTypeExpr '{}?'>", inner->toString());
}
};
} // namespace Fig

View File

@@ -1,87 +1,83 @@
/*!
@file src/Bytecode/Bytecode.hpp
@brief 字节码Bytecode定义
@author PuqiAR (im@puqiar.top)
@date 2026-02-18
*/
#pragma once
#include <cstdint>
#pragma once
#include <cstdint>
namespace Fig
{
// 定长 32-bit
using Instruction = std::uint32_t;
enum class OpCode : std::uint8_t
{
Exit, // 结束运行
LoadK, // iABx 模式: R[A] = Constants[Bx]
LoadTrue, // iABC: R[A] = true
LoadFalse, // iABC: R[A] = false
LoadNull, // iABC: R[A] = null
Exit,
Exit_MaxRecursionDepthExceeded,
FastCall, // iABC: A: ProtoIdx, B: 函数起始寄存器
Call, // 动态派发 iABC: A: 函数体对象寄存器 B: 函数起始寄存器
Return, // iABC 模式: 返回 R[A] 的值
LoadK,
LoadTrue,
LoadFalse,
LoadNull,
LoadFn, // 惰性装修, iABx: R[A] = new FunctionObject...
FastCall,
Call,
Return,
Jmp, // iAsBx: ip += sBx 无条件跳转
JmpIfFalse, // iAsBx: 如果 R[A] 为假, ip += sBx
LoadFn,
Mov, // iABx: R[A] = R[Bx]
Jmp,
JmpIfFalse,
Add, // iABC: R[A] = R[B] + R[C]
Sub, // iABC: R[A] = R[B] - R[C]
Mul, // iABC: R[A] = R[B] * R[C]
Div, // iABC: R[A] = R[B] / R[C]
Mod, // iABC: R[A] = R[B] % R[C]
BitXor, // iABC: R[A] = R[B] ^ R[C]
Mov,
IntFastAdd, // iABC: R[A] (Int) = R[B] (Int) + R[C] (Int)
IntFastSub, // iABC: R[A] (Int) = R[B] (Int) - R[C] (Int)
IntFastMul, // iABC: R[A] (Int) = R[B] (Int) * R[C] (Int)
IntFastDiv, // iABC: R[A] (Double) = R[B] (Int) / R[C] (Int)
Add,
Sub,
Mul,
Div,
Mod,
BitXor,
Equal, // iABC: R[A] = R[B] == R[C]
NotEqual, // iABC: R[A] = R[B] != R[C]
Greater, // iABC: R[A] = R[B] > R[C]
Less, // iABC: R[A] = R[B] < R[C]
GreaterEqual, // iABC: R[A] = R[B] >= R[C]
LessEqual, // iABC: R[A] = R[B] <= R[C]
IntFastAdd,
IntFastSub,
IntFastMul,
IntFastDiv,
Count, // 哨兵
Equal,
NotEqual,
Greater,
Less,
GreaterEqual,
LessEqual,
GetGlobal,
SetGlobal,
GetUpval,
SetUpval,
Copy,
Count
};
namespace Op
{
// [OpCode: 8] [A: 8] [Bx: 16]
[[nodiscard]] inline constexpr Instruction iABx(OpCode op, std::uint8_t a, std::uint16_t bx)
{
return static_cast<std::uint32_t>(op) | (static_cast<std::uint32_t>(a) << 8)
| (static_cast<std::uint32_t>(bx) << 16);
}
// [OpCode: 8] [A: 8] [B: 8] [C: 8]
[[nodiscard]] inline constexpr Instruction iABC(
OpCode op, std::uint8_t a, std::uint8_t b, std::uint8_t c)
[[nodiscard]] inline constexpr Instruction iABC(OpCode op, std::uint8_t a, std::uint8_t b, std::uint8_t c)
{
return static_cast<std::uint32_t>(op) | (static_cast<std::uint32_t>(a) << 8)
| (static_cast<std::uint32_t>(b) << 16) | (static_cast<std::uint32_t>(c) << 24);
}
[[nodiscard]]
inline constexpr Instruction iAsBx(OpCode op, std::uint8_t a, std::int16_t sbx)
[[nodiscard]] inline constexpr Instruction iAsBx(OpCode op, std::uint8_t a, std::int16_t sbx)
{
return static_cast<std::uint32_t>(op) | (static_cast<std::uint32_t>(a) << 8)
| (static_cast<std::uint32_t>(static_cast<std::uint16_t>(sbx)) << 16);
}
} // namespace Op
} // namespace Fig
} // namespace Fig

View 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

View 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

View File

@@ -1,66 +1,63 @@
#include <Compiler/Compiler.hpp>
#include <Core/Core.hpp>
#include <Deps/Deps.hpp>
#include <Lexer/Lexer.hpp>
#include <Parser/Parser.hpp>
#include <SourceManager/SourceManager.hpp>
#include <Sema/Analyzer.hpp>
#include <Compiler/Compiler.hpp>
#include <Bytecode/Disassembler.hpp>
#include <iostream>
#include <print>
#include <filesystem>
int main()
{
using namespace Fig;
String fileName = "test.fig";
String filePath = "T:/Files/Maker/Code/MyCodingLanguage/The Fig Project/Fig/test.fig";
String filePath = "T:/Files/Maker/Code/MyCodingLanguage/The Fig Project/Fig/tests/Compiler/test_basic.fig";
SourceManager manager(filePath);
manager.Read();
if (!manager.read)
if (!std::filesystem::exists(filePath.toStdString()))
{
std::cerr << "Couldn't read file";
std::cerr << "CRITICAL: Test file not found at: " << filePath << "\n";
return 1;
}
Lexer lexer(manager.GetSource(), fileName);
Parser parser(lexer, manager, fileName);
SourceManager sm{filePath};
String source = sm.Read();
const auto &program_result = parser.Parse();
if (!program_result)
if (!sm.read || source.length() == 0)
{
ReportError(program_result.error(), manager);
return 1;
}
Program *program = *program_result;
Compiler compiler(fileName, manager);
const auto &comp_result = compiler.Compile(program);
if (!comp_result)
{
ReportError(comp_result.error(), manager);
std::cerr << "CRITICAL: SourceManager failed to read: " << filePath << "\n";
return 1;
}
CompiledModule *compiledModule = *comp_result;
Lexer lexer(source, filePath);
Parser parser(lexer, sm, filePath);
size_t cnt = 0;
for (Proto *proto : compiledModule->protos)
auto pRes = parser.Parse();
if (!pRes)
{
std::cout << "=====================\n"
<< "Proto: " << cnt++ << '\n';
std::cout << "=== Constant Pool ===" << '\n';
for (size_t i = 0; i < proto->constants.size(); ++i)
{
std::print("[{}] {}\n", i, proto->constants[i].ToString());
}
DumpCode(proto->code);
std::cout << "\nMax Stack Size: " << (int) proto->maxStack << std::endl;
ReportError(pRes.error(), sm);
return 1;
}
Program *program = *pRes;
std::cout << "Successfully parsed nodes: " << program->nodes.size() << "\n";
Analyzer analyzer(sm);
auto aRes = analyzer.Analyze(program);
if (!aRes)
{
ReportError(aRes.error(), sm);
return 1;
}
Diagnostics diag;
Compiler compiler(sm, diag);
auto cRes = compiler.Compile(program);
if (!cRes)
{
ReportError(cRes.error(), sm);
return 1;
}
// 使用正式的 Disassembler
Disassembler::DisassembleModule(*cRes);
return 0;
}
}

View File

@@ -1,36 +1,125 @@
/*!
@file src/Compiler/Compiler.cpp
@brief 编译器实现
@author PuqiAR (im@puqiar.top)
@date 2026-02-18
@brief 编译器主逻辑实现:物理 Bootstrapper 与双步扫描
*/
#include <Compiler/Compiler.hpp>
#include <Ast/Stmt/FnDefStmt.hpp>
namespace Fig
{
Result<CompiledModule *, Error> Compiler::Compile(Program *program)
{
current->freeReg = 0;
module = new CompiledModule();
for (Stmt *stmt : program->nodes)
// 1. 预留 Protos[0] 给 Bootstrapper
Proto *bootProto = new Proto();
bootProto->name = "[bootstrapper]";
module->protos.push_back(bootProto);
int initIdx = -1;
int mainIdx = -1;
// 2. 第一步:预扫描顶层函数,锁定物理索引
for (auto *stmt : program->nodes)
{
auto result = compileStmt(static_cast<Stmt *>(stmt));
if (!result)
if (stmt->type == AstType::FnDefStmt)
{
return std::unexpected(result.error());
auto *f = static_cast<FnDefStmt *>(stmt);
int idx = (int) module->protos.size();
Proto *p = new Proto();
p->name = f->name;
p->numParams = (uint8_t) f->params.size();
p->maxRegisters = p->numParams;
module->protos.push_back(p);
// 连接物理符号到索引
if (f->resolvedSymbol)
{
f->resolvedSymbol->index = idx;
}
if (f->name == "init")
initIdx = idx;
if (f->name == "main")
mainIdx = idx;
}
}
if (mainFuncIndex != -1)
// 3. 第二步:在 Bootstrapper 环境中编译所有语句
FuncState bootState(bootProto, nullptr);
current = &bootState;
for (auto *stmt : program->nodes)
{
std::uint8_t baseReg = AllocReg();
Emit(Op::iABC(OpCode::FastCall, mainFuncIndex, baseReg, 0));
auto res = compileStmt(stmt);
if (!res)
{
return std::unexpected(res.error());
}
}
Emit(Op::iABC(OpCode::Exit, 0, 0, 0)); // 一定要退出,这是虚拟机退出信号,否则ub
CompiledModule *compiledModule = new CompiledModule(fileName, allProtos);
return compiledModule;
// 4. 发射 Bootstrapper 引导指令
if (initIdx != -1)
{
emit(Op::iABC(OpCode::FastCall, (uint8_t) initIdx, 0, 0));
}
if (mainIdx != -1)
{
emit(Op::iABC(OpCode::FastCall, (uint8_t) mainIdx, 0, 0));
}
emit(Op::iAsBx(OpCode::Exit, 0, 0));
return module;
}
}; // namespace Fig
int Compiler::getGlobalID(const String &name)
{
if (globalIDMap.contains(name))
return globalIDMap[name];
int id = (int) globalIDMap.size();
globalIDMap[name] = id;
return id;
}
Result<Register, Error> Compiler::allocateReg(const SourceLocation &loc)
{
if (current->freereg >= MAX_REGISTERS)
{
return std::unexpected(Error(ErrorType::RegisterOverflow, "too many registers", "", loc));
}
Register reg = current->freereg++;
if (reg >= current->proto->maxRegisters)
{
current->proto->maxRegisters = reg + 1;
}
return reg;
}
void Compiler::freeReg(Register count)
{
if (current->freereg >= count)
{
current->freereg -= count;
}
}
int Compiler::addConstant(Value val)
{
if (current->constantMap.contains(val))
return current->constantMap[val];
int idx = (int) current->proto->constants.size();
current->proto->constants.push_back(val);
current->constantMap[val] = idx;
return idx;
}
void Compiler::emit(Instruction instr)
{
current->proto->code.push_back(instr);
}
} // namespace Fig

View File

@@ -1,390 +1,72 @@
/*!
@file src/Compiler/Compiler.hpp
@brief 编译器定义
@author PuqiAR (im@puqiar.top)
@date 2026-02-19
@brief 编译器定义:物理直连 Bootstrapper
*/
#pragma once
#include <Ast/Ast.hpp>
#include <Bytecode/Bytecode.hpp>
#include <Deps/Deps.hpp>
#include <Error/Error.hpp>
#include <Error/Diagnostics.hpp>
#include <Object/Object.hpp>
#include <SourceManager/SourceManager.hpp>
#include <cassert>
#include <iostream>
namespace Fig
{
// 编译产物-函数
using Register = std::uint8_t;
struct UpvalueInfo { uint8_t index; bool isLocal; };
struct Proto
{
String name;
DynArray<Instruction> code;
DynArray<Value> constants;
std::uint8_t maxStack = 0; // 函数运行所需寄存器数量
};
struct LocalVar
{
int localId; // AST 传来的纯数字 ID
std::uint8_t reg; // 分配到的物理寄存器 ID
int depth; // 物理作用域深度(用于 EndScope 释放寄存器)
};
inline constexpr int MAX_LOCALS = 250;
inline constexpr int MAX_CONSTANTS = UINT16_MAX + 1;
// 任何跨函数、跨模块的编译,都压入弹出这个 State
struct FuncState
{
String name;
FuncState *enclosing = nullptr; // 指向外层状态 (支持闭包)
Proto *proto = nullptr;
std::uint8_t freeReg = 0;
int scopeDepth = 0;
DynArray<LocalVar> locals;
std::uint8_t fastRegMap[UINT8_MAX + 1]; // 256, 索引 = localId, 值 = 寄存器 id
FuncState(String _name, FuncState *enc = nullptr) : name(std::move(_name)), enclosing(enc)
{
proto = new Proto();
std::fill_n(fastRegMap, 256, UINT8_MAX); // 255代表未分配
}
// 注意:这里不 delete proto因为 proto 是要作为编译产物吐出去的
DynArray<UpvalueInfo> upvalues;
uint8_t maxRegisters = 0;
uint8_t numParams = 0;
};
struct CompiledModule
{
String name; // 供调试/打印
DynArray<Proto *> protos; // 扁平化函数原型
CompiledModule(String _name, DynArray<Proto *> _protos) :
name(std::move(_name)), protos(std::move(_protos))
{
}
~CompiledModule()
{
for (auto *p : protos)
{
delete p;
}
}
DynArray<Proto *> protos;
};
class Compiler
{
private:
String fileName;
static constexpr Register MAX_REGISTERS = 250;
static constexpr Register NO_REG = 255;
SourceManager &manager;
FuncState *current = nullptr; // 永远指向当前正在编译的上下文
int mainFuncIndex = -1;
HashMap<int, int> globalFuncMap; // localid -> ProtoIdx
public:
DynArray<Proto *> allProtos;
struct FuncStateProtector
struct FuncState
{
Compiler *compiler;
FuncState *prevState;
Proto *proto;
Register freereg;
FuncState *enclosing;
HashMap<Value, int> constantMap;
[[nodiscard]]
FuncStateProtector(Compiler *comp, FuncState *newState) :
compiler(comp), prevState(comp->current)
{
compiler->current = newState;
}
~FuncStateProtector()
{
compiler->current = prevState;
}
FuncState(Proto *p, FuncState *e)
: proto(p), freereg(p->numParams), enclosing(e) {}
};
Compiler(String _fileName, SourceManager &_manager) :
fileName(std::move(_fileName)), manager(_manager)
{
// 初始化顶级作用域
current = new FuncState("global", nullptr);
allProtos.push_back(current->proto); // 最顶层, bootstrapper
}
FuncState *current = nullptr;
CompiledModule *module = nullptr;
SourceManager &manager;
Diagnostics &diag;
~Compiler()
{
// 内存清理 (如果有异常中断)
while (current != nullptr)
{
FuncState *prev = current->enclosing;
delete current;
current = prev;
}
}
HashMap<String, int> globalIDMap;
int getGlobalID(const String& name);
Result<Register, Error> allocateReg(const SourceLocation &loc);
void freeReg(Register count = 1);
int addConstant(Value val);
void emit(Instruction instr);
Result<void, Error> compileStmt(Stmt *stmt);
Result<Register, Error> compileExpr(Expr *expr, Register target = NO_REG);
public:
Compiler(SourceManager &m, Diagnostics &d) : manager(m), diag(d) {}
Result<CompiledModule *, Error> Compile(Program *program);
private:
void PushState(String _name)
{
current = new FuncState(std::move(_name));
}
Proto *PopState()
{
FuncState *oldState = current;
Proto *finishedProto = oldState->proto;
current = oldState->enclosing;
delete oldState;
return finishedProto;
}
std::uint8_t AllocReg()
{
if (current->freeReg >= 255)
{
assert(false && "Register overflow!");
}
std::uint8_t reg = current->freeReg++;
if (current->freeReg > current->proto->maxStack)
{
current->proto->maxStack = current->freeReg;
}
return reg;
}
void FreeReg(std::uint8_t reg)
{
// 如果这个寄存器被局部变量使用,不释放直接 Return
for (const auto &local : current->locals)
{
if (local.reg == reg)
{
return; // 拒绝释放,保护局部变量生命周期
}
}
// 如果它是纯粹的临时计算结果),释放
if (reg == current->freeReg - 1)
{
current->freeReg--;
}
}
void Emit(Instruction inst)
{
current->proto->code.push_back(inst);
}
std::uint16_t AddConstant(Value v)
{
auto it =
std::find(current->proto->constants.begin(), current->proto->constants.end(), v);
if (it != current->proto->constants.end())
{
return std::distance(current->proto->constants.begin(), it);
}
current->proto->constants.push_back(v);
return static_cast<std::uint16_t>(current->proto->constants.size() - 1);
}
void BeginScope()
{
current->scopeDepth++;
}
void EndScope()
{
current->scopeDepth--;
while (!current->locals.empty() && current->locals.back().depth > current->scopeDepth)
{
FreeReg(current->locals.back().reg);
current->locals.pop_back();
}
}
std::uint8_t DeclareLocal(int localId)
{
std::uint8_t reg = AllocReg();
current->locals.push_back(LocalVar{localId, reg, current->scopeDepth});
current->fastRegMap[localId] = reg;
return reg;
}
std::uint8_t DeclareLocal(int localId, std::uint8_t reg) // 表示复用哪个寄存器
{
current->locals.push_back(LocalVar{localId, reg, current->scopeDepth});
current->fastRegMap[localId] = reg;
return reg;
}
// 发射一条跳转指令,并返回它在代码数组里的绝对索引 (Index)
int EmitJump(OpCode op, std::uint8_t aReg = 0)
{
// 预填 0
Emit(Op::iAsBx(op, aReg, 0));
return current->proto->code.size() - 1;
}
// 填真实偏移量到那条指令里
void PatchJump(int instructionIndex)
{
// 目标地址就是当前代码数组的末尾
int target = current->proto->code.size();
// 相对偏移量 = 目标地址 - 指令自身所在的地址 - 1
// (因为 VM 里的 ip 在取指后会自动 +1所以偏移要减去 1)
int offset = target - instructionIndex - 1;
if (offset < INT16_MIN || offset > INT16_MAX)
{
assert(false && "PatchJump: Jump offset exceeds 16-bit signed limit!");
}
Instruction &inst = current->proto->code[instructionIndex];
inst = (inst & 0x0000FFFF)
| (static_cast<Instruction>(static_cast<std::uint16_t>(offset)) << 16);
}
SourceLocation makeSourceLocation(AstNode *node)
{
SourceLocation location = node->location; // copy
location.functionName = current->name;
location.fileName = fileName;
return location;
}
Result<std::uint8_t, Error> compileIdentiExpr(IdentiExpr *);
Result<std::uint8_t, Error> compileLiteral(LiteralExpr *);
Result<std::uint8_t, Error> compileAssignment(
InfixExpr *); // 编译赋值,由 CompileInfixExpr调用
Result<std::uint8_t, Error> compileInfixExpr(InfixExpr *);
Result<std::uint8_t, Error> compileLeftValue(
Expr *); // 左值对象,可以是变量、结构体字段或模块对象
Result<std::uint8_t, Error> compileCallExpr(CallExpr *);
Result<std::uint8_t, Error> compileExpr(Expr *);
/* Statements */
Result<void, Error> compileVarDecl(VarDecl *);
Result<void, Error> compileBlockStmt(BlockStmt *);
Result<void, Error> compileIfStmt(IfStmt *);
Result<void, Error> compileWhileStmt(WhileStmt *);
Result<void, Error> compileFnDefStmt(FnDefStmt *);
Result<void, Error> compileReturnStmt(ReturnStmt *);
Result<void, Error> compileStmt(Stmt *);
};
inline void DisassembleInstruction(Instruction inst, std::size_t index)
{
// 提取OpCode (低 8 位)
auto op = static_cast<OpCode>(inst & 0xFF);
std::string_view opName = magic_enum::enum_name(op);
// 所有指令至少都有 A 操作数 (8~15 位)
std::uint8_t a = (inst >> 8) & 0xFF;
// 地址补零,指令名左对齐占 10 字符
std::cout << std::format("{:04d} {:<10} ", index, opName);
switch (op)
{
case OpCode::Exit: {
break;
}
case OpCode::Mov: {
// iABx 模式
std::uint16_t bx = (inst >> 16) & 0xFFFF;
std::cout << std::format("R{:<3} R[{}]", a, bx);
break;
}
case OpCode::LoadK: {
// iABx 模式:解析 Bx (16~31 位)
std::uint16_t bx = (inst >> 16) & 0xFFFF;
std::cout << std::format("R{:<3} K[{}]", a, bx);
break;
}
case OpCode::Jmp:
case OpCode::JmpIfFalse: {
// iAsBx
std::int16_t sbx = static_cast<std::uint16_t>(inst >> 16);
std::cout << std::format("R{:<3} [{}]", a, sbx);
break;
}
case OpCode::FastCall:
{
std::uint8_t b = (inst >> 16) & 0xFF;
std::cout << std::format("Proto{:<3} R[{}]+", a, b);
break;
}
case OpCode::Call:
{
std::uint8_t b = (inst >> 16) & 0xFF;
std::cout << std::format("R{:<3} R[{}]+", a, b);
break;
}
case OpCode::LoadTrue:
case OpCode::LoadFalse:
case OpCode::LoadNull:
case OpCode::Add:
case OpCode::Sub:
case OpCode::Mul:
case OpCode::Div:
case OpCode::Mod:
case OpCode::IntFastAdd:
case OpCode::IntFastSub:
case OpCode::IntFastMul:
case OpCode::IntFastDiv:
{
// iABC 模式:解析 B (16~23 位) 和 C (24~31 位)
std::uint8_t b = (inst >> 16) & 0xFF;
std::uint8_t c = (inst >> 24) & 0xFF;
std::cout << std::format("R{:<3} R{:<3} R{}", a, b, c);
break;
}
case OpCode::Return: {
// iA 模式:只用到了 A
std::cout << std::format("R{}", a);
break;
}
case OpCode::LoadFn: {
std::uint16_t bx = (inst >> 16) & 0xFFFF;
std::cout << std::format("R{:<3} Proto[{}]", a, bx);
break;
}
// default: {
// std::cout << "?";
// break;
// }
}
std::cout << '\n';
}
inline void DumpCode(const DynArray<Instruction> &code)
{
std::cout << " Bytecode\n";
for (std::size_t i = 0; i < code.size(); ++i)
{
DisassembleInstruction(code[i], i);
}
}
}; // namespace Fig
}

View File

@@ -1,370 +1,313 @@
/*!
@file src/Compiler/ExprCompiler.cpp
@brief 编译器实现(表达式部分)
@author PuqiAR (im@puqiar.top)
@date 2026-02-19
@brief 表达式编译器实现:引入水位线(Watermark)与零拷贝复用机制
*/
#include <Ast/Expr/CallExpr.hpp>
#include <Ast/Expr/IdentiExpr.hpp>
#include <Ast/Expr/InfixExpr.hpp>
#include <Ast/Expr/LiteralExpr.hpp>
#include <Compiler/Compiler.hpp>
#include <charconv>
#include <limits>
#include <system_error>
namespace Fig
{
Result<std::uint8_t, Error> Compiler::compileIdentiExpr(IdentiExpr *ie)
static Result<Value, Error> parsePhysicalNumber(const String &raw, const SourceLocation &loc)
{
// TODO: 处理全局变量和闭包 Upvalue
std::uint8_t targetReg = current->fastRegMap[ie->localId];
char buffer[128];
int j = 0;
bool isFloat = false;
for (size_t i = 0; i < raw.length() && j < 127; ++i)
{
char32_t c = raw[i];
if (c == '_')
continue;
if (c == '.' || c == 'e' || c == 'E')
isFloat = true;
buffer[j++] = (char) c;
}
buffer[j] = '\0';
if (targetReg == UINT8_MAX)
if (isFloat)
{
assert(false && "Compiler Bug: Encountered unmapped localId in fastRegMap!");
double dVal;
auto [ptr, ec] = std::from_chars(buffer, buffer + j, dVal);
if (ec != std::errc())
return std::unexpected(Error(ErrorType::SyntaxError, "float overflow", "", loc));
return Value::FromDouble(dVal);
}
return targetReg;
}
Result<std::uint8_t, Error> Compiler::compileLiteral(
LiteralExpr *lit) // 编译字面量, 负责转换 token -> Value
{
const Token &token = lit->token;
String lexeme = manager.GetSub(token.index, token.length);
if (!token.isLiteral())
else
{
assert(false && "CompileLiteral: token is not literal");
}
Value v;
if (token.type == TokenType::LiteralNull)
{
v = Value::GetNullInstance();
}
else if (token.type == TokenType::LiteralTrue)
{
v = Value::GetTrueInstance();
}
else if (token.type == TokenType::LiteralFalse)
{
v = Value::GetFalseInstance();
}
else if (token.type == TokenType::LiteralNumber)
{
// TODO: 更换为无异常手写数字解析版本 (charconv也可)
if (lexeme.contains(U'.') || lexeme.contains(U'e'))
int base = 10;
const char *start = buffer;
if (j > 2 && buffer[0] == '0')
{
// 非整数
double d = std::stod(lexeme.toStdString());
v = Value::FromDouble(d);
if (buffer[1] == 'x' || buffer[1] == 'X')
{
base = 16;
start += 2;
}
else if (buffer[1] == 'b' || buffer[1] == 'B')
{
base = 2;
start += 2;
}
}
int64_t iVal;
auto [ptr, ec] = std::from_chars(start, buffer + j, iVal, base);
if (ec != std::errc())
return std::unexpected(Error(ErrorType::SyntaxError, "integer overflow", "", loc));
if (iVal >= std::numeric_limits<int32_t>::min()
&& iVal <= std::numeric_limits<int32_t>::max())
{
return Value::FromInt(static_cast<int32_t>(iVal));
}
else
{
std::int32_t i = std::stoi(lexeme.toStdString());
v = Value::FromInt(i);
return Value::FromDouble(static_cast<double>(iVal));
}
}
else
{
assert("false" && "CompileLiteral: unsupport literal");
}
std::uint8_t targetReg = AllocReg();
if (current->proto->constants.size() >= MAX_CONSTANTS)
{
return std::unexpected(Error(ErrorType::TooManyConstants,
std::format("constant limit exceeded: {}", MAX_CONSTANTS),
"How did you write such code? try global variable or split file",
makeSourceLocation(lit)));
}
std::uint16_t kIndex = AddConstant(v);
Emit(Op::iABx(OpCode::LoadK, targetReg, kIndex));
return targetReg;
}
Result<std::uint8_t, Error> Compiler::compileAssignment(
InfixExpr *infix) // 编译赋值,由 CompileInfixExpr调用
Result<Register, Error> Compiler::compileExpr(Expr *expr, Register target)
{
// op必须为 =
const auto &_lhsReg = compileLeftValue(infix->left); // 必须为左值对象
if (!_lhsReg)
if (expr == nullptr)
{
return _lhsReg;
}
std::uint8_t lhsReg = *_lhsReg;
const auto &_rhsReg = compileExpr(infix->right);
std::uint8_t rhsReg = *_rhsReg;
FreeReg(rhsReg);
switch (infix->op)
{
case BinaryOperator::Assign: {
Emit(Op::iABx(OpCode::Mov, lhsReg, rhsReg)); // lhsReg = rhsReg
break;
}
case BinaryOperator::AddAssign: {
Emit(Op::iABC(OpCode::Add, lhsReg, lhsReg, rhsReg)); // lhsReg = lhsReg + rhsReg
break;
}
case BinaryOperator::SubAssign: {
Emit(Op::iABC(OpCode::Sub, lhsReg, lhsReg, rhsReg)); // lhsReg = lhsReg - rhsReg
break;
}
case BinaryOperator::MultiplyAssign: {
Emit(Op::iABC(OpCode::Mul, lhsReg, lhsReg, rhsReg)); // lhsReg = lhsReg * rhsReg
break;
}
case BinaryOperator::DivideAssign: {
Emit(Op::iABC(OpCode::Div, lhsReg, lhsReg, rhsReg)); // lhsReg = lhsReg / rhsReg
break;
}
case BinaryOperator::ModuloAssign: {
Emit(Op::iABC(OpCode::Mod, lhsReg, lhsReg, rhsReg)); // lhsReg = lhsReg % rhsReg
break;
}
case BinaryOperator::BitXorAssign: {
Emit(Op::iABC(OpCode::BitXor, lhsReg, lhsReg, rhsReg)); // lhsReg = lhsReg ^ rhsReg
break;
}
default: {
assert(false && "CompileAssignment: op unsupported yet");
}
}
return lhsReg; // 返回赋值的结果,支持连续赋值
}
Result<std::uint8_t, Error> Compiler::compileInfixExpr(
InfixExpr *infix) // 编译中缀表达式,返回一个存放结果的寄存器 ID
{
if (infix->op >= BinaryOperator::Assign && infix->op <= BinaryOperator::BitXorAssign)
{
return compileAssignment(infix);
return std::unexpected(
Error(ErrorType::InternalError, "null expr in compiler", "", {}));
}
Expr *left = infix->left;
Expr *right = infix->right;
const auto &_lhsReg = compileExpr(left);
if (!_lhsReg)
{
return _lhsReg;
}
std::uint8_t lhsReg = *_lhsReg;
const auto &_rhsReg = compileExpr(right);
if (!_rhsReg)
{
return _rhsReg;
}
std::uint8_t rhsReg = *_rhsReg;
FreeReg(rhsReg);
FreeReg(lhsReg);
std::uint8_t resultReg = AllocReg();
switch (infix->op)
{
case BinaryOperator::Add: {
if (left->resolvedType == right->resolvedType && left->resolvedType->isInt())
{
// Int + Int
Emit(Op::iABC(OpCode::IntFastAdd, resultReg, lhsReg, rhsReg));
}
else
{
Emit(Op::iABC(OpCode::Add, resultReg, lhsReg, rhsReg));
}
break;
}
case BinaryOperator::Subtract: {
if (left->resolvedType == right->resolvedType && left->resolvedType->isInt())
{
// Int - Int
Emit(Op::iABC(OpCode::IntFastSub, resultReg, lhsReg, rhsReg));
}
else
{
Emit(Op::iABC(OpCode::Sub, resultReg, lhsReg, rhsReg));
}
break;
}
case BinaryOperator::Multiply: {
if (left->resolvedType == right->resolvedType && left->resolvedType->isInt())
{
// Int * Int
Emit(Op::iABC(OpCode::IntFastMul, resultReg, lhsReg, rhsReg));
}
else
{
Emit(Op::iABC(OpCode::Mul, resultReg, lhsReg, rhsReg));
}
break;
}
case BinaryOperator::Divide: {
if (left->resolvedType == right->resolvedType && left->resolvedType->isInt())
{
// Int / Int
Emit(Op::iABC(OpCode::IntFastDiv, resultReg, lhsReg, rhsReg));
}
else
{
Emit(Op::iABC(OpCode::Div, resultReg, lhsReg, rhsReg));
}
break;
}
case BinaryOperator::Modulo: {
Emit(Op::iABC(OpCode::Mod, resultReg, lhsReg, rhsReg));
break;
}
case BinaryOperator::Greater: {
Emit(Op::iABC(OpCode::Greater, resultReg, lhsReg, rhsReg));
break;
}
case BinaryOperator::GreaterEqual: {
Emit(Op::iABC(OpCode::GreaterEqual, resultReg, lhsReg, rhsReg));
break;
}
case BinaryOperator::Less: {
Emit(Op::iABC(OpCode::Less, resultReg, lhsReg, rhsReg));
break;
}
case BinaryOperator::LessEqual: {
Emit(Op::iABC(OpCode::LessEqual, resultReg, lhsReg, rhsReg));
break;
}
case BinaryOperator::Equal: {
Emit(Op::iABC(OpCode::Equal, resultReg, lhsReg, rhsReg));
break;
}
default: assert(false && "CompileInfixExpr: op unsupported yet");
}
return resultReg;
}
Result<std::uint8_t, Error> Compiler::compileLeftValue(
Expr *expr) // 左值对象,可以是变量、结构体字段或模块对象
{
switch (expr->type)
{
case AstType::IdentiExpr:
return compileIdentiExpr(static_cast<IdentiExpr *>(expr));
// TODO: 数组切片(a[0])或对象属性(a.b)
case AstType::LiteralExpr: {
auto *l = static_cast<LiteralExpr *>(expr);
Register r = (target == NO_REG) ? *allocateReg(l->location) : target;
default:
// Analyzer 有漏洞(编译器内部
// 直接崩溃
assert(false && "Compiler Bug: Invalid L-value bypassed Analyzer!");
return 0;
}
}
Result<std::uint8_t, Error> Compiler::compileCallExpr(CallExpr *expr)
{
bool isStatic = false; // 是否为单纯的 fn(...) 静态函数调用
int protoIdx = -1;
if (expr->callee->type == AstType::IdentiExpr)
{
IdentiExpr *id = static_cast<IdentiExpr *>(expr->callee);
// 如果是函数名且深度为 0 (全局/扁平函数池)
if (id->resolvedType->tag == TypeTag::Function && id->resolvedDepth == 0)
{
if (globalFuncMap.contains(id->localId))
const Token &tok = l->literal;
if (tok.type == TokenType::LiteralNumber)
{
isStatic = true;
protoIdx = globalFuncMap[id->localId];
auto vRes =
parsePhysicalNumber(manager.GetSub(tok.index, tok.length), l->location);
if (!vRes)
return std::unexpected(vRes.error());
emit(Op::iABx(OpCode::LoadK, r, static_cast<uint16_t>(addConstant(*vRes))));
}
else if (tok.type == TokenType::LiteralString)
{
int kIdx = addConstant(Value::GetNullInstance()); // TODO: String 支持
emit(Op::iABx(OpCode::LoadK, r, static_cast<uint16_t>(kIdx)));
}
else if (tok.type == TokenType::LiteralNull)
{
emit(Op::iABC(OpCode::LoadNull, r, 0, 0));
}
else if (tok.type == TokenType::LiteralTrue)
{
emit(Op::iABC(OpCode::LoadTrue, r, 0, 0));
}
else if (tok.type == TokenType::LiteralFalse)
{
emit(Op::iABC(OpCode::LoadFalse, r, 0, 0));
}
return r;
}
}
std::uint8_t baseReg = AllocReg();
if (!isStatic)
{
auto calleeRes = compileExpr(expr->callee);
if (!calleeRes)
{
return calleeRes;
}
if (*calleeRes != baseReg)
{
Emit(Op::iABx(OpCode::Mov, baseReg, *calleeRes));
}
}
for (size_t i = 0; i < expr->args.size(); ++i)
{
std::uint8_t argTarget = AllocReg();
auto argRes = compileExpr(expr->args.args[i]);
if (!argRes)
{
return argRes;
}
if (*argRes != argTarget)
{
Emit(Op::iABx(OpCode::Mov, argTarget, *argRes));
}
}
std::uint8_t expectRet = 1;
if (isStatic)
{
Emit(Op::iABC(OpCode::FastCall, (std::uint8_t) protoIdx, baseReg, expectRet));
}
else
{
Emit(Op::iABC(OpCode::Call, baseReg, baseReg, expectRet));
}
for (size_t i = 0; i < expr->args.args.size(); ++i)
{
current->freeReg--;
}
return baseReg; // 返回值起点
}
Result<std::uint8_t, Error> Compiler::compileExpr(
Expr *expr) // 编译表达式,必定返回一个存放结果的寄存器 ID
{
switch (expr->type)
{
case AstType::Stmt:
case AstType::Expr:
case AstType::AstNode: assert(false && "CompileExpr: bad node type"); break;
case AstType::IdentiExpr: {
return compileLeftValue(expr); // 左值直接转换成右值
}
auto *i = static_cast<IdentiExpr *>(expr);
Symbol *sym = i->resolvedSymbol;
case AstType::LiteralExpr: {
LiteralExpr *lit = static_cast<LiteralExpr *>(expr);
auto result = compileLiteral(lit);
if (!result)
if (sym->location == SymbolLocation::Local)
{
return std::unexpected(result.error());
}
std::uint8_t targetReg = *result;
return targetReg;
}
// 零拷贝直读:如果是临时求值,直接返回变量的物理槽位,禁止产生副本
if (target == NO_REG)
return static_cast<Register>(sym->index);
case AstType::InfixExpr: {
return compileInfixExpr(static_cast<InfixExpr *>(expr));
// 仅在被强制指定目标(如参数装填)时发射搬运指令
if (target != sym->index)
{
emit(Op::iABx(OpCode::Mov, target, static_cast<uint16_t>(sym->index)));
}
return target;
}
Register r = (target == NO_REG) ? *allocateReg(i->location) : target;
if (sym->location == SymbolLocation::Upvalue)
{
emit(Op::iABC(OpCode::GetUpval, r, static_cast<uint8_t>(sym->index), 0));
}
else if (sym->location == SymbolLocation::Global)
{
int gId = getGlobalID(i->name);
emit(Op::iABx(OpCode::GetGlobal, r, static_cast<uint16_t>(gId)));
}
return r;
}
case AstType::CallExpr: {
return compileCallExpr(static_cast<CallExpr *>(expr));
auto *c = static_cast<CallExpr *>(expr);
Register mark = current->freereg; // 记录调用前的栈顶水位
Register baseReg = current->freereg; // 锁定滑窗基址
// 连续装填参数,占据 baseReg, baseReg+1, baseReg+2...
for (auto *arg : c->args.args)
{
auto allocRes = allocateReg(arg->location);
if (!allocRes)
{
return allocRes;
}
Register argTarget = *allocRes;
auto res = compileExpr(arg, argTarget);
if (!res)
return std::unexpected(res.error());
}
if (c->callee->type == AstType::IdentiExpr)
{
// 静态去虚化:编译期直接跳板
auto *id = static_cast<IdentiExpr *>(c->callee);
int protoIdx = id->resolvedSymbol->index;
emit(Op::iABC(OpCode::FastCall,
static_cast<uint8_t>(protoIdx),
baseReg,
static_cast<uint8_t>(c->args.args.size())));
}
else
{
// 动态闭包调用
auto r_fn = compileExpr(c->callee);
if (!r_fn)
return std::unexpected(r_fn.error());
emit(Op::iABC(
OpCode::Call, *r_fn, baseReg, static_cast<uint8_t>(c->args.args.size())));
}
// 回滚水位线:彻底释放传参时的临时占用
current->freereg = mark;
// 目标对齐:若 target 未指定allocateReg 将自然复用 baseReg实现零开销回写
Register r_dest;
if (target == NO_REG)
{
auto res = allocateReg(c->location);
if (!res)
return std::unexpected(res.error());
r_dest = *res;
}
else
{
r_dest = target;
}
if (r_dest != baseReg)
{
emit(Op::iABx(OpCode::Mov, r_dest, baseReg));
}
return r_dest;
}
case AstType::InfixExpr: {
auto *in = static_cast<InfixExpr *>(expr);
if (in->op == BinaryOperator::Assign)
{
auto r_val = compileExpr(in->right, target);
if (!r_val)
return std::unexpected(r_val.error());
if (in->left->type == AstType::IdentiExpr)
{
auto *lid = static_cast<IdentiExpr *>(in->left);
Symbol *sym = lid->resolvedSymbol;
if (sym->location == SymbolLocation::Local)
{
emit(Op::iABx(OpCode::Mov, static_cast<Register>(sym->index), *r_val));
}
else if (sym->location == SymbolLocation::Upvalue)
{
emit(Op::iABC(
OpCode::SetUpval, *r_val, static_cast<Register>(sym->index), 0));
}
else
{
emit(Op::iABx(OpCode::SetGlobal,
*r_val,
static_cast<uint16_t>(getGlobalID(lid->name))));
}
}
return r_val;
}
Register mark = current->freereg; // 记录水位线
auto r_l = compileExpr(in->left);
if (!r_l)
return std::unexpected(r_l.error());
auto r_r = compileExpr(in->right);
if (!r_r)
return std::unexpected(r_r.error());
bool isInt = in->left->resolvedType.is(TypeTag::Int)
&& in->right->resolvedType.is(TypeTag::Int);
OpCode op;
switch (in->op)
{
case BinaryOperator::Add: op = isInt ? OpCode::IntFastAdd : OpCode::Add; break;
case BinaryOperator::Subtract:
op = isInt ? OpCode::IntFastSub : OpCode::Sub;
break;
case BinaryOperator::Multiply:
op = isInt ? OpCode::IntFastMul : OpCode::Mul;
break;
case BinaryOperator::Divide:
op = isInt ? OpCode::IntFastDiv : OpCode::Div;
break;
case BinaryOperator::Modulo: op = OpCode::Mod; break;
case BinaryOperator::BitXor: op = OpCode::BitXor; break;
case BinaryOperator::Equal: op = OpCode::Equal; break;
case BinaryOperator::NotEqual: op = OpCode::NotEqual; break;
case BinaryOperator::Greater: op = OpCode::Greater; break;
case BinaryOperator::Less: op = OpCode::Less; break;
case BinaryOperator::GreaterEqual: op = OpCode::GreaterEqual; break;
case BinaryOperator::LessEqual: op = OpCode::LessEqual; break;
default:
return std::unexpected(Error(ErrorType::InternalError,
"unsupported binary operator",
"",
in->location));
}
// 释放左右操作数产生的临时寄存器
current->freereg = mark;
// 复用已释放的物理槽位存放计算结果
Register r_d;
if (target == NO_REG)
{
auto res = allocateReg(in->location);
if (!res)
return std::unexpected(res.error());
r_d = *res;
}
else
{
r_d = target;
}
emit(Op::iABC(op, r_d, *r_l, *r_r));
return r_d;
}
default: break;
}
return std::unexpected(
Error(ErrorType::InternalError, "unsupported expr", "", expr->location));
}
} // namespace Fig

View File

@@ -1,282 +1,215 @@
/*!
@file src/Compiler/StmtCompiler.cpp
@brief 编译器实现(语句部分)
@author PuqiAR (im@puqiar.top)
@date 2026-02-19
@brief 语句编译器实现:实装水位线机制,彻底消灭硬编码寄存器释放
*/
#include <Ast/Stmt/FnDefStmt.hpp>
#include <Ast/Stmt/IfStmt.hpp>
#include <Ast/Stmt/VarDecl.hpp>
#include <Ast/Stmt/WhileStmt.hpp>
#include <Compiler/Compiler.hpp>
namespace Fig
{
Result<void, Error> Compiler::compileVarDecl(VarDecl *varDecl)
Result<void, Error> Compiler::compileStmt(Stmt *stmt)
{
if (current->freeReg > MAX_LOCALS)
if (stmt == nullptr)
{
return std::unexpected(Error(ErrorType::TooManyLocals,
std::format("local limit exceeded: {}", MAX_LOCALS),
"try split function or use arrays/structs...",
makeSourceLocation(varDecl)));
return {};
}
std::uint8_t varReg;
if (varDecl->initExpr)
{
auto result = compileExpr(varDecl->initExpr);
if (!result)
{
return std::unexpected(result.error());
}
std::uint8_t resultReg = *result;
varReg = DeclareLocal(varDecl->localId, resultReg); // 复用临时计算结果寄存器
}
else
{
// TODO: 未初始化提供初始值
varReg = DeclareLocal(varDecl->localId);
}
return Result<void, Error>();
}
Result<void, Error> Compiler::compileBlockStmt(BlockStmt *blockStmt)
{
for (Stmt *stmt : blockStmt->nodes)
{
auto result = compileStmt(stmt);
if (!result)
{
return result;
}
}
return {};
}
Result<void, Error> Compiler::compileIfStmt(IfStmt *stmt)
{
/*
if cond1
{
}
else if cond2 #1
{
}
else if cond3 #2
{
}
else #3
{
}
quit #4
Bytecode:
JmpIfFalse cond1 #1
; consequent内容
; ...
; if条件为true, 跳过所有 else/elseif
Jmp #4
; #1
JmpIfFalse cond2 #2
; consequent
Jmp #4
; #2
JmpIfFalse cond3 #3
; consequent
Jmp #4
; #3
; 没有一次执行分支
; else部分
; ...
#4
*/
std::vector<int> exitJumps; // 所有分支都要跳到最后收集所有jump最后回填
const auto &condResult = compileExpr(stmt->cond);
if (!condResult)
{
return std::unexpected(condResult.error());
}
std::uint8_t condReg = *condResult;
int jumpToNext = EmitJump(OpCode::JmpIfFalse, condReg);
FreeReg(condReg);
const auto &blockResult = compileStmt(stmt->consequent);
if (!blockResult)
{
return blockResult;
}
exitJumps.push_back(EmitJump(OpCode::Jmp)); // 执行完if直接跳到出口
PatchJump(jumpToNext); // 回填跳到下一个else/elseif
for (auto *elif : stmt->elifs)
{
const auto &elifCondResult = compileExpr(elif->cond);
if (!elifCondResult)
return std::unexpected(elifCondResult.error());
std::uint8_t elifCondReg = *elifCondResult;
jumpToNext = EmitJump(OpCode::JmpIfFalse, elifCondReg);
FreeReg(elifCondReg);
const auto &blockResult = compileStmt(elif->consequent);
if (!blockResult)
{
return blockResult;
}
exitJumps.push_back(EmitJump(OpCode::Jmp)); // 执行完else if跳到出口
PatchJump(jumpToNext); // 跳到下一个分支
}
if (stmt->alternate)
{
auto result = compileStmt(stmt->alternate);
if (!result)
{
return result;
}
}
for (int exitIndex : exitJumps)
{
PatchJump(exitIndex); // 回填所有跳转出口的指令
}
return {};
}
Result<void, Error> Compiler::compileWhileStmt(WhileStmt *stmt)
{
int beginIns = current->proto->code.size() - 1;
auto condRegResult = compileExpr(stmt->cond);
if (!condRegResult)
{
return std::unexpected(condRegResult.error());
}
std::uint8_t condReg = *condRegResult;
int exitJump = EmitJump(OpCode::JmpIfFalse, condReg);
auto bodyResult = compileBlockStmt(stmt->body);
if (!bodyResult)
{
return bodyResult;
}
Emit(Op::iAsBx(
OpCode::Jmp, 0, beginIns - current->proto->code.size())); // 回到开头对condition求值
PatchJump(exitJump);
return {};
}
Result<void, Error> Compiler::compileFnDefStmt(FnDefStmt *stmt)
{
std::uint8_t funcReg = DeclareLocal(stmt->localId);
// 创建子函数编译状态
// 传入 current 作为 enclosing用于后续支持闭包 Upvalue 查找
FuncState childState(stmt->name, current);
allProtos.push_back(childState.proto);
std::uint16_t protoIdx = static_cast<std::uint16_t>(allProtos.size() - 1);
globalFuncMap[stmt->localId] = protoIdx; // 把函数的local id映射到protoIdx
{
FuncStateProtector stateGuard(this, &childState);
AllocReg();
// 将参数映射为子函数的初始局部变量 (R0, R1...)
for (Param *p : stmt->params)
{
PosParam *posParam = static_cast<PosParam *>(p); // TODO: 其他参数支持...
// 按顺序分配寄存器
DeclareLocal(posParam->localId);
}
// B编译函数体语句
auto bodyRes = compileStmt(stmt->body);
if (!bodyRes)
return bodyRes;
// 隐式返回 null
std::uint8_t resReg = AllocReg();
Emit(Op::iABC(OpCode::LoadNull, resReg, 0, 0));
Emit(Op::iABC(OpCode::Return, resReg, 0, 0));
}
// 5. 检查是否是 main 函数
if (stmt->name == U"main")
{
this->mainFuncIndex = protoIdx;
}
Emit(Op::iABx(OpCode::LoadFn, funcReg, protoIdx));
return {};
}
Result<void, Error> Compiler::compileReturnStmt(ReturnStmt *stmt)
{
auto res = compileExpr(stmt->value);
if (!res)
{
return std::unexpected(res.error());
}
Emit(Op::iABC(OpCode::Return, *res, 0, 0));
return {};
}
Result<void, Error> Compiler::compileStmt(Stmt *stmt) // 编译语句
{
switch (stmt->type)
{
case AstType::ExprStmt: {
ExprStmt *exprStmt = static_cast<ExprStmt *>(stmt);
Expr *expr = exprStmt->expr;
auto result = compileExpr(expr);
if (!result)
case AstType::BlockStmt: {
auto *b = static_cast<BlockStmt *>(stmt);
for (auto *n : b->nodes)
{
return std::unexpected(result.error());
auto res = compileStmt(n);
if (!res)
return res;
}
FreeReg(*result);
break;
}
case AstType::VarDecl: {
return compileVarDecl(static_cast<VarDecl *>(stmt));
}
auto *v = static_cast<VarDecl *>(stmt);
if (current->enclosing == nullptr) // 处理全局变量
{
Register mark = current->freereg; // 记录水位线
auto regRes = compileExpr(v->initExpr);
if (!regRes)
return std::unexpected(regRes.error());
case AstType::BlockStmt: {
return compileBlockStmt(static_cast<BlockStmt *>(stmt));
}
emit(Op::iABx(
OpCode::SetGlobal, *regRes, static_cast<uint16_t>(getGlobalID(v->name))));
current->freereg = mark; // 释放初始化表达式的临时占用
}
else
{
// 抬升水位,锁死局部变量的物理槽位
Register targetReg = static_cast<Register>(v->localId);
while (current->freereg <= targetReg)
{
auto allocRes = allocateReg(v->location);
if (!allocRes)
{
return std::unexpected(allocRes.error());
}
}
case AstType::IfStmt: {
return compileIfStmt(static_cast<IfStmt *>(stmt));
}
case AstType::WhileStmt: {
return compileWhileStmt(static_cast<WhileStmt *>(stmt));
auto regRes = compileExpr(v->initExpr, targetReg);
if (!regRes)
return std::unexpected(regRes.error());
}
break;
}
case AstType::FnDefStmt: {
return compileFnDefStmt(static_cast<FnDefStmt *>(stmt));
}
case AstType::ReturnStmt: {
return compileReturnStmt(static_cast<ReturnStmt *>(stmt));
}
}
auto *f = static_cast<FnDefStmt *>(stmt);
return Result<void, Error>();
// 物理连线:对接 Compile() 第一阶段预分配的 Proto
Proto *p = module->protos[f->resolvedSymbol->index];
FuncState fs(p, current);
FuncState *old = current;
current = &fs;
auto res = compileStmt(f->body);
if (!res)
return res;
// 窥孔拦截:防死代码污染
if (p->code.empty() || static_cast<OpCode>(p->code.back() & 0xFF) != OpCode::Return)
{
emit(Op::iABC(OpCode::Return, 0, 0, 0));
}
current = old;
break;
}
case AstType::IfStmt: {
auto *i = static_cast<IfStmt *>(stmt);
DynArray<int> exitJumps;
Register mark = current->freereg; // 记录水位线
auto r_cond = compileExpr(i->cond);
if (!r_cond)
return std::unexpected(r_cond.error());
int jmpToNext = static_cast<int>(current->proto->code.size());
emit(Op::iAsBx(OpCode::JmpIfFalse, *r_cond, 0));
current->freereg = mark; // 回收条件表达式临时槽位
if (auto r = compileStmt(i->consequent); !r)
return r;
exitJumps.push_back(static_cast<int>(current->proto->code.size()));
emit(Op::iAsBx(OpCode::Jmp, 0, 0));
int targetIdx = static_cast<int>(current->proto->code.size());
current->proto->code[jmpToNext] = Op::iAsBx(
OpCode::JmpIfFalse, *r_cond, static_cast<int16_t>(targetIdx - jmpToNext - 1));
for (auto *elif : i->elifs)
{
Register elifMark = current->freereg;
auto ec = compileExpr(elif->cond);
if (!ec)
return std::unexpected(ec.error());
int nextElif = static_cast<int>(current->proto->code.size());
emit(Op::iAsBx(OpCode::JmpIfFalse, *ec, 0));
current->freereg = elifMark; // 回收 elif 临时槽位
if (auto r = compileStmt(elif->consequent); !r)
return r;
exitJumps.push_back(static_cast<int>(current->proto->code.size()));
emit(Op::iAsBx(OpCode::Jmp, 0, 0));
int target = static_cast<int>(current->proto->code.size());
current->proto->code[nextElif] = Op::iAsBx(
OpCode::JmpIfFalse, *ec, static_cast<int16_t>(target - nextElif - 1));
}
if (i->alternate)
{
if (auto r = compileStmt(i->alternate); !r)
return r;
}
int endIdx = static_cast<int>(current->proto->code.size());
for (int pos : exitJumps)
{
current->proto->code[pos] =
Op::iAsBx(OpCode::Jmp, 0, static_cast<int16_t>(endIdx - pos - 1));
}
break;
}
case AstType::WhileStmt: {
auto *w = static_cast<WhileStmt *>(stmt);
int startIdx = static_cast<int>(current->proto->code.size());
Register mark = current->freereg; // 记录水位线
auto r_cond = compileExpr(w->cond);
if (!r_cond)
return std::unexpected(r_cond.error());
int exitJmpIdx = static_cast<int>(current->proto->code.size());
emit(Op::iAsBx(OpCode::JmpIfFalse, *r_cond, 0));
current->freereg = mark; // 回收循环条件临时槽位
if (auto r = compileStmt(w->body); !r)
return r;
int backJmpIdx = static_cast<int>(current->proto->code.size());
emit(Op::iAsBx(OpCode::Jmp, 0, static_cast<int16_t>(startIdx - backJmpIdx - 1)));
int endIdx = static_cast<int>(current->proto->code.size());
current->proto->code[exitJmpIdx] = Op::iAsBx(
OpCode::JmpIfFalse, *r_cond, static_cast<int16_t>(endIdx - exitJmpIdx - 1));
break;
}
case AstType::ReturnStmt: {
auto *rs = static_cast<ReturnStmt *>(stmt);
Register mark = current->freereg; // 记录水位线
Register retReg;
if (rs->value)
{
auto r = compileExpr(rs->value);
if (!r)
return std::unexpected(r.error());
retReg = *r;
}
else
{
auto r = allocateReg(rs->location);
if (!r)
return std::unexpected(r.error());
emit(Op::iABC(OpCode::LoadNull, *r, 0, 0));
retReg = *r;
}
emit(Op::iABC(OpCode::Return, retReg, 0, 0));
current->freereg = mark; // 回收返回值计算的占用
break;
}
case AstType::ExprStmt: {
Register mark = current->freereg; // 记录水位线
auto reg = compileExpr(static_cast<ExprStmt *>(stmt)->expr);
if (!reg)
return std::unexpected(reg.error());
current->freereg = mark; // 彻底抛弃孤立表达式的副作用
break;
}
default: break;
}
return {};
}
}; // namespace Fig
} // namespace Fig

47
src/Error/Diagnostics.hpp Normal file
View 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

View File

@@ -59,8 +59,12 @@ namespace Fig
case TooManyLocals: return "TooManyLocals";
case TooManyConstants: return "TooManyConstants";
case RegisterOverflow: return "RegisterOverflow";
case InternalError: return "InternalError";
// default: return "Some one forgot to add case to `ErrorTypeToString`";
}
return "UnknownError";
}
void PrintSystemInfos()
@@ -170,4 +174,4 @@ namespace Fig
ost << '\n';
}
}
}; // namespace Fig
}; // namespace Fig

View File

@@ -11,7 +11,6 @@
#include <Deps/Deps.hpp>
#include <SourceManager/SourceManager.hpp>
#include <source_location>
namespace Fig
@@ -51,6 +50,10 @@ namespace Fig
// compile errors
TooManyLocals,
TooManyConstants,
// --- 新增编译器内部与VM约束 ---
RegisterOverflow,
InternalError,
};
const char *ErrorTypeToString(ErrorType type);
@@ -77,6 +80,9 @@ namespace Fig
location = _location;
thrower_loc = _throwerloc;
}
// 新增:适配诊断系统的辅助判定
bool IsWarning() const { return static_cast<unsigned int>(type) < 2000; }
};
namespace TerminalColors
@@ -174,4 +180,4 @@ namespace Fig
}
void ReportError(const Error &error, const SourceManager &srcManager);
}; // namespace Fig
}; // namespace Fig

View File

@@ -187,7 +187,7 @@ namespace Fig
/*
C风格继承 + 手动分发
禁止任何 virtual 达到最高效率
禁止核心使用任何 virtual 达到最高效率
*/
enum class ObjectType : uint8_t
{
@@ -227,5 +227,23 @@ namespace Fig
{
return type == ObjectType::Instance;
}
// 调试输出
virtual String toString() const
{
return "Object";
}
};
} // namespace Fig
} // namespace Fig
namespace std
{
template <>
struct hash<Fig::Value>
{
std::size_t operator()(const Fig::Value &v) const noexcept
{
return std::hash<std::uint64_t>()(v.Raw());
}
};
} // namespace std

View File

@@ -25,5 +25,10 @@ namespace Fig
struct StringObject final : public Object
{
String data; // 40 bytes
virtual String toString() const override
{
return data;
}
};
};

View File

@@ -39,6 +39,10 @@ namespace Fig
0 - UnaryOperators::Count BinaryOperators::Count
*/
Value fields[];
Object *GetUnaryOperator(UnaryOperator _op)
{
std::uint8_t idx = static_cast<std::uint8_t>(_op);

View File

@@ -9,7 +9,7 @@
namespace Fig
{
Result<LiteralExpr *, Error> Parser::parseLiteralExpr() // 当前token为literal时调用
Result<Expr *, Error> Parser::parseLiteralExpr() // 当前token为literal时调用
{
StateProtector p(this, {State::ParsingLiteralExpr});
@@ -17,7 +17,7 @@ namespace Fig
LiteralExpr *node = arena.Allocate<LiteralExpr>(literal_token, makeSourceLocation(literal_token));
return node;
}
Result<IdentiExpr *, Error> Parser::parseIdentiExpr() // 当前token为Identifier调用
Result<Expr *, Error> Parser::parseIdentiExpr() // 当前token为Identifier调用
{
StateProtector p(this, {State::ParsingIdentiExpr});
@@ -27,7 +27,7 @@ namespace Fig
return node;
}
Result<InfixExpr *, Error> Parser::parseInfixExpr(Expr *lhs) // 当前token为 op
Result<Expr *, Error> Parser::parseInfixExpr(Expr *lhs) // 当前token为 op
{
StateProtector p(this, {State::ParsingInfixExpr});
@@ -46,7 +46,7 @@ namespace Fig
return node;
}
Result<PrefixExpr *, Error> Parser::parsePrefixExpr() // 当前token为op
Result<Expr *, Error> Parser::parsePrefixExpr() // 当前token为op
{
StateProtector p(this, {State::ParsingPrefixExpr});
@@ -65,7 +65,7 @@ namespace Fig
return node;
}
Result<IndexExpr *, Error> Parser::parseIndexExpr(
Result<Expr *, Error> Parser::parseIndexExpr(
Expr *base) // 由 parseExpression调用, 当前token为 `[`
{
StateProtector p(this, {State::ParsingIndexExpr});
@@ -91,7 +91,7 @@ namespace Fig
return indexExpr;
}
Result<CallExpr *, Error> Parser::parseCallExpr(
Result<Expr *, Error> Parser::parseCallExpr(
Expr *callee) // 由 parseExpression调用, 当前token为 `(`
{
StateProtector p(this, {State::ParsingCallExpr});

View File

@@ -1,8 +1,8 @@
/*!
@file src/Parser/Parser.cpp
@brief 语法分析器(Pratt + 手动递归下降) 实现
@brief 语法分析器实现
@author PuqiAR (im@puqiar.top)
@date 2026-02-14
@date 2026-03-08
*/
#include <Parser/Parser.hpp>
@@ -12,21 +12,22 @@ namespace Fig
Result<Program *, Error> Parser::Parse()
{
Program *program = arena.Allocate<Program>();
while (!isEOF)
while (currentToken().type != TokenType::EndOfFile)
{
auto result = parseStatement();
if (!result)
{
return std::unexpected(result.error());
}
Stmt *stmt = *result;
if (!stmt)
if (stmt)
{
continue;
program->nodes.push_back(stmt);
}
program->nodes.push_back(stmt);
}
return program;
}
}; // namespace Fig
}; // namespace Fig

View File

@@ -2,7 +2,7 @@
@file src/Parser/Parser.hpp
@brief 语法分析器(Pratt + 手动递归下降) 定义
@author PuqiAR (im@puqiar.top)
@date 2026-02-14
@date 2026-03-08
*/
#pragma once
@@ -16,12 +16,10 @@
#include <cstddef>
#include <cstdlib>
#include <unordered_set>
namespace Fig
{
class Parser
{
private:
@@ -29,60 +27,56 @@ namespace Fig
Lexer &lexer;
SourceManager &srcManager;
size_t index = 0; // tokenbuffer下标
DynArray<Token> buffer;
size_t index = 0; // 当前 Tokenbuffer 中的下标
DynArray<Token> buffer; // 已从 Lexer 读取的 Token 缓存
String fileName;
bool isEOF = false;
bool isEOF = false;
// 惰性获取下一个 Token跳过注释
Token nextToken()
{
assert(!isEOF && "nextToken: eof but called nextToken");
if (index + 1 < buffer.size())
{
return buffer[++index];
}
auto result = lexer.NextToken();
if (!result)
if (isEOF)
return buffer[index];
while (true)
{
ReportError(result.error(), srcManager);
std::exit(-1);
auto result = lexer.NextToken();
if (!result)
{
ReportError(result.error(), srcManager);
std::exit(-1);
}
const Token &token = result.value();
if (token.type == TokenType::Comments)
continue; // 惰性跳过注释
if (token.type == TokenType::EndOfFile)
isEOF = true;
buffer.push_back(token);
index = buffer.size() - 1;
return buffer[index];
}
const Token &token = result.value();
if (token.type == TokenType::EndOfFile)
{
isEOF = true;
}
buffer.push_back(token);
index++;
return token;
}
inline Token prevToken()
{
if (buffer.size() < 2)
{
return currentToken();
}
return buffer[buffer.size() - 2];
return (index > 0) ? buffer[index - 1] : buffer[0];
}
inline Token currentToken()
{
if (buffer.empty())
{
return nextToken();
}
return buffer.back();
return buffer[index];
}
// 惰性窥视后续 Token
Token peekToken(size_t lookahead = 1)
{
assert(!isEOF && "peekToken: eof but called peekToken");
size_t peekIndex = index + lookahead;
while (peekIndex >= buffer.size() && !isEOF)
size_t targetIndex = index + lookahead;
while (targetIndex >= buffer.size() && !isEOF)
{
auto result = lexer.NextToken();
if (!result)
@@ -90,29 +84,22 @@ namespace Fig
ReportError(result.error(), srcManager);
std::abort();
}
const Token &token = result.value();
if (token.type == TokenType::EndOfFile)
{
if (result->type == TokenType::Comments)
continue;
if (result->type == TokenType::EndOfFile)
isEOF = true;
}
buffer.push_back(token);
buffer.push_back(*result);
}
if (peekIndex >= buffer.size()) // 没有那么多token
{
return buffer.back(); // back是EOF Token
}
return buffer[peekIndex];
return (targetIndex >= buffer.size()) ? buffer.back() : buffer[targetIndex];
}
inline Token consumeToken()
{
if (isEOF)
return buffer.back();
Token current = currentToken();
nextToken();
if (current.type != TokenType::EndOfFile)
nextToken();
return current;
}
inline bool match(TokenType type)
{
if (currentToken().type == type)
@@ -123,47 +110,18 @@ namespace Fig
return false;
}
inline Error makeUnexpectTokenError(const String &stmtType,
const String &expect,
const Token &tokenGot,
std::source_location loc = std::source_location::current())
{
return Error(ErrorType::SyntaxError,
std::format("expect '{}' in {}, got `{}`",
expect,
stmtType,
magic_enum::enum_name(tokenGot.type)),
"none",
makeSourceLocation(tokenGot),
loc);
}
inline Error makeExpectSemicolonError(
std::source_location loc = std::source_location::current())
{
return Error(ErrorType::SyntaxError,
"expect ';' after statement",
"insert ';'",
makeSourceLocation(currentToken()),
loc);
}
public:
struct State
{
enum StateType : std::uint8_t
{
Standby,
ParsingLiteralExpr,
ParsingIdentiExpr,
ParsingInfixExpr,
ParsingPrefixExpr,
ParsingIndexExpr,
ParsingCallExpr,
ParsingVarDecl,
ParsingIf,
ParsingWhile,
@@ -171,9 +129,7 @@ namespace Fig
ParsingReturn,
ParsingBreak,
ParsingContinue,
ParsingNamedTypeExpr,
} type = StateType::Standby;
std::unordered_set<TokenType> stopAt = {};
};
@@ -190,134 +146,121 @@ namespace Fig
return baseTerminators;
}
std::unordered_set<TokenType> &getTerminators() // 返回固定的终止符
std::unordered_set<TokenType> &getTerminators()
{
/*
Syntax terminators:
; ) ] } , EOF
*/
static std::unordered_set<TokenType> terminators(getBaseTerminators());
return terminators;
}
void resetTermintors()
{
getTerminators() = getBaseTerminators();
}
bool shouldTerminate() // 判断是否终结
{
const Token &token = currentToken();
const auto &terminators = getTerminators();
if (terminators.contains(token.type))
{
bool shouldTerminate()
{
const Token &token = currentToken();
if (getTerminators().contains(token.type))
return true;
}
for (auto it = stateStack.rbegin(); it < stateStack.rend(); ++it)
{
if (it->stopAt.contains(token.type))
{
return true;
}
}
return false;
}
DynArray<State> stateStack;
State &currentState()
State &currentState()
{
return stateStack.back();
}
void pushState(State _state)
{
stateStack.push_back(std::move(_state));
}
void popState()
{
if (!stateStack.empty())
{
stateStack.pop_back();
}
}
class StateProtector
struct StateProtector
{
Parser *parser;
public:
StateProtector(Parser *p, const State &newState) : parser(p)
Parser *p;
StateProtector(Parser *_p, State _s) : p(_p)
{
parser->pushState(newState);
p->pushState(_s);
}
~StateProtector()
{
parser->popState();
p->popState();
}
// 禁止拷贝
StateProtector(const StateProtector &) = delete;
StateProtector &operator=(const StateProtector &) = delete;
};
public:
Parser(Lexer &_lexer, SourceManager &_srcManager, String _fileName) :
lexer(_lexer), srcManager(_srcManager), fileName(std::move(_fileName))
{
pushState(State());
}
private:
SourceLocation makeSourceLocation(const Token &tok)
{
auto [line, column] = srcManager.GetLineColumn(tok.index);
// 物理防爆盾:防止因解析错位导致的异常列号引起终端 OOM
if (column > 5000)
column = 1;
return SourceLocation(SourcePosition(line, column, tok.length),
fileName,
"[internal parser]",
magic_enum::enum_name(currentState().type).data());
}
/* TypeExpressions */
inline Error makeUnexpectTokenError(const String &stmt, const String &exp, const Token &got)
{
return Error(ErrorType::SyntaxError,
std::format(
"expect '{}' in {}, got `{}`", exp, stmt, magic_enum::enum_name(got.type)),
"none",
makeSourceLocation(got));
}
Result<NamedTypeExpr *, Error> parseNamedTypeExpr(); // 当前token为identifier
inline Error makeExpectSemicolonError()
{
return Error(ErrorType::SyntaxError,
"expect ';' after statement",
"insert ';'",
makeSourceLocation(currentToken()));
}
Result<TypeExpr *, Error> parseTypeExpr();
/* Expressions */
Result<LiteralExpr *, Error> parseLiteralExpr(); // 当前token为literal时调用
Result<IdentiExpr *, Error> parseIdentiExpr(); // 当前token为Identifier调用
Result<InfixExpr *, Error> parseInfixExpr(
Expr *); // 由 parseExpression递归调用, 当前token为op
Result<PrefixExpr *, Error> parsePrefixExpr(); // 由 parseExpression递归调用, 当前token为op
Result<IndexExpr *, Error> parseIndexExpr(
Expr *); // 由 parseExpression调用, 当前token为 `[`
Result<CallExpr *, Error> parseCallExpr(Expr *); // 由 parseExpression调用, 当前token为 `(`
Result<TypeExpr *, Error> parseNamedTypeExpr();
Result<Expr *, Error> parseExpression(BindingPower = 0);
Result<Expr *, Error> parseLiteralExpr();
Result<Expr *, Error> parseIdentiExpr();
Result<Expr *, Error> parsePrefixExpr();
Result<Expr *, Error> parseInfixExpr(Expr *);
Result<Expr *, Error> parseIndexExpr(Expr *);
Result<Expr *, Error> parseCallExpr(Expr *);
Result<Expr *, Error> parseNewExpr();
/* Statements */
Result<BlockStmt *, Error> parseBlockStmt(); // 当前token为 {
Result<VarDecl *, Error> parseVarDecl(bool); // 由 parseStatement调用, 当前token为 var
Result<IfStmt *, Error> parseIfStmt(); // 由 parseStatement调用, 当前token为 if
Result<WhileStmt *, Error> parseWhileStmt(); // 由 parseStatement调用, 当前token为 while
Result<BlockStmt *, Error> parseBlockStmt();
Result<VarDecl *, Error> parseVarDecl(bool);
Result<IfStmt *, Error> parseIfStmt();
Result<WhileStmt *, Error> parseWhileStmt();
Result<DynArray<Param *>, Error> parseFnParams();
Result<FnDefStmt *, Error> parseFnDefStmt(bool);
Result<ReturnStmt *, Error> parseReturnStmt();
Result<DynArray<Param *>, Error> parseFnParams(); // 由 parseFnDefStmt或lambda调用
Result<FnDefStmt *, Error> parseFnDefStmt(bool); // 由 parseStatement调用, 当前token为 func
Result<Stmt *, Error> parseStructDef(bool);
Result<Stmt *, Error> parseInterfaceDef(bool);
Result<Stmt *, Error> parseImpl();
Result<ReturnStmt *, Error> parseReturnStmt(); // 由 parseStatement调用, 当前token为 return
// continue break直接由parseStatement一步解析
Result<Stmt *, Error> parseStatement();
Result<Stmt *, Error> parseStatement();
public:
Parser(Lexer &_lexer, SourceManager &_src, String _file) :
lexer(_lexer), srcManager(_src), fileName(std::move(_file))
{
pushState(State());
}
Result<Program *, Error> Parse();
};
#define SET_STOP_AT(...) currentState().stopAt = {__VA_ARGS__};
}; // namespace Fig
} // namespace Fig

View File

@@ -7,6 +7,7 @@ int main()
String fileName = "test.fig";
String filePath = "T:/Files/Maker/Code/MyCodingLanguage/The Fig Project/Fig/test.fig";
SourceManager srcManager(filePath);
String source = srcManager.Read();

View File

@@ -1,5 +1,5 @@
/*!
@file src/Parser/StmtParser.hpp
@file src/Parser/StmtParser.cpp
@brief 语法分析器(Pratt + 手动递归下降) 语句解析实现
@author PuqiAR (im@puqiar.top)
@date 2026-02-19
@@ -9,9 +9,9 @@
namespace Fig
{
Result<BlockStmt *, Error> Parser::parseBlockStmt() // 当前token为 {
Result<BlockStmt *, Error> Parser::parseBlockStmt()
{
SourceLocation location = makeSourceLocation(consumeToken()); // consume `{`
SourceLocation location = makeSourceLocation(consumeToken());
BlockStmt *stmt = arena.Allocate<BlockStmt>();
while (true)
{
@@ -35,24 +35,23 @@ namespace Fig
}
return stmt;
}
Result<VarDecl *, Error> Parser::parseVarDecl(
bool isPublic) // 由 parseStatement调用, 当前token为 var
Result<VarDecl *, Error> Parser::parseVarDecl(bool isPublic)
{
StateProtector p(this, {State::ParsingVarDecl});
SourceLocation location = makeSourceLocation(consumeToken()); // consume `var`
SourceLocation location = makeSourceLocation(consumeToken());
if (currentToken().type != TokenType::Identifier)
{
return std::unexpected(makeUnexpectTokenError("VarDecl", "var name", currentToken()));
}
const String &name = srcManager.GetSub(currentToken().index, currentToken().length);
consumeToken(); // consume name
consumeToken();
TypeExpr *typeSpeicifer = nullptr;
if (match(TokenType::Colon)) // `:`
if (match(TokenType::Colon))
{
// SET_STOP_AT(TokenType::Walrus, TokenType::Assign);
auto result = parseTypeExpr();
if (!result)
{
@@ -72,15 +71,14 @@ namespace Fig
}
initExpr = *result;
}
else if (match(TokenType::Walrus)) // :=
else if (match(TokenType::Walrus))
{
if (typeSpeicifer) // 指定了类型同时使用 :=
if (typeSpeicifer)
{
return std::unexpected(Error(ErrorType::SyntaxError,
"used type infer but specifying the type",
"change `:=` to '='",
makeSourceLocation(prevToken()) // :=
));
makeSourceLocation(prevToken())));
}
auto result = parseExpression();
if (!result)
@@ -88,24 +86,25 @@ namespace Fig
return std::unexpected(result.error());
}
initExpr = *result;
isInfer = true; // 使用类型自动推断 :=
isInfer = true;
}
if (!match(TokenType::Semicolon))
{
return std::unexpected(makeExpectSemicolonError());
}
VarDecl *varDecl = arena.Allocate<VarDecl>(isPublic, name, typeSpeicifer, isInfer, initExpr, location);
VarDecl *varDecl =
arena.Allocate<VarDecl>(isPublic, name, typeSpeicifer, isInfer, initExpr, location);
return varDecl;
}
Result<IfStmt *, Error> Parser::parseIfStmt() // 由 parseStatement调用, 当前token is if
Result<IfStmt *, Error> Parser::parseIfStmt()
{
StateProtector p(this, {State::ParsingIf});
SourceLocation location = makeSourceLocation(consumeToken()); // consume `if`
SourceLocation location = makeSourceLocation(consumeToken());
Expr *cond = nullptr;
if (match(TokenType::LeftParen)) // match and consume `(`
if (match(TokenType::LeftParen))
{
const Token &lpToken = prevToken();
SET_STOP_AT(TokenType::RightParen, TokenType::LeftBrace);
@@ -116,7 +115,6 @@ namespace Fig
}
if (!match(TokenType::RightParen))
{
delete *result;
return std::unexpected(Error(ErrorType::SyntaxError,
"unclosed parenthese in if condition",
"insert `)`",
@@ -155,7 +153,6 @@ namespace Fig
SourceLocation elseLocation = makeSourceLocation(prevToken());
if (match(TokenType::If))
{
// else if
if (alternate)
{
return std::unexpected(Error(ErrorType::SyntaxError,
@@ -166,7 +163,7 @@ namespace Fig
Expr *cond = nullptr;
if (match(TokenType::LeftParen)) // `(`
if (match(TokenType::LeftParen))
{
const Token &lpToken = prevToken();
@@ -178,7 +175,6 @@ namespace Fig
}
if (!match(TokenType::RightParen))
{
delete *result;
return std::unexpected(Error(ErrorType::SyntaxError,
"unclosed parenthese in if condition",
"insert `)`",
@@ -212,7 +208,6 @@ namespace Fig
}
else
{
// else
if (alternate)
{
return std::unexpected(Error(ErrorType::SyntaxError,
@@ -237,11 +232,11 @@ namespace Fig
return ifStmt;
}
Result<WhileStmt *, Error> Parser::parseWhileStmt() // 由 parseStatement调用, 当前token为 while
Result<WhileStmt *, Error> Parser::parseWhileStmt()
{
StateProtector p(this, {State::ParsingWhile});
SourceLocation location = makeSourceLocation(consumeToken()); // consume `while`
SourceLocation location = makeSourceLocation(consumeToken());
Expr *cond = nullptr;
if (match(TokenType::LeftParen))
@@ -257,7 +252,6 @@ namespace Fig
if (!match(TokenType::RightParen))
{
delete *result;
return std::unexpected(Error(ErrorType::SyntaxError,
"unclosed parenthese in while condition",
"insert ')'",
@@ -278,7 +272,6 @@ namespace Fig
if (currentToken().type != TokenType::LeftBrace)
{
delete cond;
return std::unexpected(
makeUnexpectTokenError("while stmt", "left brace '{'", currentToken()));
}
@@ -286,7 +279,6 @@ namespace Fig
auto result = parseBlockStmt();
if (!result)
{
delete cond;
return std::unexpected(result.error());
}
BlockStmt *body = *result;
@@ -295,11 +287,11 @@ namespace Fig
return whileStmt;
}
Result<DynArray<Param *>, Error> Parser::parseFnParams() // 由 parseFnDefStmt或lambda调用
Result<DynArray<Param *>, Error> Parser::parseFnParams()
{
StateProtector p(this, {State::ParsingFnDefStmt});
const Token &lpToken = consumeToken(); // consume `(`
const Token &lpToken = consumeToken();
DynArray<Param *> params;
while (true)
@@ -320,10 +312,8 @@ namespace Fig
SourceLocation location = makeSourceLocation(nToken);
const String &name = srcManager.GetSub(nToken.index, nToken.length);
// TODO: 支持剩余参数解析...
TypeExpr *type = nullptr;
if (match(TokenType::Colon)) // :
if (match(TokenType::Colon))
{
auto result = parseTypeExpr();
if (!result)
@@ -335,16 +325,12 @@ namespace Fig
Expr *defaultValue = nullptr;
if (match(TokenType::Assign)) // =
if (match(TokenType::Assign))
{
SET_STOP_AT(TokenType::Comma, TokenType::RightParen, TokenType::LeftBrace); // , ) {
SET_STOP_AT(TokenType::Comma, TokenType::RightParen, TokenType::LeftBrace);
auto result = parseExpression();
if (!result)
{
if (type)
{
delete type;
}
return std::unexpected(result.error());
}
defaultValue = *result;
@@ -365,18 +351,16 @@ namespace Fig
return params;
}
Result<FnDefStmt *, Error> Parser::parseFnDefStmt(
bool isPublic) // 由 parseStatement调用, 当前token为 func
Result<FnDefStmt *, Error> Parser::parseFnDefStmt(bool isPublic)
{
SourceLocation location = makeSourceLocation(
consumeToken()); // 无论是否加了public, location都设置为 func token (我懒 :D)
SourceLocation location = makeSourceLocation(consumeToken());
if (!currentToken().isIdentifier())
{
return std::unexpected(
makeUnexpectTokenError("fn def stmt", "function name", currentToken()));
}
const Token &nameToken = consumeToken(); // consume name
const Token &nameToken = consumeToken();
const String &name = srcManager.GetSub(nameToken.index, nameToken.length);
if (currentToken().type != TokenType::LeftParen)
@@ -395,7 +379,7 @@ namespace Fig
params = *paraResult;
TypeExpr *returnType = nullptr;
if (match(TokenType::RightArrow)) // ->
if (match(TokenType::RightArrow))
{
auto result = parseTypeExpr();
if (!result)
@@ -415,24 +399,20 @@ namespace Fig
if (!bodyResult)
{
if (returnType)
{
delete returnType;
}
return std::unexpected(bodyResult.error());
}
body = *bodyResult;
FnDefStmt *fnDef = arena.Allocate<FnDefStmt>(isPublic, name, params, returnType, body, location);
FnDefStmt *fnDef =
arena.Allocate<FnDefStmt>(isPublic, name, params, returnType, body, location);
return fnDef;
}
Result<ReturnStmt *, Error>
Parser::parseReturnStmt() // 由 parseStatement调用, 当前token为 return
Result<ReturnStmt *, Error> Parser::parseReturnStmt()
{
StateProtector p(this, {State::ParsingReturn});
SourceLocation location = makeSourceLocation(consumeToken()); // consume `return`
SourceLocation location = makeSourceLocation(consumeToken());
auto result = parseExpression();
if (!result)
{
@@ -455,7 +435,7 @@ namespace Fig
if (currentToken().type == TokenType::Public)
{
consumeToken(); // consume `public`
consumeToken();
if (currentToken().type == TokenType::Variable)
{
return parseVarDecl(true);

View File

@@ -1,54 +1,73 @@
/*!
@file src/Parser/TypeExprParser.cpp
@brief 类型表达式解析器实现
@brief 类型表达式解析器实现:支持泛型与空安全
@author PuqiAR (im@puqiar.top)
@date 2026-02-25
@date 2026-03-08
*/
#include <Parser/Parser.hpp>
namespace Fig
{
Result<NamedTypeExpr *, Error> Parser::parseNamedTypeExpr() // 当前token为identifier
// 解析基础命名类型与泛型: List<Int>
Result<TypeExpr *, Error> Parser::parseNamedTypeExpr()
{
StateProtector p(this, {State::ParsingNamedTypeExpr});
SourceLocation location = makeSourceLocation(currentToken());
DynArray<String> path;
while (true)
{
const Token &subPathTok = consumeToken();
const String &subPath = srcManager.GetSub(subPathTok.index, subPathTok.length);
path.push_back(subPath);
const Token &tok = consumeToken();
const String &name = srcManager.GetSub(tok.index, tok.length);
path.push_back(name);
if (match(TokenType::Dot))
{
if (!currentToken().isIdentifier())
{
return std::unexpected(
makeUnexpectTokenError("named type expr", "identifier", currentToken()));
}
return std::unexpected(makeUnexpectTokenError("Type", "identifier", currentToken()));
}
else
else break;
}
DynArray<TypeExpr *> arguments;
if (match(TokenType::Less)) // `<`
{
while (true)
{
break;
auto result = parseTypeExpr();
if (!result) return std::unexpected(result.error());
arguments.push_back(*result);
if (match(TokenType::Greater)) break; // `>`
if (!match(TokenType::Comma))
return std::unexpected(makeUnexpectTokenError("TypeArgs", "'>' or ','", currentToken()));
}
}
NamedTypeExpr *namedTypeExpr = arena.Allocate<NamedTypeExpr>(path, location);
return namedTypeExpr;
return arena.Allocate<NamedTypeExpr>(path, arguments, location);
}
// 解析主入口: 处理 `?` 后缀
Result<TypeExpr *, Error> Parser::parseTypeExpr()
{
// TODO: 泛型表达式解析
TypeExpr *base = nullptr;
// 目前只支持命名类型 (以后可以加函数类型 (Int)->Int)
if (currentToken().isIdentifier())
{
return parseNamedTypeExpr();
auto res = parseNamedTypeExpr();
if (!res) return std::unexpected(res.error());
base = *res;
}
else
else return std::unexpected(makeUnexpectTokenError("TypeExpr", "name", currentToken()));
// 空安全处理: Int?? 也可以,但 Analyzer 会规范化它
while (match(TokenType::Question))
{
return std::unexpected(makeUnexpectTokenError("type expr", "name/...", currentToken()));
base = arena.Allocate<NullableTypeExpr>(base, makeSourceLocation(prevToken()));
}
return base;
}
}; // namespace Fig
}

File diff suppressed because it is too large Load Diff

View File

@@ -1,100 +1,53 @@
/*!
@file src/Sema/Analyzer.hpp
@brief 前端类型检查器定义
@author PuqiAR (im@puqiar.top)
@date 2026-02-23
@brief 语义分析器定义
*/
#pragma once
#include <Sema/Environment.hpp>
#include <Sema/Type.hpp>
#include <Ast/Ast.hpp>
#include <Deps/Deps.hpp>
#include <Sema/Type.hpp>
#include <Sema/Environment.hpp>
#include <Utils/Arena.hpp>
#include <Error/Diagnostics.hpp>
#include <SourceManager/SourceManager.hpp>
namespace Fig
{
class Analyzer
{
private:
Environment env;
Arena arena;
SourceManager &manager;
TypeContext typeCtx;
Environment env;
Diagnostics diag;
TypeContext typeCtx;
HashMap<String, BaseType*> globalTypes;
HashMap<String, Symbol*> globalSymbols;
TypeInfo *currentReturnType = nullptr; // 正在分析的函数,预期返回类型
bool hasInit = false;
bool hasMain = false;
struct ReturnTypeProtector
{
Analyzer *analyzer;
TypeInfo *prevCurrentReturnType;
// 核心递归查找:解决跨越函数边界的捕获问题
Result<Symbol*, Error> resolveSymbolInternal(const String &name, const SourceLocation &loc, Scope* startScope);
[[nodiscard]]
ReturnTypeProtector(Analyzer *_analyzer, TypeInfo *current) :
analyzer(_analyzer), prevCurrentReturnType(_analyzer->currentReturnType)
{
analyzer->currentReturnType = current;
}
Result<Type, Error> resolveTypeExpr(TypeExpr *texpr);
Result<void, Error> pass1(Program *prog);
Result<void, Error> resolveTypes(Program *prog);
Result<void, Error> checkBodies(Program *prog);
~ReturnTypeProtector()
{
analyzer->currentReturnType = prevCurrentReturnType;
}
ReturnTypeProtector(const ReturnTypeProtector &) = delete;
ReturnTypeProtector &operator=(const ReturnTypeProtector &) = delete;
};
SourceLocation makeSourceLocation(
AstNode *ast, std::source_location loc = std::source_location::current())
{
return SourceLocation(ast->location.sp,
ast->location.fileName,
"[internal analyzer]",
loc.function_name());
}
bool isValidLvalue(Expr *expr)
{
if (expr->type == AstType::IdentiExpr)
{
return true;
}
if (expr->type == AstType::InfixExpr)
{
InfixExpr *infix = static_cast<InfixExpr *>(expr);
if (infix->op == BinaryOperator::MemberAccess)
{
return true;
}
}
if (expr->type == AstType::IndexExpr)
{
return true;
}
return false;
}
Result<TypeInfo *, Error> resolveType(TypeExpr *);
Result<void, Error> analyzeVarDecl(VarDecl *);
Result<void, Error> analyzeIfStmt(IfStmt *);
Result<void, Error> analyzeWhileStmt(WhileStmt *);
Result<void, Error> analyzeFnDefStmt(FnDefStmt *);
Result<void, Error> analyzeReturnStmt(ReturnStmt *);
Result<void, Error> analyzeIdentiExpr(IdentiExpr *);
Result<void, Error> analyzeInfixExpr(InfixExpr *);
Result<void, Error> analyzeCallExpr(CallExpr *);
Result<void, Error> analyzeStmt(Stmt *);
Result<void, Error> analyzeExpr(Expr *);
Result<void, Error> analyzeStmt(Stmt *stmt);
Result<Type, Error> analyzeExpr(Expr *expr);
int addUpvalue(Scope *scope, Symbol *target, bool isLocal);
public:
Result<void, Error> Analyze(Program *);
Analyzer(SourceManager &m) : manager(m) {}
Analyzer(SourceManager &_manager) : manager(_manager), typeCtx() {}
Result<void, Error> Analyze(Program *prog);
Diagnostics& GetDiagnostics() { return diag; }
TypeContext& GetTypeContext() { return typeCtx; }
};
}; // namespace Fig
}

View File

@@ -1,50 +1,59 @@
#include <Sema/Analyzer.hpp>
#include <Deps/Deps.hpp>
#include <Error/Error.hpp>
#include <Lexer/Lexer.hpp>
#include <Parser/Parser.hpp>
#include <SourceManager/SourceManager.hpp>
#include <Sema/Analyzer.hpp>
#include <filesystem>
#include <iostream>
namespace fs = std::filesystem;
void runTest(const std::string &path)
{
using namespace Fig;
std::cout << "\n[TEST] Testing: " << path << std::endl;
SourceManager srcManager{String(path)};
String source = srcManager.Read();
if (!srcManager.read)
{
std::cerr << "FAILED: Could not read file" << std::endl;
return;
}
Lexer lexer(source, String(path));
Parser parser(lexer, srcManager, String(path));
auto pRes = parser.Parse();
if (!pRes)
{
std::cerr << "FAILED: Parser Error" << std::endl;
ReportError(pRes.error(), srcManager);
return;
}
// 修复:确保 analyzer 存活直到错误打印完成
Analyzer analyzer(srcManager);
auto aRes = analyzer.Analyze(*pRes);
if (!aRes)
{
std::cout << "SUCCESS: Analyzer correctly caught error:" << std::endl;
ReportError(aRes.error(), srcManager);
}
else
{
std::cerr << "FAILED: Analyzer missed the semantic error!" << std::endl;
}
}
int main()
{
using namespace Fig;
const String &fileName = "test.fig";
const String &filePath = "T:/Files/Maker/Code/MyCodingLanguage/The Fig Project/Fig/test.fig";
SourceManager manager(filePath);
manager.Read();
if (!manager.read)
std::string testDir = "T:/Files/Maker/Code/MyCodingLanguage/The Fig Project/Fig/tests/Sema";
for (const auto &entry : fs::directory_iterator(testDir))
{
std::cerr << "Read file failed \n";
return 1;
if (entry.path().extension() == ".fig")
{
runTest(entry.path().string());
}
}
Lexer lexer(manager.GetSource(), fileName);
Parser parser(lexer, manager, fileName);
auto result = parser.Parse();
if (!result)
{
ReportError(result.error(), manager);
return 1;
}
Program *program = *result;
Analyzer analyzer(manager);
const auto &analyzeResult = analyzer.Analyze(program);
if (!analyzeResult)
{
ReportError(analyzeResult.error(), manager);
return 1;
}
std::cout << "Analyze successfully, PROGRAM OK\n";
return 0;
}
}

View File

@@ -1,147 +1,74 @@
/*!
@file src/Sema/Environment.hpp
@brief 符号和作用域环境定义
@author PuqiAR (im@puqiar.top)
@date 2026-02-23
@brief 树状符号表定义
*/
#pragma once
#include <Deps/Deps.hpp>
#include <Error/Error.hpp>
#include <Sema/Type.hpp>
#include <cassert>
#include <optional>
namespace Fig
{
// 记录在 Analyzer 中的符号元数据
enum class SymbolLocation
{
Global,
Local,
Upvalue
};
struct Symbol
{
String name;
TypeInfo *type;
bool isPublic;
int depth; // 词法作用域深度
bool isConstant; // 是否是 const 声明的不可变常量 (用于报错: 尝试修改常量)
String name;
Type type;
SymbolLocation location;
int index;
bool isConst;
int localId = -1; // Analyzer 虚拟槽位分配
Symbol(String n, Type t, SymbolLocation l, int i, bool c) :
name(std::move(n)), type(t), location(l), index(i), isConst(c)
{
}
};
// 作用域回档水位线
struct ScopeWatermark
struct UpvalueCapture
{
std::size_t symbolCount;
int savedLocalId;
Symbol *target;
int index;
bool isLocal;
};
// 语义分析函数上下文 (隔离局部变量 ID 空间)
struct SemaFuncState
struct Scope
{
SemaFuncState *enclosing = nullptr;
int currentDepth = 0;
int nextLocalId = 0;
DynArray<ScopeWatermark> scopeStack;
Scope *parent = nullptr;
bool isFunctionBoundary = false;
HashMap<String, Symbol *> locals;
DynArray<UpvalueCapture> upvalues;
int nextLocalId = 0;
Scope(Scope *p, bool isFn) : parent(p), isFunctionBoundary(isFn)
{
if (p && !isFn)
nextLocalId = p->nextLocalId;
}
};
class Environment
{
private:
DynArray<Symbol> symbols;
SemaFuncState *current = nullptr;
public:
Environment()
Scope *current = nullptr;
void Push(bool isFn)
{
current = new SemaFuncState();
current = new Scope(current, isFn);
}
~Environment()
void Pop()
{
while (current)
{
SemaFuncState *prev = current->enclosing;
delete current;
current = prev;
}
}
// 函数边界控
void EnterFunction()
{
SemaFuncState *newState = new SemaFuncState();
newState->enclosing = current;
current = newState;
}
void LeaveFunction()
{
assert(current && "Environment: Unmatched LeaveFunction");
SemaFuncState *oldState = current;
current = oldState->enclosing;
delete oldState;
}
// 词法作用域控制
void EnterScope()
{
current->currentDepth++;
current->scopeStack.push_back({symbols.size(), current->nextLocalId});
}
void LeaveScope()
{
assert(current->currentDepth > 0 && "Environment: Unmatched LeaveScope");
current->currentDepth--;
assert(!current->scopeStack.empty());
ScopeWatermark archive = current->scopeStack.back();
current->scopeStack.pop_back();
// 物理截断符号表,回滚槽位发号器以复用物理寄存器
while (symbols.size() > archive.symbolCount)
{
symbols.pop_back();
}
current->nextLocalId = archive.savedLocalId;
}
// 符号操作
// 注册符号, 返回分配的 localId。调用前内部执行同级作用域重定义断言
int Define(const String &name, TypeInfo *type, bool isPublic, bool isConst)
{
for (auto it = symbols.rbegin(); it != symbols.rend(); ++it)
{
if (it->depth < current->currentDepth)
break;
if (it->name == name)
{
assert(false && "Environment.Define: redefinition");
}
}
int allocatedId = current->nextLocalId++;
symbols.push_back({name, type, isPublic, current->currentDepth, isConst, allocatedId});
return allocatedId;
}
// 解析符号。找不到返回 nullopt
std::optional<Symbol> Resolve(const String &name)
{
for (auto it = symbols.rbegin(); it != symbols.rend(); ++it)
{
if (it->name == name)
return *it;
}
return std::nullopt;
}
int GetDepth() const
{
return current->currentDepth;
Scope *old = current;
current = current->parent;
delete old;
}
};
} // namespace Fig
} // namespace Fig

93
src/Sema/Type.cpp Normal file
View 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

View File

@@ -1,171 +1,115 @@
/*!
@file src/Sema/Type.hpp
@brief 前端类型检查的类型定义和类型驻留池
@author PuqiAR (im@puqiar.top)
@date 2026-02-23
@brief 类型系统定义:对齐 NaN-boxing 物理布局
*/
#pragma once
#include <Deps/Deps.hpp>
#include <cstdint>
#include <Error/Error.hpp>
namespace Fig
{
enum class TypeTag : std::uint8_t
{
Any, // 动态类型底线
Null, // 空值
Int,
Double,
Bool,
String,
Bool,
Null,
Any,
Function,
Struct,
Interface
};
struct TypeInfo
class BaseType;
struct Type
{
BaseType *base = nullptr;
bool isNullable = false;
bool operator==(const Type &other) const
{
return base == other.base && isNullable == other.isNullable;
}
bool operator!=(const Type &other) const
{
return !(*this == other);
}
bool is(TypeTag tag) const;
String toString() const;
bool isAssignableTo(const Type &target) const;
};
class BaseType
{
public:
TypeTag tag;
String name; // 完整路径序列化, 如 Int, std.file.File
String name;
BaseType(TypeTag t, String n) : tag(t), name(std::move(n)) {}
virtual ~BaseType() = default;
};
bool isAny() const
class FuncType : public BaseType
{
public:
DynArray<Type> paramTypes;
Type retType;
FuncType(DynArray<Type> params, Type ret) :
BaseType(TypeTag::Function, "Function"), paramTypes(std::move(params)), retType(ret)
{
return tag == TypeTag::Any;
}
bool isNull() const
{
return tag == TypeTag::Null;
}
bool isInt() const
{
return tag == TypeTag::Int;
}
bool isDouble() const
{
return tag == TypeTag::Double;
}
bool isBool() const
{
return tag == TypeTag::Bool;
}
bool isString() const
{
return tag == TypeTag::String;
}
bool isFunction() const
{
return tag == TypeTag::Function;
}
bool isStruct() const
{
return tag == TypeTag::Struct;
}
};
// 全局唯一类型驻留池
class StructType : public BaseType
{
public:
struct Field
{
String name;
Type type;
bool isPublic;
int index;
};
DynArray<Field> fields;
HashMap<String, size_t> fieldMap;
HashMap<String, class FnDefStmt *> methods;
StructType(String n) : BaseType(TypeTag::Struct, std::move(n)) {}
void AddField(String name, Type type, bool isPublic)
{
size_t idx = fields.size();
fields.push_back({name, type, isPublic, (int) idx});
fieldMap[name] = idx;
}
};
class InterfaceType : public BaseType
{
public:
struct MethodSig
{
String name;
DynArray<Type> params;
Type retType;
};
HashMap<String, MethodSig> methods;
InterfaceType(String n) : BaseType(TypeTag::Interface, std::move(n)) {}
};
class TypeContext
{
private:
DynArray<TypeInfo *> allTypes;
// 缓存
TypeInfo *typeAny;
TypeInfo *typeNull;
TypeInfo *typeInt;
TypeInfo *typeDouble;
TypeInfo *typeBool;
TypeInfo *typeString;
TypeInfo *typeFunction;
TypeInfo *typeStruct;
public:
TypeInfo *GetAny()
{
return typeAny;
}
TypeInfo *GetNull()
{
return typeNull;
}
TypeInfo *GetInt()
{
return typeInt;
}
TypeInfo *GetDouble()
{
return typeDouble;
}
TypeInfo *GetBool()
{
return typeBool;
}
TypeInfo *GetString()
{
return typeString;
}
TypeInfo *GetFunction()
{
return typeFunction;
}
TypeInfo *GetStruct()
{
return typeStruct;
}
DynArray<BaseType *> allTypes;
BaseType *intType, *doubleType, *stringType, *boolType, *anyType, *nullType;
TypeInfo *ResolveTypePath(const String &fullName)
{
for (auto *t : allTypes)
{
if (t->name == fullName)
return t;
}
return nullptr; // 没找到该类型
}
TypeInfo *ResolveTypePath(const DynArray<String> &path)
{
// TODO: 支持Module 系统, 查 Module 的导出表
String fullName = path.empty() ? "" : path[0];
for (size_t i = 1; i < path.size(); ++i)
{
fullName += "." + path[i];
}
return ResolveTypePath(fullName);
}
~TypeContext()
{
for (TypeInfo *t : allTypes)
delete t;
}
TypeContext()
{
typeAny = createBuiltin(TypeTag::Any, "Any");
typeNull = createBuiltin(TypeTag::Null, "Null");
typeInt = createBuiltin(TypeTag::Int, "Int");
typeDouble = createBuiltin(TypeTag::Double, "Double");
typeBool = createBuiltin(TypeTag::Bool, "Bool");
typeString = createBuiltin(TypeTag::String, "String");
typeFunction = createBuiltin(TypeTag::Function, "Function");
typeStruct = createBuiltin(TypeTag::Struct, "Struct");
}
private:
TypeInfo *createBuiltin(TypeTag tag, String name)
{
TypeInfo *t = new TypeInfo{tag, std::move(name)};
allTypes.push_back(t);
return t;
}
TypeContext();
~TypeContext();
Type GetBasic(TypeTag tag, bool nullable = false);
Type CreateFuncType(DynArray<Type> params, Type ret);
};
}; // namespace Fig
} // namespace Fig

View File

@@ -36,7 +36,7 @@ namespace Fig
~Arena()
{
// 1. 逆序调用析构函数
// 逆序调用析构函数
DestructorNode *node = destructorHead;
while (node)
{
@@ -44,7 +44,7 @@ namespace Fig
node = node->next;
}
// 2. 释放所有分配的内存块
// 释放所有分配的内存块
for (char *chunk : chunks)
{
delete[] chunk;

View File

@@ -1,13 +1,11 @@
/*!
@file src/VM/VM.cpp
@brief 虚拟机核心执行引擎实现
@author PuqiAR (im@puqiar.top)
@date 2026-02-19
*/
#include <Core/Core.hpp>
#include <VM/VM.hpp>
// Computed GOTO!!!
#define BINARY_ARITHMETIC_OP(opName, op) \
do_##opName: \
{ \
@@ -83,11 +81,11 @@ namespace Fig
Result<Value, Error> VM::Execute(CompiledModule *compiledModule)
{
Proto *entry = compiledModule->protos[0];
pushFrame(entry, registers);
(void) pushFrame(entry, registers); // 刚开始执行寄存器不会溢出
// 🔥 必须与 Bytecode.hpp 中的 OpCode 枚举严格一一对应!
static const void *dispatchTable[] = {
&&do_Exit,
// 对齐 Bytecode.hpp 中的 OpCode 顺序
static const void *dispatchTable[] = {&&do_Exit,
&&do_Exit_MaxRecursionDepthExceeded,
&&do_LoadK,
&&do_LoadTrue,
@@ -123,11 +121,17 @@ namespace Fig
&&do_Less,
&&do_GreaterEqual,
&&do_LessEqual,
&&do_GetGlobal,
&&do_SetGlobal,
&&do_GetUpval,
&&do_SetUpval,
&&do_Copy,
&&do_Count};
Instruction inst;
// 取指 -> 直接查表并 Jump
#define DISPATCH() \
do \
{ \
@@ -139,7 +143,15 @@ namespace Fig
DISPATCH();
do_Exit: {
[[unlikely]] return Value::GetNullInstance();
return Value::FromInt(decodeSBx(inst));
}
do_Exit_MaxRecursionDepthExceeded: {
CoreIO::GetStdErr() << std::format(
"Oops! max recursion depth limit {} exceeded in Fn `{}` , exiting...\n",
MAX_RECURSION_DEPTH,
(currentFrame - 1)->proto->name); // pushFrame失败了但currentFrame仍然移动所以 (currentFrame - 1)是 lastFrame
std::exit(static_cast<int>(MAX_RECURSION_DEPTH));
}
do_LoadK: {
@@ -171,7 +183,9 @@ namespace Fig
std::uint8_t a = decodeA(inst);
Proto *proto = compiledModule->protos[a];
std::uint8_t baseReg = decodeB(inst);
pushFrame(proto, currentFrame->registerBase + baseReg);
currentFrame->ip = pushFrame(proto, currentFrame->registerBase + baseReg);
DISPATCH();
}
@@ -181,16 +195,18 @@ namespace Fig
}
do_Return: {
std::uint8_t a = decodeA(inst);
*currentFrame->registerBase = currentFrame->registerBase[a];
std::uint8_t a = decodeA(inst);
Value retVal = currentFrame->registerBase[a];
// 此时 registerBase[0] 指向的是 Caller 的 baseReg 槽位
currentFrame->registerBase[0] = retVal;
popFrame();
DISPATCH();
}
do_LoadFn: {
// std::uint8_t a = decodeA(inst);
// std::uint16_t bx = decodeBx(inst);
// TODO: R[a] = new FunctionObject(compiledModule->protos[bx])
DISPATCH();
}
@@ -272,7 +288,8 @@ namespace Fig
Value l = currentFrame->registerBase[b];
Value r = currentFrame->registerBase[c];
currentFrame->registerBase[a] = Value::FromDouble(l.AsInt() + r.AsInt());
currentFrame->registerBase[a] =
Value::FromDouble(static_cast<double>(l.AsInt()) / r.AsInt());
DISPATCH();
}
@@ -283,10 +300,40 @@ namespace Fig
BINARY_COMPARE_OP(GreaterEqual, >=);
BINARY_COMPARE_OP(LessEqual, <=);
do_GetGlobal: {
std::uint8_t a = decodeA(inst);
std::uint16_t bx = decodeBx(inst);
currentFrame->registerBase[a] = globals[bx];
DISPATCH();
}
do_SetGlobal: {
std::uint8_t a = decodeA(inst);
std::uint16_t bx = decodeBx(inst);
globals[bx] = currentFrame->registerBase[a];
DISPATCH();
}
do_GetUpval: {
assert(false && "VM: GetUpval requires FunctionObject (Closure) implementation");
DISPATCH();
}
do_SetUpval: {
assert(false && "VM: SetUpval requires FunctionObject (Closure) implementation");
DISPATCH();
}
do_Copy: {
std::uint8_t a = decodeA(inst);
std::uint8_t b = decodeB(inst);
currentFrame->registerBase[a] = currentFrame->registerBase[b];
DISPATCH();
}
do_Count: {
assert(false && "Hit Count sentinel!");
return Value::GetNullInstance();
}
}
}; // namespace Fig
}; // namespace Fig

View File

@@ -31,13 +31,20 @@ namespace Fig
class VM
{
private:
static constexpr unsigned int MAX_REGISTERS = 1024;
static constexpr unsigned int MAX_REGISTERS = 1024;
static constexpr unsigned int MAX_GLOBALS = 65536;
static constexpr unsigned int MAX_RECURSION_DEPTH = 2233;
Instruction POISON_MAX_RECURSION_DEPTH_EXCEED_INST;
// 一次性分配
Value registers[MAX_REGISTERS];
Value globals[MAX_GLOBALS];
DynArray<CallFrame> frames;
CallFrame frames[MAX_RECURSION_DEPTH];
CallFrame *currentFrame;
CallFrame *frameLimit;
public:
VM()
{
@@ -45,27 +52,36 @@ namespace Fig
{
registers[i] = Value::GetNullInstance();
}
for (unsigned int i = 0; i < MAX_GLOBALS; ++i)
{
globals[i] = Value::GetNullInstance();
}
currentFrame = frames;
frameLimit = frames + MAX_RECURSION_DEPTH - 1;
POISON_MAX_RECURSION_DEPTH_EXCEED_INST =
Op::iAsBx(OpCode::Exit_MaxRecursionDepthExceeded, 0, 0);
}
private:
void pushFrame(Proto *proto, Value *base)
[[nodiscard]]
inline Instruction *pushFrame(Proto *proto, Value *base)
{
frames.push_back({
proto,
proto->code.data(),
base
});
currentFrame = &frames.back();
if (++currentFrame >= frameLimit) [[unlikely]] // 达到最大递归层数
{
POISON_MAX_RECURSION_DEPTH_EXCEED_INST =
Op::iAsBx(OpCode::Exit_MaxRecursionDepthExceeded, 0, 0);
return &POISON_MAX_RECURSION_DEPTH_EXCEED_INST;
}
*currentFrame = CallFrame{proto, proto->code.data(), base};
return currentFrame->ip;
}
void popFrame()
inline void popFrame()
{
frames.pop_back();
if (!frames.empty())
{
currentFrame = &frames.back();
}
--currentFrame;
}
inline OpCode decodeOpCode(Instruction inst)

View File

@@ -1,3 +1,4 @@
#include <Bytecode/Disassembler.hpp>
#include <Compiler/Compiler.hpp>
#include <Core/Core.hpp>
#include <Deps/Deps.hpp>
@@ -7,12 +8,10 @@
#include <SourceManager/SourceManager.hpp>
#include <VM/VM.hpp>
#include <chrono>
#include <iostream>
#include <print>
int main()
{
using namespace Fig;
@@ -25,68 +24,53 @@ int main()
if (!manager.read)
{
std::cerr << "Couldn't read file";
std::cerr << "CRITICAL: Could not read source file: " << filePath << "\n";
return 1;
}
Lexer lexer(manager.GetSource(), fileName);
Parser parser(lexer, manager, fileName);
const auto &program_result = parser.Parse();
if (!program_result)
auto pRes = parser.Parse();
if (!pRes)
{
ReportError(program_result.error(), manager);
ReportError(pRes.error(), manager);
return 1;
}
Program *program = *program_result;
Program *program = *pRes;
Analyzer analyzer(manager);
const auto &analyzeResult = analyzer.Analyze(program);
if (!analyzeResult)
Analyzer analyzer(manager);
auto aRes = analyzer.Analyze(program);
if (!aRes)
{
ReportError(analyzeResult.error(), manager);
ReportError(aRes.error(), manager);
return 1;
}
std::cout << "analyzer: Program OK, PASSED\n";
std::cout << "Analyzer: Program OK\n";
Compiler compiler(fileName, manager);
const auto &comp_result = compiler.Compile(program);
if (!comp_result)
Diagnostics diag;
Compiler compiler(manager, diag);
auto cRes = compiler.Compile(program);
if (!cRes)
{
ReportError(comp_result.error(), manager);
ReportError(cRes.error(), manager);
return 1;
}
CompiledModule *compiledModule = *comp_result;
size_t cnt = 0;
for (Proto *proto : compiledModule->protos)
{
std::cout << "\n"
<< "Proto: " << cnt++ << '\n';
std::cout << " Constant Pool" << '\n';
for (size_t i = 0; i < proto->constants.size(); ++i)
{
std::print("[{}] {}\n", i, proto->constants[i].ToString());
}
CompiledModule *compiledModule = *cRes;
DumpCode(proto->code);
Disassembler::DisassembleModule(compiledModule);
std::cout << "\nMax Stack Size: " << (int) proto->maxStack << std::endl;
}
VM vm;
using Clock = std::chrono::high_resolution_clock;
Clock clock;
auto start = clock.now();
std::cout << "\n--- VM Execution Start ---\n";
auto start = clock.now();
auto result_ = vm.Execute(compiledModule);
auto end = clock.now();
auto end = clock.now();
auto duration = end - start;
auto duration = std::chrono::duration_cast<std::chrono::milliseconds>(end - start);
if (!result_)
{
@@ -94,9 +78,9 @@ int main()
return 1;
}
Value result = *result_;
std::cout << "result: " << result.ToString() << "\n";
std::cout << "execution cost: " << std::chrono::duration_cast<std::chrono::milliseconds>(duration).count() << "ms\n";
std::cout << "Result: " << (*result_).ToString() << "\n";
std::cout << "Execution Cost: " << duration.count() << "ms\n";
vm.PrintRegisters();
}
return 0;
}

View 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);
}

View File

@@ -0,0 +1,3 @@
func main() {
break; // 错误break 不在循环内
}

View File

@@ -0,0 +1,4 @@
func main() {
var x = 10;
var x = 20; // 错误x 重复定义
}

View File

@@ -0,0 +1,4 @@
struct Point { x: Int, y: Int }
func main() {
var p = new Point{ x: 1, z: 2 }; // 错误Point 没有字段 z
}

View File

@@ -0,0 +1,4 @@
func main() {
var x = 10;
io.println(y); // 错误y 未定义
}

View File

@@ -13,11 +13,6 @@ elseif is_plat("windows") then
-- 2. local dev (Windows + llvm-mingw)
set_toolchains("mingw") -- llvm-mingw
add_ldflags("-Wl,--stack,268435456")
-- set_toolchains("clang")
-- static lib
-- add_ldflags("-target x86_64-w64-mingw32", "-static")
-- add_cxxflags("-stdlib=libc++")
-- add_ldflags("-stdlib=libc++")
end
set_languages("c++23")
@@ -33,7 +28,6 @@ target("LexerTest")
add_files("src/Token/Token.cpp")
add_files("src/Error/Error.cpp")
add_files("src/Lexer/Lexer.cpp")
add_files("src/Lexer/LexerTest.cpp")
target("ParserTest")
@@ -41,13 +35,11 @@ target("ParserTest")
add_files("src/Token/Token.cpp")
add_files("src/Error/Error.cpp")
add_files("src/Lexer/Lexer.cpp")
add_files("src/Ast/Operator.cpp")
add_files("src/Parser/ExprParser.cpp")
add_files("src/Parser/StmtParser.cpp")
add_files("src/Parser/TypeExprParser.cpp")
add_files("src/Parser/Parser.cpp")
add_files("src/Parser/ParserTest.cpp")
target("ObjectTest")
@@ -59,13 +51,12 @@ target("AnalyzerTest")
add_files("src/Token/Token.cpp")
add_files("src/Error/Error.cpp")
add_files("src/Lexer/Lexer.cpp")
add_files("src/Ast/Operator.cpp")
add_files("src/Parser/ExprParser.cpp")
add_files("src/Parser/StmtParser.cpp")
add_files("src/Parser/TypeExprParser.cpp")
add_files("src/Parser/Parser.cpp")
add_files("src/Sema/Type.cpp")
add_files("src/Sema/Analyzer.cpp")
add_files("src/Sema/AnalyzerTest.cpp")
@@ -74,21 +65,18 @@ target("CompilerTest")
add_files("src/Token/Token.cpp")
add_files("src/Error/Error.cpp")
add_files("src/Lexer/Lexer.cpp")
add_files("src/Ast/Operator.cpp")
add_files("src/Bytecode/Disassembler.cpp")
add_files("src/Parser/ExprParser.cpp")
add_files("src/Parser/StmtParser.cpp")
add_files("src/Parser/TypeExprParser.cpp")
add_files("src/Parser/Parser.cpp")
add_files("src/Object/Object.cpp")
add_files("src/Sema/Type.cpp")
add_files("src/Sema/Analyzer.cpp")
add_files("src/Compiler/ExprCompiler.cpp")
add_files("src/Compiler/StmtCompiler.cpp")
add_files("src/Compiler/Compiler.cpp")
add_files("src/Compiler/CompileTest.cpp")
target("LSP")
@@ -96,17 +84,14 @@ target("LSP")
add_files("src/Token/Token.cpp")
add_files("src/Error/Error.cpp")
add_files("src/Lexer/Lexer.cpp")
add_files("src/Ast/Operator.cpp")
add_files("src/Parser/ExprParser.cpp")
add_files("src/Parser/StmtParser.cpp")
add_files("src/Parser/TypeExprParser.cpp")
add_files("src/Parser/Parser.cpp")
add_files("src/Sema/Type.cpp")
add_files("src/Sema/Analyzer.cpp")
add_files("src/LSP/LSPServer.cpp")
set_filename("Fig-LSP")
target("Fig")
@@ -114,20 +99,17 @@ target("Fig")
add_files("src/Token/Token.cpp")
add_files("src/Error/Error.cpp")
add_files("src/Lexer/Lexer.cpp")
add_files("src/Ast/Operator.cpp")
add_files("src/Bytecode/Disassembler.cpp")
add_files("src/Parser/ExprParser.cpp")
add_files("src/Parser/StmtParser.cpp")
add_files("src/Parser/TypeExprParser.cpp")
add_files("src/Parser/Parser.cpp")
add_files("src/Object/Object.cpp")
add_files("src/Sema/Type.cpp")
add_files("src/Sema/Analyzer.cpp")
add_files("src/Compiler/ExprCompiler.cpp")
add_files("src/Compiler/StmtCompiler.cpp")
add_files("src/Compiler/Compiler.cpp")
add_files("src/VM/VM.cpp")
add_files("src/main.cpp")
add_files("src/main.cpp")