From 9f7fe79a2ecde3cb618ded59b9e41673c71b9b42 Mon Sep 17 00:00:00 2001 From: PuqiAR Date: Tue, 21 Jul 2026 22:52:17 +0800 Subject: [PATCH] Made some preparations to refactor semantic analysis and type system --- src/Compiler/CompileTest.cpp | 67 --- src/Compiler/Compiler.cpp | 142 ------- src/Compiler/Compiler.hpp | 11 +- src/Compiler/ExprCompiler.cpp | 477 --------------------- src/Compiler/StmtCompiler.cpp | 269 ------------ src/LSP/LSPServer.cpp | 19 - src/Object/ObjectBase.hpp | 32 ++ src/Object/StructObject.hpp | 33 +- src/Sema/Analyzer.cpp | 752 ---------------------------------- src/Sema/Analyzer.hpp | 49 +-- src/Sema/AnalyzerTest.cpp | 64 --- src/Sema/Environment.hpp | 65 ++- src/Sema/Type.cpp | 100 ----- src/Sema/Type.hpp | 135 +----- xmake.lua | 74 ---- 15 files changed, 116 insertions(+), 2173 deletions(-) delete mode 100644 src/Compiler/CompileTest.cpp delete mode 100644 src/Compiler/Compiler.cpp delete mode 100644 src/Compiler/ExprCompiler.cpp delete mode 100644 src/Compiler/StmtCompiler.cpp delete mode 100644 src/LSP/LSPServer.cpp delete mode 100644 src/Sema/Analyzer.cpp delete mode 100644 src/Sema/AnalyzerTest.cpp delete mode 100644 src/Sema/Type.cpp diff --git a/src/Compiler/CompileTest.cpp b/src/Compiler/CompileTest.cpp deleted file mode 100644 index 6350653..0000000 --- a/src/Compiler/CompileTest.cpp +++ /dev/null @@ -1,67 +0,0 @@ -#include -#include -#include -#include -#include -#include - -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; -} diff --git a/src/Compiler/Compiler.cpp b/src/Compiler/Compiler.cpp deleted file mode 100644 index bcfe9fa..0000000 --- a/src/Compiler/Compiler.cpp +++ /dev/null @@ -1,142 +0,0 @@ -/*! - @file src/Compiler/Compiler.cpp - @brief 编译器主逻辑实现:物理 Bootstrapper 与双步扫描 -*/ - -#include -#include - -namespace Fig -{ - Result 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(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 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 diff --git a/src/Compiler/Compiler.hpp b/src/Compiler/Compiler.hpp index 237e167..19ce883 100644 --- a/src/Compiler/Compiler.hpp +++ b/src/Compiler/Compiler.hpp @@ -50,6 +50,15 @@ namespace Fig public: Compiler(SourceManager &m, Diagnostics &d) : manager(m), diag(d) {} - Result Compile(Program *program); + Result 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; + } }; } diff --git a/src/Compiler/ExprCompiler.cpp b/src/Compiler/ExprCompiler.cpp deleted file mode 100644 index 9b6d701..0000000 --- a/src/Compiler/ExprCompiler.cpp +++ /dev/null @@ -1,477 +0,0 @@ -/*! - @file src/Compiler/ExprCompiler.cpp - @brief 表达式编译 -*/ - -#include -#include -#include -#include -#include -#include -#include -#include - -namespace Fig -{ - static Result 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::min() - && iVal <= std::numeric_limits::max()) - { - return Value::FromInt(static_cast(iVal)); - } - else - { - return Value::FromDouble(static_cast(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::min() - && dVal <= std::numeric_limits::max()) - { - return Value::FromInt(static_cast(dVal)); - } - else - { - return Value::FromDouble(dVal); - } - } - } - - Result 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(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(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(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(expr); - Symbol *sym = i->resolvedSymbol; - - if (sym->location == SymbolLocation::Local) - { - // no-copy for temp eval - if (target == NO_REG) - return static_cast(sym->index); - - // 仅在被强制指定目标(如参数装填)时发射搬运指令 - if (target != sym->index) - { - emit( - Op::iABx(OpCode::Mov, target, static_cast(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(sym->index), 0), - &i->location); - } - else if (sym->location == SymbolLocation::Global) - { - int gId = getGlobalID(i->name); - emit(Op::iABx(OpCode::GetGlobal, r, static_cast(gId)), &i->location); - } - return r; - } - - case AstType::CallExpr: { - auto *c = static_cast(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(c->callee); - // 只有在全局区的函数,才能使用 FastCall - if (id->resolvedSymbol->location == SymbolLocation::Global) - { - isGlobalFastCall = true; - int protoIdx = id->resolvedSymbol->index; - emit( - Op::iABC( - OpCode::FastCall, - static_cast(protoIdx), - baseReg, - static_cast(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(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(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(in->left); - Symbol *sym = lid->resolvedSymbol; - if (sym->location == SymbolLocation::Local) - { - emit( - Op::iABx(OpCode::Mov, static_cast(sym->index), *r_val), - &lid->location); - } - else if (sym->location == SymbolLocation::Upvalue) - { - emit( - Op::iABC( - OpCode::SetUpval, *r_val, static_cast(sym->index), 0), - &lid->location); - } - else - { - emit( - Op::iABx( - OpCode::SetGlobal, - *r_val, - static_cast(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(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(l->body)); - if (!result) - { - return result; - } - - emit(Op::iABC(OpCode::Return, *result, 0, 0), &l->location); - } - else - { - auto result = compileStmt(static_cast(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 \ No newline at end of file diff --git a/src/Compiler/StmtCompiler.cpp b/src/Compiler/StmtCompiler.cpp deleted file mode 100644 index 2556545..0000000 --- a/src/Compiler/StmtCompiler.cpp +++ /dev/null @@ -1,269 +0,0 @@ -/*! - @file src/Compiler/StmtCompiler.cpp - @brief 语句编译 -*/ - -#include -#include -#include -#include -#include - -namespace Fig -{ - Result Compiler::compileStmt(Stmt *stmt) - { - if (stmt == nullptr) - { - return {}; - } - - switch (stmt->type) - { - case AstType::BlockStmt: { - auto *b = static_cast(stmt); - for (auto *n : b->nodes) - { - auto res = compileStmt(n); - if (!res) - return res; - } - break; - } - - case AstType::VarDecl: { - auto *v = static_cast(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(getGlobalID(v->name))), - &v->location); - current->freereg = mark; // 释放初始化表达式的临时占用 - } - else - { - // 抬升水位,锁死局部变量的物理槽位 - Register targetReg = static_cast(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(stmt); - - if (f->protoIndex == -1) // 闭包环境没有被扫到 - { - Proto *newProto = new Proto(); - newProto->name = f->name; - newProto->numParams = static_cast(f->params.size()); - newProto->maxRegisters = newProto->numParams; // sync - - f->protoIndex = static_cast(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(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(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(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(f->protoIndex)), - &f->location); - - int gId = getGlobalID(f->name); - emit(Op::iABx(OpCode::SetGlobal, r, static_cast(gId)), - &f->location); - - freeReg(); - } - break; - } - - case AstType::IfStmt: { - auto *i = static_cast(stmt); - DynArray 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(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(current->proto->code.size())); - emit(Op::iAsBx(OpCode::Jmp, 0, 0), &i->location); - - int targetIdx = static_cast(current->proto->code.size()); - current->proto->code[jmpToNext] = Op::iAsBx( - OpCode::JmpIfFalse, *r_cond, static_cast(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(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(current->proto->code.size())); - emit(Op::iAsBx(OpCode::Jmp, 0, 0), &elif->location); - - int target = static_cast(current->proto->code.size()); - - current->proto->code.resize(nextElif); - current->proto->code[nextElif] = Op::iAsBx( - OpCode::JmpIfFalse, *ec, static_cast(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(current->proto->code.size()); - for (int pos : exitJumps) - { - current->proto->code[pos] = - Op::iAsBx(OpCode::Jmp, 0, static_cast(endIdx - pos - 1)); - } - break; - } - - case AstType::WhileStmt: { - auto *w = static_cast(stmt); - int startIdx = static_cast(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(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(current->proto->code.size()); - emit(Op::iAsBx(OpCode::Jmp, 0, static_cast(startIdx - backJmpIdx - 1)), - &w->location); - - int endIdx = static_cast(current->proto->code.size()); - current->proto->code[exitJmpIdx] = Op::iAsBx( - OpCode::JmpIfFalse, *r_cond, static_cast(endIdx - exitJmpIdx - 1)); - break; - } - - case AstType::ReturnStmt: { - auto *rs = static_cast(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(stmt)->expr); - if (!reg) - return std::unexpected(reg.error()); - - current->freereg = mark; // 彻底抛弃孤立表达式的副作用 - break; - } - - default: break; - } - return {}; - } -} // namespace Fig \ No newline at end of file diff --git a/src/LSP/LSPServer.cpp b/src/LSP/LSPServer.cpp deleted file mode 100644 index d9e04da..0000000 --- a/src/LSP/LSPServer.cpp +++ /dev/null @@ -1,19 +0,0 @@ -#include - -#ifdef _WIN32 - #include - #include -#endif - -int main() -{ -#ifdef _WIN32 - _setmode(_fileno(stdin), _O_BINARY); - _setmode(_fileno(stdout), _O_BINARY); -#endif - - Fig::LspServer server; - - server.Run(); - return 0; -} \ No newline at end of file diff --git a/src/Object/ObjectBase.hpp b/src/Object/ObjectBase.hpp index c468d55..31e9bcc 100644 --- a/src/Object/ObjectBase.hpp +++ b/src/Object/ObjectBase.hpp @@ -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 diff --git a/src/Object/StructObject.hpp b/src/Object/StructObject.hpp index 7383e16..f811219 100644 --- a/src/Object/StructObject.hpp +++ b/src/Object/StructObject.hpp @@ -9,6 +9,7 @@ #include #include +#include namespace Fig { @@ -23,33 +24,29 @@ namespace Fig // + 6 bytes padding }; */ + struct FieldMeta + { + String name; + Type type; + }; + struct StructObject final : public Object { - String name; // 元信息(仅供调试/打印/反射) - - // 内存布局信息 - std::uint8_t fieldCount; - Object *operators[GetOperatorsSize()]; - /* - 运算符重载,nullptr代表无重载 - 一般为 NativeFunction / Function - - 排列: - [unary operators ]( binary operators] - 0 - UnaryOperators::Count BinaryOperators::Count - */ - + String name; + std::uint8_t fieldCount; + FieldMeta *fields; // [fieldCount] + Object *operators[GetOperatorsSize()]; + // operators: [UnaryOp 0..N][BinaryOp 0..N], nullptr = 无重载 Object *GetUnaryOperator(UnaryOperator _op) { - std::uint8_t idx = static_cast(_op); - return operators[idx]; + return operators[static_cast(_op)]; } Object *GetBinaryOperator(BinaryOperator _op) { - std::uint16_t idx = static_cast(UnaryOperator::Count) + static_cast(_op); - return operators[idx]; + return operators[static_cast(UnaryOperator::Count) + + static_cast(_op)]; } }; }; // namespace Fig \ No newline at end of file diff --git a/src/Sema/Analyzer.cpp b/src/Sema/Analyzer.cpp deleted file mode 100644 index e2480be..0000000 --- a/src/Sema/Analyzer.cpp +++ /dev/null @@ -1,752 +0,0 @@ -/*! - @file src/Sema/Analyzer.cpp - @brief 语义分析器实现:实装强类型校验 (Call, Infix, Member, Return, Assign) -*/ - -#include -#include -#include -#include -#include -#include - -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 *¤t; - FnDefStmt *old; - FnStateGuard(FnDefStmt *&c, FnDefStmt *n) : current(c), old(c) - { - current = n; - } - ~FnStateGuard() - { - current = old; - } - }; - - Result 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 Analyzer::pass1(Program *prog) - { - for (auto *stmt : prog->nodes) - { - if (stmt->type == AstType::StructDefStmt) - { - auto *s = static_cast(stmt); - if (globalTypes.contains(s->name)) - { - return std::unexpected( - Error(ErrorType::RedeclarationError, "type redeclared", "", s->location)); - } - - auto *t = arena.Allocate(s->name); - typeCtx.allTypes.push_back(t); - globalTypes[s->name] = t; - } - else if (stmt->type == AstType::FnDefStmt) - { - auto *f = static_cast(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(f->name, Type{}, SymbolLocation::Global, 0, true); - globalSymbols[f->name] = sym; - env.current->locals[f->name] = sym; - f->resolvedSymbol = sym; - } - } - return {}; - } - - Result Analyzer::resolveTypes(Program *prog) - { - for (auto *stmt : prog->nodes) - { - if (stmt->type == AstType::StructDefStmt) - { - auto *s = static_cast(stmt); - auto *st = static_cast(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(stmt); - auto res = resolveTypeExpr(f->returnTypeSpecifier); - if (!res) - return std::unexpected(res.error()); - f->resolvedReturnType = *res; - - DynArray 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 Analyzer::checkBodies(Program *prog) - { - for (auto *stmt : prog->nodes) - { - auto r = analyzeStmt(stmt); - if (!r) - return r; - } - return {}; - } - - Result Analyzer::analyzeStmt(Stmt *stmt) - { - if (!stmt) - return {}; - switch (stmt->type) - { - case AstType::BlockStmt: { - auto *b = static_cast(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(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(v->name, declT, loc, idx, false); - v->localId = idx; - break; - } - - case AstType::FnDefStmt: { - auto *f = static_cast(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(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 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( - 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(upval.index), upval.isLocal}); - } - - break; - } - - case AstType::IfStmt: { - auto *i = static_cast(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(stmt)->cond : - static_cast(stmt)->cond; - Stmt *body = isWhile ? static_cast(stmt)->body : - static_cast(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(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(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(stmt)->expr); - if (!res) - return std::unexpected(res.error()); - break; - } - default: break; - } - return {}; - } - - Result Analyzer::analyzeExpr(Expr *expr) - { - if (!expr) - return typeCtx.GetBasic(TypeTag::Null); - switch (expr->type) - { - case AstType::LiteralExpr: { - auto t = static_cast(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(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(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(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(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(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(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(expr); - auto calleeRes = analyzeExpr(c->callee); - if (!calleeRes) - return calleeRes; - Type calleeType = *calleeRes; - - DynArray 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(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(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( - false, "LambdaFn", l->params, l->returnType, nullptr, l->location); - - FnStateGuard fnGuard(state.currentFn, f); - ScopeGuard scopeGuard(env, true); - - DynArray 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( - p->name, - p->resolvedType, - SymbolLocation::Local, - env.current->nextLocalId++, - false); - } - - if (l->isExprBody) - { - Expr *expr = static_cast(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(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 - 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( - 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 Analyzer::resolveTypeExpr(Expr *texpr) - { - if (!texpr) - return typeCtx.GetBasic(TypeTag::Any); - if (texpr->type == AstType::NamedTypeExpr) - { - auto *n = static_cast(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(texpr)->inner); - if (!res) - { - return res; - } - - res->isNullable = true; - return res; - } - else if (texpr->type == AstType::FnTypeExpr) - { - auto f = static_cast(texpr); - - DynArray 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 \ No newline at end of file diff --git a/src/Sema/Analyzer.hpp b/src/Sema/Analyzer.hpp index 67f9cd2..5e2b764 100644 --- a/src/Sema/Analyzer.hpp +++ b/src/Sema/Analyzer.hpp @@ -1,14 +1,14 @@ /*! @file src/Sema/Analyzer.hpp - @brief 语义分析器定义 + @brief 语义分析 + @author PuqiAR (im@puqiar.top) + @date 2026-06-06 */ #pragma once #include #include -#include -#include #include #include @@ -16,38 +16,17 @@ namespace Fig { class Analyzer { - private: - Arena arena; - SourceManager &manager; - TypeContext typeCtx; - Environment env; - Diagnostics diag; - - HashMap globalTypes; - HashMap globalSymbols; - - bool hasInit = false; - bool hasMain = false; - - // 核心递归查找:解决跨越函数边界的捕获问题 - Result resolveSymbolInternal(const String &name, const SourceLocation &loc, Scope* startScope); - - Result resolveTypeExpr(Expr *texpr); - Result pass1(Program *prog); - Result resolveTypes(Program *prog); - Result checkBodies(Program *prog); - - Result analyzeStmt(Stmt *stmt); - Result analyzeExpr(Expr *expr); - - int addUpvalue(Scope *scope, Symbol *target, bool isLocal); - public: - Analyzer(SourceManager &m) : manager(m) {} + Analyzer(SourceManager &) {} - Result Analyze(Program *prog); - - Diagnostics& GetDiagnostics() { return diag; } - TypeContext& GetTypeContext() { return typeCtx; } + Result Analyze(Program *) + { + return {}; + } + + Diagnostics &GetDiagnostics() { return diag; } + + private: + Diagnostics diag; }; -} +} // namespace Fig diff --git a/src/Sema/AnalyzerTest.cpp b/src/Sema/AnalyzerTest.cpp deleted file mode 100644 index 910fa33..0000000 --- a/src/Sema/AnalyzerTest.cpp +++ /dev/null @@ -1,64 +0,0 @@ -#include -#include -#include -#include - - -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; -} diff --git a/src/Sema/Environment.hpp b/src/Sema/Environment.hpp index 9833418..4f4457d 100644 --- a/src/Sema/Environment.hpp +++ b/src/Sema/Environment.hpp @@ -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; + String name; + Type type; + 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; - + Scope *parent = nullptr; + bool isFnBoundary = false; HashMap locals; - DynArray 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,14 +43,20 @@ 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; - current = current->parent; + auto *old = current; + current = current->parent; delete old; } }; diff --git a/src/Sema/Type.cpp b/src/Sema/Type.cpp deleted file mode 100644 index c6e531b..0000000 --- a/src/Sema/Type.cpp +++ /dev/null @@ -1,100 +0,0 @@ -/*! - @file src/Sema/Type.cpp - @brief 类型系统实现 -*/ - -#include - -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(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 params, Type ret) - { - auto *ft = new FuncType(std::move(params), ret); - allTypes.push_back(ft); - return Type{ft, false}; - } -} // namespace Fig diff --git a/src/Sema/Type.hpp b/src/Sema/Type.hpp index 386636b..fe05e51 100644 --- a/src/Sema/Type.hpp +++ b/src/Sema/Type.hpp @@ -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 -#include + +#include namespace Fig { - enum class TypeTag : std::uint8_t - { - Int, - Double, - String, - Bool, - Null, - Any, - Function, - Struct, - Interface - }; - - 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; + TypeObject *obj = nullptr; + bool isNullable = false; + bool is(TypeTag t) const; bool isAssignableTo(const Type &target) const; }; - class BaseType + inline bool Type::is(TypeTag t) const { - public: - TypeTag tag; - String name; - BaseType(TypeTag t, String n) : tag(t), name(std::move(n)) {} - virtual ~BaseType() = default; + return obj && obj->tag == t; + } - bool operator==(const BaseType &other) const - { - return tag == other.tag && name == other.name; - } - }; - - class FuncType : public BaseType + inline bool Type::isAssignableTo(const Type &target) const { - public: - DynArray paramTypes; - Type retType; - FuncType(DynArray params, Type ret) : - BaseType(TypeTag::Function, "Function"), paramTypes(std::move(params)), retType(ret) - { - } - - bool operator==(const FuncType &other) const - { - return paramTypes == other.paramTypes && retType == other.retType; - } - }; - - class StructType : public BaseType - { - public: - struct Field - { - String name; - Type type; - bool isPublic; - int index; - }; - DynArray fields; - HashMap fieldMap; - HashMap 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 params; - Type retType; - }; - HashMap 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 allTypes; - BaseType *intType, *doubleType, *stringType, *boolType, *anyType, *nullType; - - TypeContext(); - ~TypeContext(); - - Type GetBasic(TypeTag tag, bool nullable = false); - Type CreateFuncType(DynArray params, Type ret); - }; + 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); + } } // namespace Fig diff --git a/xmake.lua b/xmake.lua index 95b29d5..d803e0b 100644 --- a/xmake.lua +++ b/xmake.lua @@ -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") @@ -130,13 +62,7 @@ target("Fig") 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/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")