From 1fe9ccf7ead0b5949984dbf520dc19a7079b39a5 Mon Sep 17 00:00:00 2001 From: PuqiAR Date: Sat, 28 Feb 2026 20:42:15 +0800 Subject: [PATCH] =?UTF-8?q?feat:=20=E5=AE=9E=E7=8E=B0=E6=8E=A7=E5=88=B6?= =?UTF-8?q?=E6=B5=81=E8=AF=AD=E5=8F=A5=E5=B9=B6=E4=BC=98=E5=8C=96=E7=B1=BB?= =?UTF-8?q?=E5=9E=8B=E8=A7=A3=E6=9E=90=20-=20=E6=96=B0=E5=A2=9E=E4=BA=86?= =?UTF-8?q?=20ReturnStmt=E3=80=81BreakStmt=20=E5=92=8C=20ContinueStmt=20?= =?UTF-8?q?=E7=BB=93=E6=9E=84=EF=BC=8C=E4=BB=A5=E6=94=AF=E6=8C=81=20AST=20?= =?UTF-8?q?=E4=B8=AD=E7=9A=84=E6=8E=A7=E5=88=B6=E6=B5=81=E3=80=82=20-=20?= =?UTF-8?q?=E5=BC=95=E5=85=A5=E4=BA=86=20TypeInfo=20=E5=92=8C=20TypeContex?= =?UTF-8?q?t=20=E4=BB=A5=E5=AE=9E=E7=8E=B0=E6=9B=B4=E5=A5=BD=E7=9A=84?= =?UTF-8?q?=E7=B1=BB=E5=9E=8B=E7=AE=A1=E7=90=86=E5=92=8C=E8=A7=A3=E6=9E=90?= =?UTF-8?q?=E3=80=82=20-=20=E5=AF=B9=E5=88=86=E6=9E=90=E5=99=A8=E8=BF=9B?= =?UTF-8?q?=E8=A1=8C=E4=BA=86=E5=A2=9E=E5=BC=BA=EF=BC=8C=E8=83=BD=E5=A4=9F?= =?UTF-8?q?=E5=A4=84=E7=90=86=E5=87=BD=E6=95=B0=E5=AE=9A=E4=B9=89=E5=92=8C?= =?UTF-8?q?=E8=BF=94=E5=9B=9E=E8=AF=AD=E5=8F=A5=EF=BC=8C=E5=8C=85=E6=8B=AC?= =?UTF-8?q?=E7=B1=BB=E5=9E=8B=E6=A3=80=E6=9F=A5=E5=92=8C=E9=94=99=E8=AF=AF?= =?UTF-8?q?=E5=A4=84=E7=90=86=E3=80=82=20-=20=E6=9B=B4=E6=96=B0=E4=BA=86?= =?UTF-8?q?=E7=BC=96=E8=AF=91=E5=99=A8=E5=92=8C=E8=A7=A3=E6=9E=90=E5=99=A8?= =?UTF-8?q?=E4=BB=A5=E9=80=82=E5=BA=94=E6=96=B0=E7=9A=84=E6=8E=A7=E5=88=B6?= =?UTF-8?q?=E6=B5=81=E8=AF=AD=E5=8F=A5=E5=92=8C=E7=B1=BB=E5=9E=8B=E8=A7=A3?= =?UTF-8?q?=E6=9E=90=E9=80=BB=E8=BE=91=E3=80=82=20-=20=E9=87=8D=E6=9E=84?= =?UTF-8?q?=E4=BA=86=E7=8E=B0=E6=9C=89=E4=BB=A3=E7=A0=81=E4=BB=A5=E6=8F=90?= =?UTF-8?q?=E9=AB=98=E6=B8=85=E6=99=B0=E5=BA=A6=E5=92=8C=E5=8F=AF=E7=BB=B4?= =?UTF-8?q?=E6=8A=A4=E6=80=A7=EF=BC=8C=E5=8C=85=E6=8B=AC=E5=AF=B9=E8=A1=A8?= =?UTF-8?q?=E8=BE=BE=E5=BC=8F=E5=92=8C=E8=AF=AD=E5=8F=A5=E4=B8=AD=E7=9A=84?= =?UTF-8?q?=E7=B1=BB=E5=9E=8B=E5=A4=84=E7=90=86=E7=9A=84=E6=9B=B4=E6=94=B9?= =?UTF-8?q?=E3=80=82=20-=20=E5=88=A0=E9=99=A4=E4=BA=86=E8=BF=87=E6=97=B6?= =?UTF-8?q?=E7=9A=84=20String=20=E5=92=8C=20Struct=20=E5=AE=9A=E4=B9=89?= =?UTF-8?q?=EF=BC=8C=E4=BB=A3=E4=B9=8B=E4=BB=A5=20StringObject=20=E5=92=8C?= =?UTF-8?q?=20StructObject=20=E4=BB=A5=E5=AE=9E=E7=8E=B0=E6=9B=B4=E5=A5=BD?= =?UTF-8?q?=E7=9A=84=E5=AF=B9=E8=B1=A1=E8=A1=A8=E7=A4=BA=E3=80=82?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/Ast/Ast.hpp | 1 + src/Ast/Base.hpp | 17 +- src/Ast/Stmt/ControlFlowStmts.hpp | 72 +++++ src/Ast/Stmt/FnDefStmt.hpp | 20 +- src/Compiler/Compiler.hpp | 23 +- src/Compiler/StmtCompiler.cpp | 1 + src/Object/FunctionObject.hpp | 25 ++ src/Object/Object.cpp | 28 +- src/Object/Object.hpp | 5 +- src/Object/ObjectBase.hpp | 62 ++--- src/Object/{String.hpp => StringObject.hpp} | 2 +- src/Object/{Struct.hpp => StructObject.hpp} | 4 +- src/Parser/Parser.hpp | 6 + src/Parser/StmtParser.cpp | 55 +++- src/Sema/Analyzer.cpp | 282 ++++++++++++++++---- src/Sema/Analyzer.hpp | 48 +++- src/Sema/Environment.hpp | 12 +- src/Sema/Type.hpp | 116 +++++++- 18 files changed, 642 insertions(+), 137 deletions(-) create mode 100644 src/Ast/Stmt/ControlFlowStmts.hpp create mode 100644 src/Object/FunctionObject.hpp rename src/Object/{String.hpp => StringObject.hpp} (94%) rename src/Object/{Struct.hpp => StructObject.hpp} (94%) diff --git a/src/Ast/Ast.hpp b/src/Ast/Ast.hpp index 0946821..ed172a1 100644 --- a/src/Ast/Ast.hpp +++ b/src/Ast/Ast.hpp @@ -14,6 +14,7 @@ #include #include +#include #include #include #include diff --git a/src/Ast/Base.hpp b/src/Ast/Base.hpp index ca0d813..f4748ea 100644 --- a/src/Ast/Base.hpp +++ b/src/Ast/Base.hpp @@ -33,12 +33,15 @@ namespace Fig CallExpr, // 后缀表达式,函数调用 /* Statements */ - ExprStmt, // 表达式语句,如 println(1) - VarDecl, // 变量声明 - IfStmt, // If语句 - ElseIfStmt, // ElseIf语句,不准悬空,平铺式else if - WhileStmt, // while语句 - FnDefStmt, // func函数定义语句 + ExprStmt, // 表达式语句,如 println(1) + VarDecl, // 变量声明 + IfStmt, // If语句 + ElseIfStmt, // ElseIf语句,不准悬空,平铺式else if + WhileStmt, // while语句 + FnDefStmt, // func函数定义语句 + ReturnStmt, // 返回语句 + BreakStmt, // break语句 + ContinueStmt, // continue语句 /* Type Expressions */ TypeExpr, // 基类 @@ -67,7 +70,7 @@ namespace Fig struct Expr : public AstNode { - TypeTag resolvedType = TypeTag::Any; + TypeInfo *resolvedType = nullptr; // TODO: 可选的常量折叠 // 拓展 isConstExpr和 constValue槽位 diff --git a/src/Ast/Stmt/ControlFlowStmts.hpp b/src/Ast/Stmt/ControlFlowStmts.hpp new file mode 100644 index 0000000..d91b071 --- /dev/null +++ b/src/Ast/Stmt/ControlFlowStmts.hpp @@ -0,0 +1,72 @@ +/*! + @file src/Ast/Stmt/ControlFlowStmts + @brief 控制流语句 return, break, continue 定义 + @author PuqiAR (im@puqiar.top) + @date 2026-02-27 +*/ + +#pragma once + +#include + +namespace Fig +{ + struct ReturnStmt final : public Stmt + { + Expr *value; + + ReturnStmt() + { + type = AstType::ReturnStmt; + } + + ReturnStmt(Expr *_value, SourceLocation _location) : value(_value) + { + type = AstType::ReturnStmt; + location = std::move(_location); + } + + virtual String toString() const override + { + return std::format("", value->toString()); + } + }; + + struct BreakStmt final : public Stmt + { + BreakStmt() + { + type = AstType::BreakStmt; + } + + BreakStmt(SourceLocation _location) + { + type = AstType::BreakStmt; + location = std::move(_location); + } + + virtual String toString() const override + { + return ""; + } + }; + + struct ContinueStmt final : public Stmt + { + ContinueStmt() + { + type = AstType::ContinueStmt; + } + + ContinueStmt(SourceLocation _location) + { + type = AstType::ContinueStmt; + location = std::move(_location); + } + + virtual String toString() const override + { + return ""; + } + }; +}; // namespace Fig \ No newline at end of file diff --git a/src/Ast/Stmt/FnDefStmt.hpp b/src/Ast/Stmt/FnDefStmt.hpp index 0a11a94..c2c19da 100644 --- a/src/Ast/Stmt/FnDefStmt.hpp +++ b/src/Ast/Stmt/FnDefStmt.hpp @@ -16,6 +16,9 @@ namespace Fig String name; SourceLocation location; + TypeInfo *resolvedType = nullptr; + int localId = -1; + virtual String toString() const = 0; }; @@ -28,18 +31,16 @@ namespace Fig PosParam(String _name, TypeExpr *_type, Expr *_defaultValue, SourceLocation _location) : type(_type), defaultValue(_defaultValue) { - name = std::move(_name); + name = std::move(_name); location = std::move(_location); } virtual String toString() const override { - return std::format( - "", + return std::format("", name, (type ? type->toString() : "Any"), - (defaultValue ? " =" + defaultValue->toString() : "") - ); + (defaultValue ? " =" + defaultValue->toString() : "")); } }; @@ -58,6 +59,9 @@ namespace Fig TypeExpr *returnType; BlockStmt *body; + TypeInfo *resolvedReturnType = nullptr; + int localId = -1; + FnDefStmt() { type = AstType::FnDefStmt; @@ -87,14 +91,12 @@ namespace Fig } pStr += p->toString(); } - return std::format( - " {} {{{}}}>", + return std::format(" {} {{{}}}>", (isPublic ? "public " : ""), name, pStr, (returnType ? returnType->toString() : "Any"), - body->toString() - ); + body->toString()); } }; }; // namespace Fig \ No newline at end of file diff --git a/src/Compiler/Compiler.hpp b/src/Compiler/Compiler.hpp index 014b55e..24cdb73 100644 --- a/src/Compiler/Compiler.hpp +++ b/src/Compiler/Compiler.hpp @@ -34,8 +34,8 @@ namespace Fig int depth; // 物理作用域深度(用于 EndScope 释放寄存器) }; - static constexpr int MAX_LOCALS = 250; - static constexpr int MAX_CONSTANTS = UINT16_MAX; + inline constexpr int MAX_LOCALS = 250; + inline constexpr int MAX_CONSTANTS = UINT16_MAX + 1; // 任何跨函数、跨模块的编译,都压入弹出这个 State struct FuncState @@ -66,6 +66,24 @@ namespace Fig SourceManager &manager; FuncState *current = nullptr; // 永远指向当前正在编译的上下文 public: + struct FuncStateProtector + { + Compiler *compiler; + FuncState *prevState; + + [[nodiscard]] + FuncStateProtector(Compiler *comp, FuncState *newState) : + compiler(comp), prevState(comp->current) + { + compiler->current = newState; + } + + ~FuncStateProtector() + { + compiler->current = prevState; + } + }; + Compiler(String _fileName, SourceManager &_manager) : fileName(std::move(_fileName)), manager(_manager) { @@ -85,7 +103,6 @@ namespace Fig } Result Compile(Program *program); - private: void PushState(String _name) { diff --git a/src/Compiler/StmtCompiler.cpp b/src/Compiler/StmtCompiler.cpp index 10e9407..39bb3be 100644 --- a/src/Compiler/StmtCompiler.cpp +++ b/src/Compiler/StmtCompiler.cpp @@ -32,6 +32,7 @@ namespace Fig } else { + // TODO: 未初始化提供初始值 varReg = DeclareLocal(varDecl->localId); } diff --git a/src/Object/FunctionObject.hpp b/src/Object/FunctionObject.hpp new file mode 100644 index 0000000..416aba2 --- /dev/null +++ b/src/Object/FunctionObject.hpp @@ -0,0 +1,25 @@ +/*! + @file src/Object/FunctionObject.hpp + @brief 函数对象定义 + @author PuqiAR (im@puqiar.top) + @date 2026-02-28 +*/ + +#pragma once + +#include + + +namespace Fig +{ + // 运行时闭包对象 (24字节 Base + 8字节 Proto指针 = 32 bytes) + + struct Proto; + struct FunctionObject final : public Object + { + Proto *proto; // 指向编译器生成的只读字节码与常量池 + + // TODO: 实现闭包时 加一个 Upvalue 指针数组 + // Value* upvalues; + }; +} // namespace Fig \ No newline at end of file diff --git a/src/Object/Object.cpp b/src/Object/Object.cpp index c514f83..aa3b08f 100644 --- a/src/Object/Object.cpp +++ b/src/Object/Object.cpp @@ -9,5 +9,31 @@ namespace Fig { - + constexpr String Value::ToString() const + { + if (IsNull()) + { + return "null"; + } + else if (IsInt()) + { + return std::to_string(AsInt()); + } + else if (IsDouble()) + { + return std::format("{}", AsDouble()); + } + else if (IsBool()) + { + return (AsBool() ? "true" : "false"); + } + else if (IsObject()) + { + return "Object"; // TODO: 分派 + } + else + { + return "Unknow"; + } + } }; // namespace Fig \ No newline at end of file diff --git a/src/Object/Object.hpp b/src/Object/Object.hpp index cf50ebd..687f913 100644 --- a/src/Object/Object.hpp +++ b/src/Object/Object.hpp @@ -8,5 +8,6 @@ #pragma once #include -#include -#include \ No newline at end of file +#include +#include +#include \ No newline at end of file diff --git a/src/Object/ObjectBase.hpp b/src/Object/ObjectBase.hpp index 5612783..0d7a21a 100644 --- a/src/Object/ObjectBase.hpp +++ b/src/Object/ObjectBase.hpp @@ -111,11 +111,6 @@ namespace Fig return IsDouble() || IsInt(); } - [[nodiscard]] constexpr bool IsObject() const - { - return (v_ & (SIGN_BIT | QNAN_MASK)) == (SIGN_BIT | QNAN_MASK); - } - [[nodiscard]] constexpr bool IsNull() const { return v_ == (QNAN_MASK | TAG_NULL); @@ -126,6 +121,11 @@ namespace Fig return (v_ | 1) == (QNAN_MASK | TAG_TRUE); } + [[nodiscard]] constexpr bool IsObject() const + { + return (v_ & (SIGN_BIT | QNAN_MASK)) == (SIGN_BIT | QNAN_MASK); + } + // 提取数据 (Unbox / As) [[nodiscard]] constexpr double AsDouble() const { @@ -182,33 +182,7 @@ namespace Fig // 类函数 [[nodiscard]] - constexpr String ToString() const - { - if (IsNull()) - { - return "null"; - } - else if (IsInt()) - { - return std::to_string(AsInt()); - } - else if (IsDouble()) - { - return std::format("{}", AsDouble()); - } - else if (IsBool()) - { - return (AsBool() ? "true" : "false"); - } - else if (IsObject()) - { - return "Object"; // TODO: 分派 - } - else - { - return "Unknow"; - } - } + constexpr String ToString() const; }; /* @@ -223,15 +197,35 @@ namespace Fig Instance, }; - struct Struct /* : public Object */; // 结构体基类的定义,前向声明 + struct StructObject /* : public Object */; // 结构体基类的定义,前向声明 // Total 24 bytes size struct Object { Object *next; // 8 bytes: gc链表 - Struct *klass; // 8 bytes: 一切皆对象,父类指针 + StructObject *klass; // 8 bytes: 一切皆对象,父类指针 ObjectType type; // 1 byte : 类型 bool isMarked = false; // 1 byte : gc标记 // + 6 bytes padding + + constexpr bool isString() const + { + return type == ObjectType::String; + } + + constexpr bool isFunction() const + { + return type == ObjectType::Function; + } + + constexpr bool isStruct() const + { + return type == ObjectType::Struct; + } + + constexpr bool isInstance() const + { + return type == ObjectType::Instance; + } }; } // namespace Fig \ No newline at end of file diff --git a/src/Object/String.hpp b/src/Object/StringObject.hpp similarity index 94% rename from src/Object/String.hpp rename to src/Object/StringObject.hpp index 0db5e65..b4d698a 100644 --- a/src/Object/String.hpp +++ b/src/Object/StringObject.hpp @@ -1,5 +1,5 @@ /*! - @file src/Object/String.hpp + @file src/Object/StringObject.hpp @brief 字符串对象标识 @author PuqiAR (im@puqiar.top) @date 2026-02-19 diff --git a/src/Object/Struct.hpp b/src/Object/StructObject.hpp similarity index 94% rename from src/Object/Struct.hpp rename to src/Object/StructObject.hpp index 541c24c..a28610e 100644 --- a/src/Object/Struct.hpp +++ b/src/Object/StructObject.hpp @@ -1,6 +1,6 @@ /*! - @file src/Object/Struct.hpp - @brief 结构体类型 Struct定义 + @file src/Object/StructObject.hpp + @brief 结构体类型 StructObject 定义 @author PuqiAR (im@puqiar.top) @date 2026-02-19 */ diff --git a/src/Parser/Parser.hpp b/src/Parser/Parser.hpp index 4ff6572..d32725b 100644 --- a/src/Parser/Parser.hpp +++ b/src/Parser/Parser.hpp @@ -166,6 +166,9 @@ namespace Fig ParsingIf, ParsingWhile, ParsingFnDefStmt, + ParsingReturn, + ParsingBreak, + ParsingContinue, ParsingNamedTypeExpr, @@ -305,6 +308,9 @@ namespace Fig Result, Error> parseFnParams(); // 由 parseFnDefStmt或lambda调用 Result parseFnDefStmt(bool); // 由 parseStatement调用, 当前token为 func + Result parseReturnStmt(); // 由 parseStatement调用, 当前token为 return + // continue break直接由parseStatement一步解析 + Result parseStatement(); public: diff --git a/src/Parser/StmtParser.cpp b/src/Parser/StmtParser.cpp index 17e57c5..5b17ab1 100644 --- a/src/Parser/StmtParser.cpp +++ b/src/Parser/StmtParser.cpp @@ -357,7 +357,8 @@ namespace Fig { if (!currentToken().isIdentifier()) { - return std::unexpected(makeUnexpectTokenError("fn params", "param name", currentToken())); + return std::unexpected( + makeUnexpectTokenError("fn params", "param name", currentToken())); } } } @@ -418,13 +419,36 @@ namespace Fig { delete returnType; } - body = *bodyResult; + return std::unexpected(bodyResult.error()); } + body = *bodyResult; FnDefStmt *fnDef = new FnDefStmt(isPublic, name, params, returnType, body, location); return fnDef; } + Result + Parser::parseReturnStmt() // 由 parseStatement调用, 当前token为 return + { + StateProtector p(this, {State::ParsingReturn}); + + SourceLocation location = makeSourceLocation(consumeToken()); // consume `return` + auto result = parseExpression(); + if (!result) + { + return std::unexpected(result.error()); + } + + Expr *value = *result; + ReturnStmt *returnStmt = new ReturnStmt(value, location); + + if (!match(TokenType::Semicolon)) + { + return std::unexpected(makeExpectSemicolonError()); + } + return returnStmt; + } + Result Parser::parseStatement() { StateProtector p(this, {State::Standby}); @@ -471,6 +495,33 @@ namespace Fig return parseFnDefStmt(false); } + if (currentToken().type == TokenType::Return) + { + return parseReturnStmt(); + } + + if (match(TokenType::Break)) + { + SourceLocation location = makeSourceLocation(prevToken()); + if (!match(TokenType::Semicolon)) + { + return std::unexpected(makeExpectSemicolonError()); + } + BreakStmt *breakStmt = new BreakStmt(location); + return breakStmt; + } + + if (match(TokenType::Continue)) + { + SourceLocation location = makeSourceLocation(prevToken()); + if (!match(TokenType::Semicolon)) + { + return std::unexpected(makeExpectSemicolonError()); + } + ContinueStmt *continueStmt = new ContinueStmt(location); + return continueStmt; + } + if (isEOF) { return nullptr; diff --git a/src/Sema/Analyzer.cpp b/src/Sema/Analyzer.cpp index c39b9e0..d23c9e7 100644 --- a/src/Sema/Analyzer.cpp +++ b/src/Sema/Analyzer.cpp @@ -9,6 +9,29 @@ namespace Fig { + Result Analyzer::resolveType(TypeExpr *typeExpr) + { + 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; + } + Result Analyzer::analyzeVarDecl(VarDecl *stmt) { auto sym = env.Resolve(stmt->name); @@ -20,7 +43,7 @@ namespace Fig makeSourceLocation(stmt))); } - TypeTag initType = TypeTag::Any; + TypeInfo *initType = typeCtx.GetNull(); if (stmt->initExpr) { const auto &res = analyzeExpr(stmt->initExpr); @@ -31,23 +54,29 @@ namespace Fig initType = stmt->initExpr->resolvedType; } - TypeTag declaredType = TypeTag::Any; + TypeInfo *declaredType = typeCtx.GetAny(); if (stmt->typeSpecifier) { - // TODO: 解析类型定义 + auto result = resolveType(stmt->typeSpecifier); + if (!result) + { + return std::unexpected(result.error()); + } + + declaredType = *result; } if (stmt->isInfer) { declaredType = initType; } - else if (declaredType != TypeTag::Any && 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 '{}'", - magic_enum::enum_name(initType), + initType->name, stmt->name, - magic_enum::enum_name(declaredType)), + declaredType->name), "none", makeSourceLocation(stmt->initExpr))); } @@ -62,11 +91,12 @@ namespace Fig { return condRes; } - if (stmt->cond->resolvedType != TypeTag::Any && stmt->cond->resolvedType != TypeTag::Bool) + 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 `{}`", - magic_enum::enum_name(stmt->cond->resolvedType)), + std::format( + "if condition must be boolean, got `{}`", stmt->cond->resolvedType->name), "ensure condition is boolean", makeSourceLocation(stmt->cond))); } @@ -79,12 +109,12 @@ namespace Fig for (ElseIfStmt *elif : stmt->elifs) { auto condRes = analyzeExpr(elif->cond); - if (elif->cond->resolvedType != TypeTag::Any - && elif->cond->resolvedType != TypeTag::Bool) + if (elif->cond->resolvedType != typeCtx.GetAny() + && elif->cond->resolvedType != typeCtx.GetBool()) { return std::unexpected(Error(ErrorType::TypeError, std::format("else if condition must be boolean, got `{}`", - magic_enum::enum_name(elif->cond->resolvedType)), + elif->cond->resolvedType->name), "ensure condition is boolean", makeSourceLocation(elif->cond))); } @@ -114,11 +144,12 @@ namespace Fig return condRes; } - if (stmt->cond->resolvedType != TypeTag::Any && stmt->cond->resolvedType != TypeTag::Bool) + 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 `{}`", - magic_enum::enum_name(stmt->cond->resolvedType)), + std::format( + "while condition must be boolean, got `{}`", stmt->cond->resolvedType->name), "ensure condition is boolean", makeSourceLocation(stmt->cond))); } @@ -131,6 +162,138 @@ namespace Fig 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) + { + return std::unexpected(result.error()); + } + 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) + { + posParam->resolvedType = typeCtx.GetAny(); + if (posParam->type) + { + auto result = resolveType(posParam->type); + if (!result) + { + return std::unexpected(result.error()); + } + posParam->resolvedType = *result; + } + + 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 + { + // ... 其他参数解析 + } + } + + ReturnTypeProtector p(this, stmt->resolvedReturnType); + + auto bodyRes = analyzeStmt(stmt->body); + + env.LeaveScope(); + env.LeaveFunction(); + + if (!bodyRes) + { + return bodyRes; + } + return {}; + } + + Result Analyzer::analyzeReturnStmt(ReturnStmt *stmt) + { + if (!currentReturnType) + { + return std::unexpected(Error(ErrorType::SyntaxError, + "return outside function", + "remove `return ...`", + makeSourceLocation(stmt))); + } + auto result = analyzeExpr(stmt->value); + if (!result) + { + return result; + } + + TypeInfo *valueType = stmt->value->resolvedType; + if (currentReturnType != typeCtx.GetAny() && 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); @@ -146,7 +309,7 @@ namespace Fig expr->resolvedType = sym->type; expr->resolvedDepth = sym->depth; - expr->isGlobal = (sym->depth == 0); + expr->isGlobal = (sym->depth == 0); return {}; } @@ -161,16 +324,16 @@ namespace Fig if (!resR) return std::unexpected(resR.error()); - TypeTag lType = expr->left->resolvedType; - TypeTag rType = expr->right->resolvedType; + TypeInfo *lType = expr->left->resolvedType; + TypeInfo *rType = expr->right->resolvedType; switch (expr->op) { // 算术族 (+, -, *, /, **) case BinaryOperator::Add: - if (lType == TypeTag::String && rType == TypeTag::String) + if (lType == typeCtx.GetString() && rType == typeCtx.GetString()) { - expr->resolvedType = TypeTag::String; + expr->resolvedType = typeCtx.GetString(); break; } [[fallthrough]]; @@ -178,18 +341,18 @@ namespace Fig case BinaryOperator::Multiply: case BinaryOperator::Divide: case BinaryOperator::Power: - if (lType == TypeTag::Int && rType == TypeTag::Int) + if (lType == typeCtx.GetInt() && rType == typeCtx.GetInt()) { - expr->resolvedType = TypeTag::Int; + expr->resolvedType = typeCtx.GetInt(); } - else if ((lType == TypeTag::Int || lType == TypeTag::Double) - && (rType == TypeTag::Int || rType == TypeTag::Double)) + else if ((lType == typeCtx.GetInt() || lType == typeCtx.GetDouble()) + && (rType == typeCtx.GetInt() || rType == typeCtx.GetDouble())) { - expr->resolvedType = TypeTag::Double; + expr->resolvedType = typeCtx.GetDouble(); } - else if (lType == TypeTag::Any || rType == TypeTag::Any) + else if (lType == typeCtx.GetAny() || rType == typeCtx.GetAny()) { - expr->resolvedType = TypeTag::Any; + expr->resolvedType = typeCtx.GetAny(); } else { @@ -207,13 +370,13 @@ namespace Fig case BinaryOperator::BitXor: case BinaryOperator::ShiftLeft: case BinaryOperator::ShiftRight: - if (lType == TypeTag::Int && rType == TypeTag::Int) + if (lType == typeCtx.GetInt() && rType == typeCtx.GetInt()) { - expr->resolvedType = TypeTag::Int; + expr->resolvedType = typeCtx.GetInt(); } - else if (lType == TypeTag::Any || rType == TypeTag::Any) + else if (lType == typeCtx.GetAny() || rType == typeCtx.GetAny()) { - expr->resolvedType = TypeTag::Any; + expr->resolvedType = typeCtx.GetAny(); } else { @@ -224,7 +387,7 @@ namespace Fig } break; - // 比较族 (==, !=, <, >, <=, >=) + // 比较族 (==, !=, <, >, <=, >=) case BinaryOperator::Equal: case BinaryOperator::NotEqual: @@ -233,11 +396,11 @@ namespace Fig case BinaryOperator::LessEqual: case BinaryOperator::GreaterEqual: case BinaryOperator::Is: - if (lType != TypeTag::Any && rType != TypeTag::Any + if (lType != typeCtx.GetAny() && rType != typeCtx.GetAny() && lType != rType) // lType == rType放行 { - if (!((lType == TypeTag::Int && rType == TypeTag::Double) - || (lType == TypeTag::Double && rType == TypeTag::Int))) + if (!((lType == typeCtx.GetInt() && rType == typeCtx.GetDouble()) + || (lType == typeCtx.GetDouble() && rType == typeCtx.GetInt()))) { return std::unexpected(Error(ErrorType::TypeError, "cannot compare different types", @@ -250,19 +413,19 @@ namespace Fig // 如 1.2 is Int --> false // 1 is Int --> true - expr->resolvedType = TypeTag::Bool; + expr->resolvedType = typeCtx.GetBool(); break; // 逻辑族 (&&, ||) case BinaryOperator::LogicalAnd: case BinaryOperator::LogicalOr: - if (lType == TypeTag::Bool && rType == TypeTag::Bool) + if (lType == typeCtx.GetBool() && rType == typeCtx.GetBool()) { - expr->resolvedType = TypeTag::Bool; + expr->resolvedType = typeCtx.GetBool(); } - else if (lType == TypeTag::Any || rType == TypeTag::Any) + else if (lType == typeCtx.GetAny() || rType == typeCtx.GetAny()) { - expr->resolvedType = TypeTag::Bool; + expr->resolvedType = typeCtx.GetBool(); } else { @@ -294,9 +457,9 @@ namespace Fig // 类型匹配拦截 (纯赋值) if (expr->op == BinaryOperator::Assign) { - if (lType != TypeTag::Any && rType != TypeTag::Any && lType != rType) + if (lType != typeCtx.GetAny() && rType != typeCtx.GetAny() && lType != rType) { - if (!(lType == TypeTag::Double && rType == TypeTag::Int)) + if (!(lType == typeCtx.GetDouble() && rType == typeCtx.GetInt())) { // 允许 Int 赋给 Double return std::unexpected(Error(ErrorType::TypeError, "cannot assign value to variable of different type", @@ -310,7 +473,7 @@ namespace Fig // 成员访问 (.) case BinaryOperator::MemberAccess: - if (lType != TypeTag::Struct && lType != TypeTag::Any) + if (lType != typeCtx.GetStruct() && lType != typeCtx.GetAny()) { return std::unexpected(Error(ErrorType::TypeError, "member access requires a Struct object", @@ -319,14 +482,13 @@ namespace Fig } if (expr->right->type != AstType::IdentiExpr) { - return std::unexpected(Error( - ErrorType::SyntaxError, - std::format("expect field name after member access '.', got {}", expr->right->toString()), + return std::unexpected(Error(ErrorType::SyntaxError, + std::format("expect field name after member access '.', got {}", + expr->right->toString()), "none", - makeSourceLocation(expr->right) - )); + makeSourceLocation(expr->right))); } - expr->resolvedType = TypeTag::Any; + expr->resolvedType = typeCtx.GetAny(); break; default: @@ -373,6 +535,14 @@ namespace Fig return analyzeWhileStmt(static_cast(stmt)); } + case AstType::FnDefStmt: { + return analyzeFnDefStmt(static_cast(stmt)); + } + + case AstType::ReturnStmt: { + return analyzeReturnStmt(static_cast(stmt)); + } + // TODO: 其他语句分析 // default: @@ -396,30 +566,30 @@ namespace Fig switch (lit->token.type) { case TokenType::LiteralTrue: - case TokenType::LiteralFalse: lit->resolvedType = TypeTag::Bool; break; + case TokenType::LiteralFalse: lit->resolvedType = typeCtx.GetBool(); break; - case TokenType::LiteralNull: lit->resolvedType = TypeTag::Null; 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 = TypeTag::Double; + lit->resolvedType = typeCtx.GetDouble(); } else { - lit->resolvedType = TypeTag::Int; + lit->resolvedType = typeCtx.GetInt(); } break; } case TokenType::LiteralString: { - lit->resolvedType = TypeTag::String; + lit->resolvedType = typeCtx.GetString(); break; } default: { - lit->resolvedType = TypeTag::Any; + lit->resolvedType = typeCtx.GetAny(); break; } } @@ -435,7 +605,7 @@ namespace Fig default: // 对于还没实现的表达式,默认降级为 Any 防止崩溃 - expr->resolvedType = TypeTag::Any; + expr->resolvedType = typeCtx.GetAny(); return {}; } } diff --git a/src/Sema/Analyzer.hpp b/src/Sema/Analyzer.hpp index 3aa2d66..0d50b87 100644 --- a/src/Sema/Analyzer.hpp +++ b/src/Sema/Analyzer.hpp @@ -10,27 +10,50 @@ #include #include - #include #include - namespace Fig { class Analyzer { private: - Environment env; + Environment env; SourceManager &manager; - SourceLocation makeSourceLocation(AstNode *ast, std::source_location loc = std::source_location::current()) + TypeContext typeCtx; + + TypeInfo *currentReturnType = nullptr; // 正在分析的函数,预期返回类型 + + struct ReturnTypeProtector { - return SourceLocation( - ast->location.sp, + Analyzer *analyzer; + TypeInfo *prevCurrentReturnType; + + [[nodiscard]] + ReturnTypeProtector(Analyzer *_analyzer, TypeInfo *current) : + analyzer(_analyzer), prevCurrentReturnType(_analyzer->currentReturnType) + { + analyzer->currentReturnType = current; + } + + ~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() - ); + loc.function_name()); } bool isValidLvalue(Expr *expr) @@ -54,18 +77,23 @@ namespace Fig 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 analyzeStmt(Stmt *); Result analyzeExpr(Expr *); + public: Result Analyze(Program *); - Analyzer(SourceManager &_manager) : manager(_manager) {} + Analyzer(SourceManager &_manager) : manager(_manager), typeCtx() {} }; }; // namespace Fig \ No newline at end of file diff --git a/src/Sema/Environment.hpp b/src/Sema/Environment.hpp index 077100e..59afcd7 100644 --- a/src/Sema/Environment.hpp +++ b/src/Sema/Environment.hpp @@ -19,11 +19,11 @@ namespace Fig // 记录在 Analyzer 中的符号元数据 struct Symbol { - String name; - TypeTag type; - bool isPublic; - int depth; // 词法作用域深度 - bool isConstant; // 是否是 const 声明的不可变常量 (用于报错: 尝试修改常量) + String name; + TypeInfo *type; + bool isPublic; + int depth; // 词法作用域深度 + bool isConstant; // 是否是 const 声明的不可变常量 (用于报错: 尝试修改常量) int localId = -1; // Analyzer 虚拟槽位分配 }; @@ -111,7 +111,7 @@ namespace Fig // 符号操作 // 注册符号, 返回分配的 localId。调用前内部执行同级作用域重定义断言 - int Define(const String &name, TypeTag type, bool isPublic, bool isConst) + int Define(const String &name, TypeInfo *type, bool isPublic, bool isConst) { for (auto it = symbols.rbegin(); it != symbols.rend(); ++it) { diff --git a/src/Sema/Type.hpp b/src/Sema/Type.hpp index e44be85..49d11fd 100644 --- a/src/Sema/Type.hpp +++ b/src/Sema/Type.hpp @@ -1,12 +1,13 @@ /*! @file src/Sema/Type.hpp - @brief 前端类型检查的类型定义 + @brief 前端类型检查的类型定义和类型驻留池 @author PuqiAR (im@puqiar.top) @date 2026-02-23 */ #pragma once +#include #include namespace Fig @@ -23,6 +24,113 @@ namespace Fig Struct, }; - // TODO: 复杂类型的推导(泛型,结构体) - // 添加 TypeInfo 结构体,目前先用 TypeTag -}; \ No newline at end of file + struct TypeInfo + { + TypeTag tag; + String name; // 完整路径序列化, 如 Int, std.file.File + + bool isAny() const + { + return tag == TypeTag::Any; + } + }; + + // 全局唯一类型驻留池 + 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; + } + + 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; + } + }; +}; // namespace Fig \ No newline at end of file