Made some preparations to refactor semantic analysis and type system

This commit is contained in:
2026-07-21 22:52:17 +08:00
parent 0f5304001c
commit 9f7fe79a2e
15 changed files with 116 additions and 2173 deletions

View File

@@ -1,67 +0,0 @@
#include <Parser/Parser.hpp>
#include <Sema/Analyzer.hpp>
#include <Compiler/Compiler.hpp>
#include <Bytecode/Disassembler.hpp>
#include <iostream>
#include <filesystem>
int main()
{
using namespace Fig;
String filePath = "T:/Files/Maker/Code/MyCodingLanguage/The Fig Project/Fig/tests/Compiler/test_basic.fig";
if (!std::filesystem::exists(filePath.toStdString()))
{
std::cerr << "CRITICAL: Test file not found at: " << filePath << "\n";
return 1;
}
SourceManager sm{filePath};
String source = sm.Read();
if (!sm.read || source.length() == 0)
{
std::cerr << "CRITICAL: SourceManager failed to read: " << filePath << "\n";
return 1;
}
Lexer lexer(source, filePath);
Diagnostics diagnostics;
Parser parser(lexer, sm, filePath, diagnostics);
diagnostics.EmitAll(sm);
auto pRes = parser.Parse();
if (!pRes)
{
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,142 +0,0 @@
/*!
@file src/Compiler/Compiler.cpp
@brief 编译器主逻辑实现:物理 Bootstrapper 与双步扫描
*/
#include <Ast/Stmt/FnDefStmt.hpp>
#include <Compiler/Compiler.hpp>
namespace Fig
{
Result<CompiledModule *, Error> Compiler::Compile(Program *program)
{
module = new CompiledModule();
if (program->nodes.empty())
{
return module;
}
// 预留 Protos[0] 给 Bootstrapper
Proto *bootProto = new Proto();
bootProto->name = "[bootstrapper]";
module->protos.push_back(bootProto);
int initIdx = -1;
int mainIdx = -1;
SourceLocation *mainFnLoc = nullptr;
SourceLocation *initFnLoc = nullptr;
// 预扫描顶层函数
for (auto *stmt : program->nodes)
{
if (stmt->type == AstType::FnDefStmt)
{
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;
f->protoIndex = idx;
module->protos.push_back(p);
// 连接物理符号到索引
if (f->resolvedSymbol)
{
f->resolvedSymbol->index = idx;
}
if (f->name == "init")
{
initIdx = idx;
initFnLoc = &stmt->location;
}
if (f->name == "main")
{
mainIdx = idx;
mainFnLoc = &stmt->location;
}
}
}
// Bootstrapper 中编译所有语句
FuncState bootState(bootProto, nullptr);
current = &bootState;
for (auto *stmt : program->nodes)
{
auto res = compileStmt(stmt);
if (!res)
{
return std::unexpected(res.error());
}
}
// 发射 Bootstrapper 引导指令
if (initIdx != -1)
{
emit(Op::iABC(OpCode::FastCall, (uint8_t) initIdx, 0, 0), initFnLoc);
}
if (mainIdx != -1)
{
emit(Op::iABC(OpCode::FastCall, (uint8_t) mainIdx, 0, 0), mainFnLoc);
}
emit(Op::iAsBx(OpCode::Exit, 0, 0), &program->nodes.back()->location);
return module;
}
int Compiler::getGlobalID(const String &name)
{
if (globalIDMap.contains(name))
return globalIDMap[name];
int id = (int) globalIDMap.size();
globalIDMap[name] = id;
return id;
}
Result<Register, Error> Compiler::allocateReg(const SourceLocation &loc)
{
if (current->freereg >= MAX_REGISTERS)
{
return std::unexpected(
Error(ErrorType::RegisterOverflow, "too many registers", "", loc));
}
Register reg = current->freereg++;
if (reg >= current->proto->maxRegisters)
{
current->proto->maxRegisters = reg + 1;
}
return reg;
}
void Compiler::freeReg(Register count)
{
if (current->freereg >= count)
{
current->freereg -= count;
}
}
int Compiler::addConstant(Value val)
{
if (current->constantMap.contains(val))
return current->constantMap[val];
int idx = (int) current->proto->constants.size();
current->proto->constants.push_back(val);
current->constantMap[val] = idx;
return idx;
}
void Compiler::emit(Instruction inst, SourceLocation *loc)
{
current->proto->code.push_back(inst);
current->proto->locations.push_back(loc);
}
} // namespace Fig

View File

@@ -50,6 +50,15 @@ namespace Fig
public:
Compiler(SourceManager &m, Diagnostics &d) : manager(m), diag(d) {}
Result<CompiledModule *, Error> Compile(Program *program);
Result<CompiledModule *, Error> Compile(Program *)
{
auto *mod = new CompiledModule();
auto *boot = new Proto();
boot->name = "[bootstrapper]";
boot->maxRegisters = 1;
boot->code.push_back(Op::iAsBx(OpCode::Exit, 0, 0));
mod->protos.push_back(boot);
return mod;
}
};
}

View File

@@ -1,477 +0,0 @@
/*!
@file src/Compiler/ExprCompiler.cpp
@brief 表达式编译
*/
#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
{
static Result<Value, Error> parsePhysicalNumber(const String &raw, const SourceLocation &loc)
{
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 (j == 0 && (c == '.' || c == 'e' || c == 'E'))
return std::unexpected(
Error(ErrorType::SyntaxError, "unexpected leading character", "", loc));
if (c == '.' || c == 'e' || c == 'E')
isFloat = true;
buffer[j++] = (char) c;
}
buffer[j] = '\0';
// 检查16进制/2进制前缀
bool isHexOrBin = false;
int base = 10;
const char *start = buffer;
if (j >= 2 && buffer[0] == '0')
{
if (buffer[1] == 'x' || buffer[1] == 'X')
{
base = 16;
start += 2;
isHexOrBin = true;
}
else if (buffer[1] == 'b' || buffer[1] == 'B')
{
base = 2;
start += 2;
isHexOrBin = true;
}
}
if (isFloat)
{
// 如果既有浮点标记又是0x开头可能是16进制浮点
auto fmt =
(isHexOrBin && base == 16) ? std::chars_format::hex : std::chars_format::general;
double dVal;
auto [ptr, ec] = std::from_chars(start, buffer + j, dVal, fmt);
if (ec != std::errc() || ptr != buffer + j)
return std::unexpected(
Error(ErrorType::SyntaxError, "invalid float literal", "", loc));
return Value::FromDouble(dVal);
}
else if (isHexOrBin)
{
// 16进制或2进制整数
int64_t iVal;
auto [ptr, ec] = std::from_chars(start, buffer + j, iVal, base);
if (ec != std::errc() || ptr != buffer + j)
return std::unexpected(
Error(ErrorType::SyntaxError, "integer overflow or invalid literal", "", 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
{
return Value::FromDouble(static_cast<double>(iVal));
}
}
else
{
// 10进制数字可能是整数或浮点数
double dVal;
auto [ptr, ec] = std::from_chars(start, buffer + j, dVal, std::chars_format::general);
if (ec != std::errc() || ptr != buffer + j)
return std::unexpected(
Error(ErrorType::SyntaxError, "invalid number literal", "", loc));
// 检查是否是整数(没有小数部分且不超出int32范围)
if (dVal == std::floor(dVal) && dVal >= std::numeric_limits<int32_t>::min()
&& dVal <= std::numeric_limits<int32_t>::max())
{
return Value::FromInt(static_cast<int32_t>(dVal));
}
else
{
return Value::FromDouble(dVal);
}
}
}
Result<Register, Error> Compiler::compileExpr(Expr *expr, Register target)
{
if (expr == nullptr)
{
return std::unexpected(
Error(ErrorType::InternalError, "null expr in compiler", "", {}));
}
switch (expr->type)
{
case AstType::LiteralExpr: {
auto *l = static_cast<LiteralExpr *>(expr);
Register r = (target == NO_REG) ? *allocateReg(l->location) : target;
const Token &tok = l->literal;
if (tok.type == TokenType::LiteralNumber)
{
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))),
&l->location);
}
else if (tok.type == TokenType::LiteralString)
{
int kIdx = addConstant(Value::GetNullInstance()); // TODO: String 支持
emit(Op::iABx(OpCode::LoadK, r, static_cast<uint16_t>(kIdx)), &l->location);
}
else if (tok.type == TokenType::LiteralNull)
{
emit(Op::iABC(OpCode::LoadNull, r, 0, 0), &l->location);
}
else if (tok.type == TokenType::LiteralTrue)
{
emit(Op::iABC(OpCode::LoadTrue, r, 0, 0), &l->location);
}
else if (tok.type == TokenType::LiteralFalse)
{
emit(Op::iABC(OpCode::LoadFalse, r, 0, 0), &l->location);
}
return r;
}
case AstType::IdentiExpr: {
auto *i = static_cast<IdentiExpr *>(expr);
Symbol *sym = i->resolvedSymbol;
if (sym->location == SymbolLocation::Local)
{
// no-copy for temp eval
if (target == NO_REG)
return static_cast<Register>(sym->index);
// 仅在被强制指定目标(如参数装填)时发射搬运指令
if (target != sym->index)
{
emit(
Op::iABx(OpCode::Mov, target, static_cast<uint16_t>(sym->index)),
&i->location);
}
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),
&i->location);
}
else if (sym->location == SymbolLocation::Global)
{
int gId = getGlobalID(i->name);
emit(Op::iABx(OpCode::GetGlobal, r, static_cast<uint16_t>(gId)), &i->location);
}
return r;
}
case AstType::CallExpr: {
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());
}
bool isGlobalFastCall = false;
if (c->callee->type == AstType::IdentiExpr)
{
auto *id = static_cast<IdentiExpr *>(c->callee);
// 只有在全局区的函数,才能使用 FastCall
if (id->resolvedSymbol->location == SymbolLocation::Global)
{
isGlobalFastCall = true;
int protoIdx = id->resolvedSymbol->index;
emit(
Op::iABC(
OpCode::FastCall,
static_cast<uint8_t>(protoIdx),
baseReg,
static_cast<uint8_t>(c->args.args.size())),
&c->location);
}
}
if (!isGlobalFastCall)
{
// 动态闭包调用
// 先获取闭包对象所在的物理寄存器
auto r_fn = compileExpr(c->callee);
if (!r_fn)
return std::unexpected(r_fn.error());
// 使用动态 Call 指令RA 是指向堆闭包的寄存器
emit(
Op::iABC(
OpCode::Call,
*r_fn,
baseReg,
static_cast<uint8_t>(c->args.args.size())),
&c->location);
}
// free arg temps
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), &c->location);
}
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),
&lid->location);
}
else if (sym->location == SymbolLocation::Upvalue)
{
emit(
Op::iABC(
OpCode::SetUpval, *r_val, static_cast<Register>(sym->index), 0),
&lid->location);
}
else
{
emit(
Op::iABx(
OpCode::SetGlobal,
*r_val,
static_cast<uint16_t>(getGlobalID(lid->name))),
&lid->location);
}
}
return r_val;
}
Register mark = current->freereg; // mark
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), &in->location);
return r_d;
}
case AstType::LambdaExpr: {
auto l = static_cast<LambdaExpr *>(expr);
Proto *proto = new Proto;
proto->name = l->toString();
FuncState fs(proto, current);
FuncState *old = current;
current = &fs;
if (l->isExprBody)
{
auto result = compileExpr(static_cast<Expr *>(l->body));
if (!result)
{
return result;
}
emit(Op::iABC(OpCode::Return, *result, 0, 0), &l->location);
}
else
{
auto result = compileStmt(static_cast<BlockStmt *>(l->body));
if (!result)
{
return std::unexpected(result.error());
}
auto _r = allocateReg(l->body->location);
if (!_r)
{
return _r;
}
Register r = *_r;
emit(Op::iABC(OpCode::LoadNull, r, 0, 0), &l->body->location);
emit(Op::iABC(OpCode::Return, r, 0, 0), &l->body->location);
}
int protoIndex = (int) module->protos.size();
module->protos.push_back(proto);
current = old;
if (target == NO_REG)
{
auto _r = allocateReg(expr->location);
if (!_r)
{
return _r;
}
emit(Op::iABx(OpCode::LoadFn, *_r, protoIndex), &l->body->location);
return *_r;
}
else
{
emit(Op::iABx(OpCode::LoadFn, target, protoIndex), &l->body->location);
}
return target;
}
default: break;
}
return std::unexpected(
Error(ErrorType::InternalError, "unsupported expr", "", expr->location));
}
} // namespace Fig

View File

@@ -1,269 +0,0 @@
/*!
@file src/Compiler/StmtCompiler.cpp
@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::compileStmt(Stmt *stmt)
{
if (stmt == nullptr)
{
return {};
}
switch (stmt->type)
{
case AstType::BlockStmt: {
auto *b = static_cast<BlockStmt *>(stmt);
for (auto *n : b->nodes)
{
auto res = compileStmt(n);
if (!res)
return res;
}
break;
}
case AstType::VarDecl: {
auto *v = static_cast<VarDecl *>(stmt);
if (current->enclosing == nullptr) // 处理全局变量
{
Register mark = current->freereg; // mark
auto regRes = compileExpr(v->initExpr);
if (!regRes)
return std::unexpected(regRes.error());
emit(Op::iABx(OpCode::SetGlobal,
*regRes,
static_cast<uint16_t>(getGlobalID(v->name))),
&v->location);
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());
}
}
auto regRes = compileExpr(v->initExpr, targetReg);
if (!regRes)
return std::unexpected(regRes.error());
}
break;
}
case AstType::FnDefStmt: {
auto *f = static_cast<FnDefStmt *>(stmt);
if (f->protoIndex == -1) // 闭包环境没有被扫到
{
Proto *newProto = new Proto();
newProto->name = f->name;
newProto->numParams = static_cast<uint8_t>(f->params.size());
newProto->maxRegisters = newProto->numParams; // sync
f->protoIndex = static_cast<int>(module->protos.size());
module->protos.push_back(newProto);
}
// 获取静态原型 (flat protos)
Proto *p = module->protos[f->protoIndex];
p->upvalues = f->upvalues;
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), &f->location);
}
current = old;
// 如果是局部闭包,在当前栈帧分配寄存器并生成 LoadFn
if (f->resolvedSymbol->location == SymbolLocation::Local)
{
Register targetReg = static_cast<Register>(f->resolvedSymbol->index);
while (current->freereg <= targetReg)
{
auto allocRes = allocateReg(f->location);
if (!allocRes)
return std::unexpected(allocRes.error());
}
// 生成 LoadFn: RA = 目标寄存器, Bx = Proto 在 module->protos 中的绝对索引
emit(Op::iABx(OpCode::LoadFn, targetReg, static_cast<uint16_t>(f->protoIndex)),
&f->location);
}
else if (f->resolvedSymbol->location == SymbolLocation::Global)
{
auto result = allocateReg(f->location);
if (!result)
{
return std::unexpected(result.error());
}
Register r = *result;
emit(Op::iABx(OpCode::LoadFn, r, static_cast<uint16_t>(f->protoIndex)),
&f->location);
int gId = getGlobalID(f->name);
emit(Op::iABx(OpCode::SetGlobal, r, static_cast<std::uint16_t>(gId)),
&f->location);
freeReg();
}
break;
}
case AstType::IfStmt: {
auto *i = static_cast<IfStmt *>(stmt);
DynArray<int> exitJumps;
Register mark = current->freereg; // mark
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), &i->location);
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), &i->location);
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), &elif->location);
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), &elif->location);
int target = static_cast<int>(current->proto->code.size());
current->proto->code.resize(nextElif);
current->proto->code[nextElif] = Op::iAsBx(
OpCode::JmpIfFalse, *ec, static_cast<int16_t>(target - nextElif - 1));
current->proto->locations.resize(nextElif);
current->proto->locations[nextElif] = &elif->location;
}
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; // mark
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), &w->location);
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)),
&w->location);
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; // mark
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), &rs->location);
retReg = *r;
}
emit(Op::iABC(OpCode::Return, retReg, 0, 0), &rs->location);
current->freereg = mark; // 回收返回值计算的占用
break;
}
case AstType::ExprStmt: {
Register mark = current->freereg; // mark
auto reg = compileExpr(static_cast<ExprStmt *>(stmt)->expr);
if (!reg)
return std::unexpected(reg.error());
current->freereg = mark; // 彻底抛弃孤立表达式的副作用
break;
}
default: break;
}
return {};
}
} // namespace Fig

View File

@@ -1,19 +0,0 @@
#include <LSP/LSPServer.hpp>
#ifdef _WIN32
#include <fcntl.h>
#include <io.h>
#endif
int main()
{
#ifdef _WIN32
_setmode(_fileno(stdin), _O_BINARY);
_setmode(_fileno(stdout), _O_BINARY);
#endif
Fig::LspServer server;
server.Run();
return 0;
}

View File

@@ -196,6 +196,7 @@ namespace Fig
Function,
Struct,
Instance,
TypeObj,
};
struct StructObject /* : public Object */; // 结构体基类的定义,前向声明
@@ -235,6 +236,37 @@ namespace Fig
{
return type == ObjectType::Instance;
}
constexpr bool isTypeObj() const
{
return type == ObjectType::TypeObj;
}
};
enum class TypeTag : uint8_t
{
Null,
Int,
Double,
String,
Bool,
Any,
Type,
Function,
Struct,
Interface,
};
struct TypeObject : Object
{
String name;
TypeTag tag;
TypeObject(String _name, TypeTag _t) : name(std::move(_name)), tag(_t)
{
type = ObjectType::TypeObj;
klass = nullptr; // TypeObject 自身的 klass 指向 TypeTypeObject初始化后设置
}
};
} // namespace Fig

View File

@@ -9,6 +9,7 @@
#include <Ast/Operator.hpp>
#include <Object/ObjectBase.hpp>
#include <Sema/Type.hpp>
namespace Fig
{
@@ -23,33 +24,29 @@ namespace Fig
// + 6 bytes padding
};
*/
struct FieldMeta
{
String name;
Type type;
};
struct StructObject final : public Object
{
String name; // 元信息(仅供调试/打印/反射)
// 内存布局信息
String name;
std::uint8_t fieldCount;
FieldMeta *fields; // [fieldCount]
Object *operators[GetOperatorsSize()];
/*
运算符重载nullptr代表无重载
一般为 NativeFunction / Function
排列:
[unary operators ]( binary operators]
0 - UnaryOperators::Count BinaryOperators::Count
*/
// operators: [UnaryOp 0..N][BinaryOp 0..N], nullptr = 无重载
Object *GetUnaryOperator(UnaryOperator _op)
{
std::uint8_t idx = static_cast<std::uint8_t>(_op);
return operators[idx];
return operators[static_cast<std::uint8_t>(_op)];
}
Object *GetBinaryOperator(BinaryOperator _op)
{
std::uint16_t idx = static_cast<std::uint8_t>(UnaryOperator::Count) + static_cast<std::uint8_t>(_op);
return operators[idx];
return operators[static_cast<std::uint8_t>(UnaryOperator::Count)
+ static_cast<std::uint8_t>(_op)];
}
};
}; // namespace Fig

View File

@@ -1,752 +0,0 @@
/*!
@file src/Sema/Analyzer.cpp
@brief 语义分析器实现:实装强类型校验 (Call, Infix, Member, Return, Assign)
*/
#include <Ast/Ast.hpp>
#include <Ast/Expr/MemberExpr.hpp>
#include <Ast/Stmt/ImplStmt.hpp>
#include <Ast/Stmt/InterfaceDefStmt.hpp>
#include <Ast/Stmt/StructDefStmt.hpp>
#include <Sema/Analyzer.hpp>
namespace Fig
{
struct AnalyzerState
{
int loopDepth = 0;
FnDefStmt *currentFn = nullptr;
} state;
struct ScopeGuard
{
Environment &env;
ScopeGuard(Environment &e, bool isFn) : env(e)
{
env.Push(isFn);
}
~ScopeGuard()
{
env.Pop();
}
};
struct LoopGuard
{
int &depth;
LoopGuard(int &d) : depth(d)
{
depth++;
}
~LoopGuard()
{
depth--;
}
};
struct FnStateGuard
{
FnDefStmt *&current;
FnDefStmt *old;
FnStateGuard(FnDefStmt *&c, FnDefStmt *n) : current(c), old(c)
{
current = n;
}
~FnStateGuard()
{
current = old;
}
};
Result<void, Error> Analyzer::Analyze(Program *prog)
{
ScopeGuard guard(env, false);
auto r1 = pass1(prog);
if (!r1)
return r1;
auto r2 = resolveTypes(prog);
if (!r2)
return r2;
auto r3 = checkBodies(prog);
if (!r3)
return r3;
return {};
}
Result<void, Error> Analyzer::pass1(Program *prog)
{
for (auto *stmt : prog->nodes)
{
if (stmt->type == AstType::StructDefStmt)
{
auto *s = static_cast<StructDefStmt *>(stmt);
if (globalTypes.contains(s->name))
{
return std::unexpected(
Error(ErrorType::RedeclarationError, "type redeclared", "", s->location));
}
auto *t = arena.Allocate<StructType>(s->name);
typeCtx.allTypes.push_back(t);
globalTypes[s->name] = t;
}
else if (stmt->type == AstType::FnDefStmt)
{
auto *f = static_cast<FnDefStmt *>(stmt);
if (f->name == "main")
{
hasMain = true;
}
if (globalSymbols.contains(f->name))
{
return std::unexpected(
Error(ErrorType::RedeclarationError, "func redeclared", "", f->location));
}
Symbol *sym =
arena.Allocate<Symbol>(f->name, Type{}, SymbolLocation::Global, 0, true);
globalSymbols[f->name] = sym;
env.current->locals[f->name] = sym;
f->resolvedSymbol = sym;
}
}
return {};
}
Result<void, Error> Analyzer::resolveTypes(Program *prog)
{
for (auto *stmt : prog->nodes)
{
if (stmt->type == AstType::StructDefStmt)
{
auto *s = static_cast<StructDefStmt *>(stmt);
auto *st = static_cast<StructType *>(globalTypes[s->name]);
for (auto &f : s->fields)
{
auto res = resolveTypeExpr(f.type);
if (!res)
{
return std::unexpected(res.error());
}
st->AddField(f.name, *res, f.isPublic);
}
}
else if (stmt->type == AstType::FnDefStmt)
{
auto *f = static_cast<FnDefStmt *>(stmt);
auto res = resolveTypeExpr(f->returnTypeSpecifier);
if (!res)
return std::unexpected(res.error());
f->resolvedReturnType = *res;
DynArray<Type> paramTypes;
for (auto *p : f->params)
{
auto pres = resolveTypeExpr(p->typeSpecifier);
if (!pres)
return std::unexpected(pres.error());
p->resolvedType = *pres;
paramTypes.push_back(*pres);
}
f->resolvedSymbol->type = typeCtx.CreateFuncType(std::move(paramTypes), *res);
}
}
return {};
}
Result<void, Error> Analyzer::checkBodies(Program *prog)
{
for (auto *stmt : prog->nodes)
{
auto r = analyzeStmt(stmt);
if (!r)
return r;
}
return {};
}
Result<void, Error> Analyzer::analyzeStmt(Stmt *stmt)
{
if (!stmt)
return {};
switch (stmt->type)
{
case AstType::BlockStmt: {
auto *b = static_cast<BlockStmt *>(stmt);
ScopeGuard guard(env, false);
for (auto *s : b->nodes)
{
if (auto r = analyzeStmt(s); !r)
return r;
}
break;
}
case AstType::VarDecl: {
auto *v = static_cast<VarDecl *>(stmt);
Type initT = typeCtx.GetBasic(TypeTag::Any);
if (v->initExpr)
{
auto res = analyzeExpr(v->initExpr);
if (!res)
return std::unexpected(res.error());
initT = *res;
}
Type declT = v->typeSpecifier ? *resolveTypeExpr(v->typeSpecifier) : initT;
// 赋值拦截
if (v->initExpr && !initT.isAssignableTo(declT))
{
return std::unexpected(Error(
ErrorType::TypeError,
"cannot assign '" + initT.toString() + "' to type '" + declT.toString()
+ "'",
"",
v->location));
}
if (env.current->locals.contains(v->name))
return std::unexpected(
Error(ErrorType::RedeclarationError, "var redeclared", "", v->location));
SymbolLocation loc =
env.current->parent ? SymbolLocation::Local : SymbolLocation::Global;
int idx = (loc == SymbolLocation::Local) ? env.current->nextLocalId++ : 0;
env.current->locals[v->name] =
arena.Allocate<Symbol>(v->name, declT, loc, idx, false);
v->localId = idx;
break;
}
case AstType::FnDefStmt: {
auto *f = static_cast<FnDefStmt *>(stmt);
// 局部闭包延迟类型推导
if (!f->resolvedSymbol) // 闭包?
{
SymbolLocation loc =
env.current->parent ? SymbolLocation::Local : SymbolLocation::Global;
int idx = (loc == SymbolLocation::Local) ? env.current->nextLocalId++ : 0;
Symbol *sym = arena.Allocate<Symbol>(f->name, Type{}, loc, idx, true);
f->resolvedSymbol = sym;
env.current->locals[f->name] = sym;
auto res = resolveTypeExpr(f->returnTypeSpecifier);
if (!res)
return std::unexpected(res.error());
f->resolvedReturnType = *res;
DynArray<Type> paramTypes;
for (auto *p : f->params)
{
auto pres = resolveTypeExpr(p->typeSpecifier);
if (!pres)
return std::unexpected(pres.error());
p->resolvedType = *pres;
paramTypes.push_back(*pres);
}
f->resolvedSymbol->type = typeCtx.CreateFuncType(std::move(paramTypes), *res);
}
FnStateGuard fnGuard(state.currentFn, f);
ScopeGuard scopeGuard(env, true);
for (auto *p : f->params)
{
env.current->locals[p->name] = arena.Allocate<Symbol>(
p->name,
p->resolvedType,
SymbolLocation::Local,
env.current->nextLocalId++,
false);
}
if (auto r = analyzeStmt(f->body); !r)
return r;
for (const auto &upval : env.current->upvalues)
{
f->upvalues.push_back({static_cast<std::uint8_t>(upval.index), upval.isLocal});
}
break;
}
case AstType::IfStmt: {
auto *i = static_cast<IfStmt *>(stmt);
if (auto c = analyzeExpr(i->cond); !c)
return std::unexpected(c.error());
else if (!c->isAssignableTo(typeCtx.GetBasic(TypeTag::Bool)))
{
return std::unexpected(Error(
ErrorType::TypeError, "condition must be Bool", "", i->cond->location));
}
if (auto b = analyzeStmt(i->consequent); !b)
return b;
for (auto *elif : i->elifs)
{
if (auto c = analyzeExpr(elif->cond); !c)
return std::unexpected(c.error());
else if (!c->isAssignableTo(typeCtx.GetBasic(TypeTag::Bool)))
{
return std::unexpected(Error(
ErrorType::TypeError,
"condition must be Bool",
"",
elif->cond->location));
}
if (auto b = analyzeStmt(elif->consequent); !b)
return b;
}
if (i->alternate)
{
if (auto a = analyzeStmt(i->alternate); !a)
return a;
}
break;
}
case AstType::WhileStmt: {
bool isWhile = stmt->type == AstType::WhileStmt;
Expr *cond = isWhile ? static_cast<WhileStmt *>(stmt)->cond :
static_cast<IfStmt *>(stmt)->cond;
Stmt *body = isWhile ? static_cast<WhileStmt *>(stmt)->body :
static_cast<IfStmt *>(stmt)->consequent;
if (auto c = analyzeExpr(cond); !c)
return std::unexpected(c.error());
else if (!c->isAssignableTo(typeCtx.GetBasic(TypeTag::Bool)))
{
return std::unexpected(
Error(ErrorType::TypeError, "condition must be Bool", "", cond->location));
}
if (isWhile)
{
LoopGuard loopGuard(state.loopDepth);
if (auto b = analyzeStmt(body); !b)
return b;
}
else
{
if (auto b = analyzeStmt(body); !b)
return b;
auto *i = static_cast<IfStmt *>(stmt);
if (i->alternate)
{
if (auto a = analyzeStmt(i->alternate); !a)
return a;
}
}
break;
}
case AstType::BreakStmt:
case AstType::ContinueStmt: {
if (state.loopDepth <= 0)
{
return std::unexpected(
Error(ErrorType::SyntaxError, "outside loop", "", stmt->location));
}
break;
}
case AstType::ReturnStmt: {
auto *rs = static_cast<ReturnStmt *>(stmt);
Type retT = typeCtx.GetBasic(TypeTag::Null);
if (rs->value)
{
auto res = analyzeExpr(rs->value);
if (!res)
return std::unexpected(res.error());
retT = *res;
}
// 返回值校验
if (state.currentFn && !retT.isAssignableTo(state.currentFn->resolvedReturnType))
{
return std::unexpected(Error(
ErrorType::TypeError,
"cannot return '" + retT.toString() + "' from function expecting '"
+ state.currentFn->resolvedReturnType.toString() + "'",
"",
rs->location));
}
break;
}
case AstType::ExprStmt: {
auto res = analyzeExpr(static_cast<ExprStmt *>(stmt)->expr);
if (!res)
return std::unexpected(res.error());
break;
}
default: break;
}
return {};
}
Result<Type, Error> Analyzer::analyzeExpr(Expr *expr)
{
if (!expr)
return typeCtx.GetBasic(TypeTag::Null);
switch (expr->type)
{
case AstType::LiteralExpr: {
auto t = static_cast<LiteralExpr *>(expr)->literal.type;
if (t == TokenType::LiteralNumber)
return expr->resolvedType = typeCtx.GetBasic(TypeTag::Int);
if (t == TokenType::LiteralString)
return expr->resolvedType = typeCtx.GetBasic(TypeTag::String);
if (t == TokenType::LiteralTrue || t == TokenType::LiteralFalse)
return expr->resolvedType = typeCtx.GetBasic(TypeTag::Bool);
return expr->resolvedType = typeCtx.GetBasic(TypeTag::Null);
}
case AstType::IdentiExpr: {
auto *i = static_cast<IdentiExpr *>(expr);
auto res = resolveSymbolInternal(i->name, i->location, env.current);
if (!res)
return std::unexpected(res.error());
i->resolvedSymbol = *res;
return expr->resolvedType = (*res)->type;
}
case AstType::MemberExpr: {
auto *m = static_cast<MemberExpr *>(expr);
auto targetRes = analyzeExpr(m->target);
if (!targetRes)
return targetRes;
Type targetType = *targetRes;
if (targetType.is(TypeTag::Any))
return expr->resolvedType = typeCtx.GetBasic(TypeTag::Any);
if (!targetType.is(TypeTag::Struct))
return std::unexpected(Error(
ErrorType::TypeError, "member access requires struct", "", m->location));
auto *st = static_cast<StructType *>(targetType.base);
if (!st->fieldMap.contains(m->name))
{
return std::unexpected(Error(
ErrorType::TypeError,
"struct '" + st->name + "' has no field named '" + m->name + "'",
"",
m->location));
}
// 字段类型
return expr->resolvedType = st->fields[st->fieldMap[m->name]].type;
}
case AstType::NewExpr: {
auto *o = static_cast<NewExpr *>(expr);
auto res = resolveTypeExpr(o->typeExpr);
if (!res)
{
return std::unexpected(res.error());
}
if (!res->base || res->base->tag != TypeTag::Struct)
{
return std::unexpected(
Error(ErrorType::TypeError, "requires struct", "", o->location));
}
auto *st = static_cast<StructType *>(res->base);
for (auto &arg : o->args)
{
if (!arg.name.empty() && !st->fieldMap.contains(arg.name))
return std::unexpected(
Error(ErrorType::TypeError, "unknown field", "", arg.value->location));
auto r = analyzeExpr(arg.value);
if (!r)
{
return std::unexpected(r.error());
}
// 字段赋值类型检查
if (!arg.name.empty()
&& !r->isAssignableTo(st->fields[st->fieldMap[arg.name]].type))
{
return std::unexpected(Error(
ErrorType::TypeError, "field type mismatch", "", arg.value->location));
}
}
return expr->resolvedType = *res;
}
case AstType::InfixExpr: {
auto *in = static_cast<InfixExpr *>(expr);
auto lRes = analyzeExpr(in->left);
if (!lRes)
return lRes;
auto rRes = analyzeExpr(in->right);
if (!rRes)
return rRes;
Type l = *lRes;
Type r = *rRes;
if (in->op == BinaryOperator::Assign)
{
if (!r.isAssignableTo(l))
return std::unexpected(Error(
ErrorType::TypeError,
"cannot assign '" + r.toString() + "' to '" + l.toString() + "'",
"",
in->location));
return expr->resolvedType = l;
}
if (in->op == BinaryOperator::Equal || in->op == BinaryOperator::NotEqual
|| in->op == BinaryOperator::Greater || in->op == BinaryOperator::Less
|| in->op == BinaryOperator::GreaterEqual
|| in->op == BinaryOperator::LessEqual)
{
return expr->resolvedType = typeCtx.GetBasic(TypeTag::Bool);
}
if (l.is(TypeTag::Any) || r.is(TypeTag::Any))
return expr->resolvedType = typeCtx.GetBasic(TypeTag::Any);
// 算术操作强检查
if (in->op == BinaryOperator::Add && l.is(TypeTag::String) && r.is(TypeTag::String))
return expr->resolvedType = typeCtx.GetBasic(TypeTag::String);
if (l.is(TypeTag::Int) && r.is(TypeTag::Int))
return expr->resolvedType = typeCtx.GetBasic(TypeTag::Int);
if ((l.is(TypeTag::Int) || l.is(TypeTag::Double))
&& (r.is(TypeTag::Int) || r.is(TypeTag::Double)))
return expr->resolvedType = typeCtx.GetBasic(TypeTag::Double);
return std::unexpected(Error(
ErrorType::TypeError, "invalid types for binary operator", "", in->location));
}
case AstType::CallExpr: {
auto *c = static_cast<CallExpr *>(expr);
auto calleeRes = analyzeExpr(c->callee);
if (!calleeRes)
return calleeRes;
Type calleeType = *calleeRes;
DynArray<Type> argTypes;
for (auto *a : c->args.args)
{
auto ar = analyzeExpr(a);
if (!ar)
return std::unexpected(ar.error());
argTypes.push_back(*ar);
}
if (calleeType.is(TypeTag::Any))
return expr->resolvedType = typeCtx.GetBasic(TypeTag::Any);
// 函数签名校验
if (!calleeType.is(TypeTag::Function))
return std::unexpected(
Error(ErrorType::TypeError, "callee is not a function", "", c->location));
auto *ft = static_cast<FuncType *>(calleeType.base);
if (ft->paramTypes.size() != argTypes.size())
{
return std::unexpected(Error(
ErrorType::SyntaxError,
std::format(
"expected {} arguments, got {}", ft->paramTypes.size(), argTypes.size()),
"none",
c->location));
}
for (size_t i = 0; i < argTypes.size(); ++i)
{
if (!argTypes[i].isAssignableTo(ft->paramTypes[i]))
{
return std::unexpected(Error(
ErrorType::TypeError,
"argument " + std::to_string(i + 1) + " expects '"
+ ft->paramTypes[i].toString() + "', got '" + argTypes[i].toString()
+ "'",
"",
c->args.args[i]->location));
}
}
return expr->resolvedType = ft->retType;
}
case AstType::LambdaExpr: {
auto l = static_cast<LambdaExpr *>(expr);
Type returnType = typeCtx.GetBasic(TypeTag::Any);
if (l->returnType)
{
auto tres = resolveTypeExpr(l->returnType);
if (!tres)
{
return tres;
}
returnType = *tres;
}
FnDefStmt *f = arena.Allocate<FnDefStmt>(
false, "LambdaFn", l->params, l->returnType, nullptr, l->location);
FnStateGuard fnGuard(state.currentFn, f);
ScopeGuard scopeGuard(env, true);
DynArray<Type> paramTypes;
for (auto *p : l->params)
{
auto pres = resolveTypeExpr(p->typeSpecifier);
if (!pres)
{
return pres;
}
p->resolvedType = *pres;
paramTypes.push_back(*pres);
env.current->locals[p->name] = arena.Allocate<Symbol>(
p->name,
p->resolvedType,
SymbolLocation::Local,
env.current->nextLocalId++,
false);
}
if (l->isExprBody)
{
Expr *expr = static_cast<Expr *>(l->body);
if (auto r = analyzeExpr(expr); !r)
{
return r;
}
if (!expr->resolvedType.isAssignableTo(state.currentFn->resolvedReturnType))
{
return std::unexpected(Error(
ErrorType::TypeError,
"cannot return '" + state.currentFn->resolvedReturnType.toString()
+ "' from lambda function expecting '"
+ state.currentFn->resolvedReturnType.toString() + "'",
"",
expr->location));
}
}
else
{
Stmt *stmt = static_cast<Stmt *>(l->body);
if (auto r = analyzeStmt(stmt); !r)
{
return std::unexpected(r.error());
}
}
return l->resolvedType = typeCtx.CreateFuncType(paramTypes, returnType);
}
default: break;
}
return expr->resolvedType = typeCtx.GetBasic(TypeTag::Any);
}
Result<Symbol *, Error>
Analyzer::resolveSymbolInternal(const String &name, const SourceLocation &loc, Scope *s)
{
Scope *curr = s;
while (curr)
{
if (curr->locals.contains(name))
return curr->locals[name];
if (curr->isFunctionBoundary)
break;
curr = curr->parent;
}
if (curr && curr->parent)
{
auto res = resolveSymbolInternal(name, loc, curr->parent);
if (!res)
return res;
Symbol *outer = *res;
if (outer->location == SymbolLocation::Global)
return outer;
int idx = addUpvalue(curr, outer, outer->location == SymbolLocation::Local);
return arena.Allocate<Symbol>(
name, outer->type, SymbolLocation::Upvalue, idx, outer->isConst);
}
if (globalSymbols.contains(name))
return globalSymbols[name];
return std::unexpected(
Error(ErrorType::UseUndeclaredIdentifier, "symbol not found", "", loc));
}
int Analyzer::addUpvalue(Scope *s, Symbol *t, bool isL)
{
for (size_t i = 0; i < s->upvalues.size(); ++i)
if (s->upvalues[i].target == t)
return (int) i;
int idx = (int) s->upvalues.size();
s->upvalues.push_back({t, idx, isL});
return idx;
}
Result<Type, Error> Analyzer::resolveTypeExpr(Expr *texpr)
{
if (!texpr)
return typeCtx.GetBasic(TypeTag::Any);
if (texpr->type == AstType::NamedTypeExpr)
{
auto *n = static_cast<NamedTypeExpr *>(texpr);
if (n->path.empty())
return typeCtx.GetBasic(TypeTag::Any);
String &root = n->path[0];
if (root == "Any")
return typeCtx.GetBasic(TypeTag::Any);
if (root == "Int")
return typeCtx.GetBasic(TypeTag::Int);
if (root == "Double")
return typeCtx.GetBasic(TypeTag::Double);
if (root == "String")
return typeCtx.GetBasic(TypeTag::String);
if (root == "Bool")
return typeCtx.GetBasic(TypeTag::Bool);
if (root == "Null")
return typeCtx.GetBasic(TypeTag::Null);
if (globalTypes.contains(root))
return Type{globalTypes[root], false};
return std::unexpected(
Error(ErrorType::UseUndeclaredIdentifier, "unknown type", "", texpr->location));
}
else if (texpr->type == AstType::NullableTypeExpr)
{
auto res = resolveTypeExpr(static_cast<NullableTypeExpr *>(texpr)->inner);
if (!res)
{
return res;
}
res->isNullable = true;
return res;
}
else if (texpr->type == AstType::FnTypeExpr)
{
auto f = static_cast<FnTypeExpr *>(texpr);
DynArray<Type> paraTypes;
Type returnType = typeCtx.GetBasic(TypeTag::Any);
for (auto &pt : f->paraTypes)
{
auto result = resolveTypeExpr(pt);
if (!result)
{
return result;
}
paraTypes.push_back(*result);
}
if (f->returnType)
{
auto result = resolveTypeExpr(f->returnType);
if (!result)
{
return result;
}
returnType = *result;
}
return typeCtx.CreateFuncType(paraTypes, returnType);
}
return typeCtx.GetBasic(TypeTag::Any);
}
} // namespace Fig

View File

@@ -1,14 +1,14 @@
/*!
@file src/Sema/Analyzer.hpp
@brief 语义分析器定义
@brief 语义分析
@author PuqiAR (im@puqiar.top)
@date 2026-06-06
*/
#pragma once
#include <Ast/Ast.hpp>
#include <Sema/Type.hpp>
#include <Sema/Environment.hpp>
#include <Utils/Arena.hpp>
#include <Error/Diagnostics.hpp>
#include <SourceManager/SourceManager.hpp>
@@ -16,38 +16,17 @@ namespace Fig
{
class Analyzer
{
private:
Arena arena;
SourceManager &manager;
TypeContext typeCtx;
Environment env;
Diagnostics diag;
HashMap<String, BaseType*> globalTypes;
HashMap<String, Symbol*> globalSymbols;
bool hasInit = false;
bool hasMain = false;
// 核心递归查找:解决跨越函数边界的捕获问题
Result<Symbol*, Error> resolveSymbolInternal(const String &name, const SourceLocation &loc, Scope* startScope);
Result<Type, Error> resolveTypeExpr(Expr *texpr);
Result<void, Error> pass1(Program *prog);
Result<void, Error> resolveTypes(Program *prog);
Result<void, Error> checkBodies(Program *prog);
Result<void, Error> analyzeStmt(Stmt *stmt);
Result<Type, Error> analyzeExpr(Expr *expr);
int addUpvalue(Scope *scope, Symbol *target, bool isLocal);
public:
Analyzer(SourceManager &m) : manager(m) {}
Analyzer(SourceManager &) {}
Result<void, Error> Analyze(Program *prog);
Result<void, Error> Analyze(Program *)
{
return {};
}
Diagnostics& GetDiagnostics() { return diag; }
TypeContext& GetTypeContext() { return typeCtx; }
Diagnostics &GetDiagnostics() { return diag; }
private:
Diagnostics diag;
};
}
} // namespace Fig

View File

@@ -1,64 +0,0 @@
#include <Parser/Parser.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));
Diagnostics diagnostics;
Parser parser(lexer, srcManager, String(path), diagnostics);
diagnostics.EmitAll(srcManager);
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()
{
std::string testDir = "T:/Files/Maker/Code/MyCodingLanguage/The Fig Project/Fig/tests/Sema";
for (const auto &entry : fs::directory_iterator(testDir))
{
if (entry.path().extension() == ".fig")
{
runTest(entry.path().string());
}
}
return 0;
}

View File

@@ -1,6 +1,8 @@
/*!
@file src/Sema/Environment.hpp
@brief 树状符号表定义
@brief 符号表
@author PuqiAR (im@puqiar.top)
@date 2026-07-05
*/
#pragma once
@@ -10,49 +12,30 @@
namespace Fig
{
enum class SymbolLocation
enum class SymbolKind : uint8_t
{
Global,
Local,
Upvalue
Var,
Const,
Func,
Type,
};
struct Symbol
{
String name;
Type type;
SymbolLocation location;
int index;
bool isConst;
SymbolKind kind;
int index; // local: register idx, global: global idx, upvalue: upvalue idx
Symbol(String n, Type t, SymbolLocation l, int i, bool c) :
name(std::move(n)), type(t), location(l), index(i), isConst(c)
{
}
};
struct UpvalueCapture
{
Symbol *target;
int index;
bool isLocal;
bool isType() const { return kind == SymbolKind::Type; }
};
struct Scope
{
Scope *parent = nullptr;
bool isFunctionBoundary = false;
bool isFnBoundary = 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;
}
int nextReg = 0;
};
class Environment
@@ -60,13 +43,19 @@ namespace Fig
public:
Scope *current = nullptr;
void Push(bool isFn)
void push(bool isFn)
{
current = new Scope(current, isFn);
auto *s = new Scope;
s->parent = current;
s->isFnBoundary = isFn;
if (current && !isFn)
s->nextReg = current->nextReg;
current = s;
}
void Pop()
void pop()
{
Scope *old = current;
auto *old = current;
current = current->parent;
delete old;
}

View File

@@ -1,100 +0,0 @@
/*!
@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,135 +1,36 @@
/*!
@file src/Sema/Type.hpp
@brief 类型系统定义:对齐 NaN-boxing 物理布局
@brief 类型系统
@author PuqiAR (im@puqiar.top)
@date 2026-07-05
*/
#pragma once
#include <Deps/Deps.hpp>
#include <Error/Error.hpp>
#include <Object/ObjectBase.hpp>
namespace Fig
{
enum class TypeTag : std::uint8_t
{
Int,
Double,
String,
Bool,
Null,
Any,
Function,
Struct,
Interface
};
class BaseType;
struct Type
{
BaseType *base = nullptr;
TypeObject *obj = 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 is(TypeTag t) const;
bool isAssignableTo(const Type &target) const;
};
class BaseType
{
public:
TypeTag tag;
String name;
BaseType(TypeTag t, String n) : tag(t), name(std::move(n)) {}
virtual ~BaseType() = default;
bool operator==(const BaseType &other) const
{
return tag == other.tag && name == other.name;
}
};
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)
inline bool Type::is(TypeTag t) const
{
return obj && obj->tag == t;
}
bool operator==(const FuncType &other) const
inline bool Type::isAssignableTo(const Type &target) const
{
return paramTypes == other.paramTypes && retType == other.retType;
if (target.is(TypeTag::Any) || is(TypeTag::Any))
return true;
if (is(TypeTag::Null) && target.isNullable)
return true;
return obj == target.obj && (!isNullable || target.isNullable);
}
};
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, struct 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;
}
bool operator==(const StructType &other) const
{
return this == &other; // 即使是两个完全一样的struct, 也认作不同的type
}
};
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)) {}
bool operator==(const InterfaceType &other) const
{
return this == &other; // 即使是两个完全一样的interface, 也认作不同的type
}
};
class TypeContext
{
public:
DynArray<BaseType *> allTypes;
BaseType *intType, *doubleType, *stringType, *boolType, *anyType, *nullType;
TypeContext();
~TypeContext();
Type GetBasic(TypeTag tag, bool nullable = false);
Type CreateFuncType(DynArray<Type> params, Type ret);
};
} // namespace Fig

View File

@@ -50,74 +50,6 @@ target("ObjectTest")
add_files("src/Object/Object.cpp")
add_files("src/Object/ObjectTest.cpp")
target("AnalyzerTest")
add_files("src/Core/*.cpp")
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")
target("CompilerTest")
add_files("src/Core/*.cpp")
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")
add_files("src/Core/*.cpp")
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("ReplTest")
add_files("src/Core/*.cpp")
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/Repl/ReplTest.cpp")
target("Fig")
add_files("src/Core/*.cpp")
add_files("src/Error/Error.cpp")
@@ -131,12 +63,6 @@ target("Fig")
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/Compiler/ExprCompiler.cpp")
add_files("src/Compiler/StmtCompiler.cpp")
add_files("src/Compiler/Compiler.cpp")
add_files("src/Bytecode/Disassembler.cpp")
add_files("src/Object/Object.cpp")