From bb23ddf9fa232c4a40bc00137a243ce8a8ff7415 Mon Sep 17 00:00:00 2001 From: PuqiAR Date: Thu, 26 Feb 2026 14:41:41 +0800 Subject: [PATCH] =?UTF-8?q?feat:=20=E6=B7=BB=E5=8A=A0=E5=87=BD=E6=95=B0?= =?UTF-8?q?=E5=AE=9A=E4=B9=89=E5=92=8C=E7=B1=BB=E5=9E=8B=E8=A1=A8=E8=BE=BE?= =?UTF-8?q?=E5=BC=8F=E6=94=AF=E6=8C=81=EF=BC=8C=E9=87=8D=E6=9E=84=E8=A7=A3?= =?UTF-8?q?=E6=9E=90=E5=99=A8=E4=BB=A5=E5=A4=84=E7=90=86=E6=96=B0=E8=AF=AD?= =?UTF-8?q?=E6=B3=95(=E5=87=BD=E6=95=B0=E5=AE=9A=E4=B9=89)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/Ast/Ast.hpp | 4 +- src/Ast/Base.hpp | 17 +++- src/Ast/Stmt/FnDefStmt.hpp | 100 ++++++++++++++++++++++ src/Ast/Stmt/VarDecl.hpp | 4 +- src/Ast/TypeExpr.hpp | 36 ++++++++ src/Parser/Parser.hpp | 13 +++ src/Parser/StmtParser.cpp | 152 ++++++++++++++++++++++++++++++++-- src/Parser/TypeExprParser.cpp | 56 +++++++++++++ xmake.lua | 5 ++ 9 files changed, 376 insertions(+), 11 deletions(-) create mode 100644 src/Ast/Stmt/FnDefStmt.hpp create mode 100644 src/Ast/TypeExpr.hpp create mode 100644 src/Parser/TypeExprParser.cpp diff --git a/src/Ast/Ast.hpp b/src/Ast/Ast.hpp index d533941..0946821 100644 --- a/src/Ast/Ast.hpp +++ b/src/Ast/Ast.hpp @@ -15,6 +15,8 @@ #include #include +#include #include #include -#include \ No newline at end of file +#include +#include \ No newline at end of file diff --git a/src/Ast/Base.hpp b/src/Ast/Base.hpp index 27b046e..ca0d813 100644 --- a/src/Ast/Base.hpp +++ b/src/Ast/Base.hpp @@ -38,6 +38,12 @@ namespace Fig IfStmt, // If语句 ElseIfStmt, // ElseIf语句,不准悬空,平铺式else if WhileStmt, // while语句 + FnDefStmt, // func函数定义语句 + + /* Type Expressions */ + TypeExpr, // 基类 + NamedTypeExpr, // 命名类型,支持namespace, std.file这样的 + // 泛型等... }; struct AstNode { @@ -45,7 +51,16 @@ namespace Fig SourceLocation location; virtual String toString() const = 0; - virtual ~AstNode(){}; + virtual ~AstNode() {}; + }; + + struct TypeExpr : public AstNode + { + TypeExpr() + { + type = AstType::TypeExpr; + } + virtual ~TypeExpr() = default; }; struct Program; diff --git a/src/Ast/Stmt/FnDefStmt.hpp b/src/Ast/Stmt/FnDefStmt.hpp new file mode 100644 index 0000000..0a11a94 --- /dev/null +++ b/src/Ast/Stmt/FnDefStmt.hpp @@ -0,0 +1,100 @@ +/*! + @file src/Ast/Stmt/FnDefStmt.hpp + @brief FnDefStmt定义 + @author PuqiAR (im@puqiar.top) + @date 2026-02-25 +*/ + +#pragma once + +#include + +namespace Fig +{ + struct Param + { + String name; + SourceLocation location; + + virtual String toString() const = 0; + }; + + struct PosParam final : public Param + { + TypeExpr *type; + 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() : "") + ); + } + }; + + /* + (public) func foo([name: (type) (= default value)]) (-> return type) + { + ... + } + + */ + + struct FnDefStmt final : public Stmt + { + String name; + DynArray params; + TypeExpr *returnType; + BlockStmt *body; + + FnDefStmt() + { + type = AstType::FnDefStmt; + } + + 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() + ); + } + }; +}; // namespace Fig \ No newline at end of file diff --git a/src/Ast/Stmt/VarDecl.hpp b/src/Ast/Stmt/VarDecl.hpp index 2d94883..5fa31c0 100644 --- a/src/Ast/Stmt/VarDecl.hpp +++ b/src/Ast/Stmt/VarDecl.hpp @@ -15,7 +15,7 @@ namespace Fig struct VarDecl final : public Stmt { String name; - Expr *typeSpecifier; + TypeExpr *typeSpecifier; bool isInfer; // 是否用了 := 类型推断 Expr *initExpr; @@ -26,7 +26,7 @@ namespace Fig type = AstType::VarDecl; } - VarDecl(bool _isPublic, String _name, Expr *_typeSpecifier, bool _isInfer, Expr *_initExpr, SourceLocation _location) : + VarDecl(bool _isPublic, String _name, TypeExpr *_typeSpecifier, bool _isInfer, Expr *_initExpr, SourceLocation _location) : name(std::move(_name)), typeSpecifier(_typeSpecifier), isInfer(_isInfer), diff --git a/src/Ast/TypeExpr.hpp b/src/Ast/TypeExpr.hpp new file mode 100644 index 0000000..60e1e5d --- /dev/null +++ b/src/Ast/TypeExpr.hpp @@ -0,0 +1,36 @@ +/*! + @file src/Ast/TypeExpr.hpp + @brief TypeExpr定义 + @author PuqiAR (im@puqiar.top) + @date 2026-02-25 +*/ + +#pragma once + +#include + +namespace Fig +{ + + struct NamedTypeExpr final : public TypeExpr + { + DynArray path; // {"std", "file"} etc. + + NamedTypeExpr() + { + type = AstType::NamedTypeExpr; + } + + NamedTypeExpr(DynArray _path, SourceLocation _location) : + path(std::move(_path)) + { + type = AstType::NamedTypeExpr; + location = std::move(_location); + } + + virtual String toString() const override + { + return std::format("", path); + } + }; +}; \ No newline at end of file diff --git a/src/Parser/Parser.hpp b/src/Parser/Parser.hpp index c325077..4ff6572 100644 --- a/src/Parser/Parser.hpp +++ b/src/Parser/Parser.hpp @@ -165,6 +165,9 @@ namespace Fig ParsingVarDecl, ParsingIf, ParsingWhile, + ParsingFnDefStmt, + + ParsingNamedTypeExpr, } type = StateType::Standby; std::unordered_set stopAt = {}; @@ -273,6 +276,12 @@ namespace Fig magic_enum::enum_name(currentState().type).data()); } + /* TypeExpressions */ + + Result parseNamedTypeExpr(); // 当前token为identifier + + Result parseTypeExpr(); + /* Expressions */ Result parseLiteralExpr(); // 当前token为literal时调用 Result parseIdentiExpr(); // 当前token为Identifier调用 @@ -292,6 +301,10 @@ namespace Fig Result parseVarDecl(bool); // 由 parseStatement调用, 当前token为 var Result parseIfStmt(); // 由 parseStatement调用, 当前token为 if Result parseWhileStmt(); // 由 parseStatement调用, 当前token为 while + + Result, Error> parseFnParams(); // 由 parseFnDefStmt或lambda调用 + Result parseFnDefStmt(bool); // 由 parseStatement调用, 当前token为 func + Result parseStatement(); public: diff --git a/src/Parser/StmtParser.cpp b/src/Parser/StmtParser.cpp index 785af60..17e57c5 100644 --- a/src/Parser/StmtParser.cpp +++ b/src/Parser/StmtParser.cpp @@ -49,11 +49,11 @@ namespace Fig const String &name = srcManager.GetSub(currentToken().index, currentToken().length); consumeToken(); // consume name - Expr *typeSpeicifer = nullptr; + TypeExpr *typeSpeicifer = nullptr; if (match(TokenType::Colon)) // `:` { - SET_STOP_AT(TokenType::Walrus, TokenType::Assign); - auto result = parseExpression(0); + // SET_STOP_AT(TokenType::Walrus, TokenType::Assign); + auto result = parseTypeExpr(); if (!result) { return std::unexpected(result.error()); @@ -295,6 +295,136 @@ namespace Fig return whileStmt; } + Result, Error> Parser::parseFnParams() // 由 parseFnDefStmt或lambda调用 + { + StateProtector p(this, {State::ParsingFnDefStmt}); + + const Token &lpToken = consumeToken(); // consume `(` + DynArray params; + + while (true) + { + if (isEOF) + { + return std::unexpected(Error(ErrorType::SyntaxError, + "unclosed parenthese in function parameters", + "insert ')'", + makeSourceLocation(lpToken))); + } + if (match(TokenType::RightParen)) + { + break; + } + + const Token &nToken = consumeToken(); + SourceLocation location = makeSourceLocation(nToken); + const String &name = srcManager.GetSub(nToken.index, nToken.length); + + // TODO: 支持剩余参数解析... + + TypeExpr *type = nullptr; + if (match(TokenType::Colon)) // : + { + auto result = parseTypeExpr(); + if (!result) + { + return std::unexpected(result.error()); + } + type = *result; + } + + Expr *defaultValue = nullptr; + + if (match(TokenType::Assign)) // = + { + 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; + } + + PosParam *posParam = new PosParam(name, type, defaultValue, location); + params.push_back(posParam); + + if (match(TokenType::Comma)) + { + if (!currentToken().isIdentifier()) + { + return std::unexpected(makeUnexpectTokenError("fn params", "param name", currentToken())); + } + } + } + return params; + } + + Result Parser::parseFnDefStmt( + bool isPublic) // 由 parseStatement调用, 当前token为 func + { + SourceLocation location = makeSourceLocation( + consumeToken()); // 无论是否加了public, location都设置为 func token (我懒 :D) + + if (!currentToken().isIdentifier()) + { + return std::unexpected( + makeUnexpectTokenError("fn def stmt", "function name", currentToken())); + } + const Token &nameToken = consumeToken(); // consume name + const String &name = srcManager.GetSub(nameToken.index, nameToken.length); + + if (currentToken().type != TokenType::LeftParen) + { + return std::unexpected( + makeUnexpectTokenError("fn def stmt", "lparen '('", currentToken())); + } + + DynArray params; + + auto paraResult = parseFnParams(); + if (!paraResult) + { + return std::unexpected(paraResult.error()); + } + params = *paraResult; + + TypeExpr *returnType = nullptr; + if (match(TokenType::RightArrow)) // -> + { + auto result = parseTypeExpr(); + if (!result) + { + return std::unexpected(result.error()); + } + returnType = *result; + } + + if (currentToken().type != TokenType::LeftBrace) + { + return std::unexpected( + makeUnexpectTokenError("fn def stmt", "function body '{'", currentToken())); + } + BlockStmt *body = nullptr; + auto bodyResult = parseBlockStmt(); + + if (!bodyResult) + { + if (returnType) + { + delete returnType; + } + body = *bodyResult; + } + + FnDefStmt *fnDef = new FnDefStmt(isPublic, name, params, returnType, body, location); + return fnDef; + } + Result Parser::parseStatement() { StateProtector p(this, {State::Standby}); @@ -306,11 +436,14 @@ namespace Fig { return parseVarDecl(true); } - else + + if (currentToken().type == TokenType::Function) { - return std::unexpected( - makeUnexpectTokenError("public", "var/const/func/struct", currentToken())); + return parseFnDefStmt(true); } + + return std::unexpected( + makeUnexpectTokenError("public", "var/const/func/struct", currentToken())); } if (currentToken().type == TokenType::LeftBrace) @@ -333,11 +466,16 @@ namespace Fig return parseWhileStmt(); } + if (currentToken().type == TokenType::Function) + { + return parseFnDefStmt(false); + } + if (isEOF) { return nullptr; } - + const auto &expr_result = parseExpression(); if (!expr_result) { diff --git a/src/Parser/TypeExprParser.cpp b/src/Parser/TypeExprParser.cpp new file mode 100644 index 0000000..9556e6f --- /dev/null +++ b/src/Parser/TypeExprParser.cpp @@ -0,0 +1,56 @@ +/*! + @file src/Parser/TypeExprParser.cpp + @brief 类型表达式解析器实现 + @author PuqiAR (im@puqiar.top) + @date 2026-02-25 +*/ + +#pragma once + +#include + +namespace Fig +{ + Result Parser::parseNamedTypeExpr() // 当前token为identifier + { + 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); + + if (match(TokenType::Dot)) + { + if (!currentToken().isIdentifier()) + { + return std::unexpected( + makeUnexpectTokenError("named type expr", "identifier", currentToken())); + } + } + else + { + break; + } + } + NamedTypeExpr *namedTypeExpr = new NamedTypeExpr(path, location); + return namedTypeExpr; + } + + Result Parser::parseTypeExpr() + { + // TODO: 泛型表达式解析 + if (currentToken().isIdentifier()) + { + return parseNamedTypeExpr(); + } + else + { + return std::unexpected(makeUnexpectTokenError("type expr", "name/...", currentToken())); + } + } +}; // namespace Fig \ No newline at end of file diff --git a/xmake.lua b/xmake.lua index b9c36a6..a102f1b 100644 --- a/xmake.lua +++ b/xmake.lua @@ -45,6 +45,7 @@ target("ParserTest") 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") @@ -62,6 +63,7 @@ target("AnalyzerTest") 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/Analyzer.cpp") @@ -76,6 +78,7 @@ target("CompilerTest") 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/Object/Object.cpp") @@ -97,6 +100,7 @@ target("LSP") 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/Analyzer.cpp") @@ -114,6 +118,7 @@ target("Fig") 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/Object/Object.cpp")