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