diff --git a/src/Ast/Ast.hpp b/src/Ast/Ast.hpp index 347905a..e8f5b58 100644 --- a/src/Ast/Ast.hpp +++ b/src/Ast/Ast.hpp @@ -16,6 +16,8 @@ #include #include #include +#include +#include #include #include @@ -24,6 +26,8 @@ #include #include #include +#include +#include #include #include #include \ No newline at end of file diff --git a/src/Ast/Base.hpp b/src/Ast/Base.hpp index 746b28a..9f98c1c 100644 --- a/src/Ast/Base.hpp +++ b/src/Ast/Base.hpp @@ -31,6 +31,8 @@ namespace Fig MemberExpr, // obj.prop NewExpr, // new Point{} LambdaExpr, + TernaryExpr, // cond ? then : else + PostfixExpr, // expr++ / expr-- /* Statements */ ExprStmt, @@ -45,12 +47,16 @@ namespace Fig ReturnStmt, BreakStmt, ContinueStmt, + ForStmt, // for loop + ImportStmt, // import /* Type Expressions */ TypeExpr, - NamedTypeExpr, - NullableTypeExpr, + NamedTypeExpr, // 废弃,用 IdentiExpr/MemberExpr/ApplyExpr 替代 + NullableTypeExpr, // 废弃,用 NullableExpr 替代 FnTypeExpr, + ApplyExpr, // 泛型实例化: List + NullableExpr, // 可空后缀: Int? }; struct AstNode @@ -62,15 +68,6 @@ namespace Fig virtual ~AstNode() {}; }; - struct TypeExpr : public AstNode - { - TypeExpr() - { - type = AstType::TypeExpr; - } - virtual ~TypeExpr() = default; - }; - struct Expr : public AstNode { // 语义分析后填充 @@ -116,4 +113,55 @@ namespace Fig return ""; } }; + + // --- Type Expressions (inherit Expr — 类型即值) --- + + struct TypeExpr : public Expr + { + TypeExpr() { type = AstType::TypeExpr; } + virtual ~TypeExpr() = default; + }; + + // ApplyExpr: 泛型实例化,List → ApplyExpr(base, [Int]) + struct ApplyExpr final : public Expr + { + Expr *base; // 基础类型表达式 + DynArray args; // 泛型参数 + + ApplyExpr() { type = AstType::ApplyExpr; } + ApplyExpr(Expr *_base, DynArray _args, SourceLocation _loc) : + base(_base), args(std::move(_args)) + { + type = AstType::ApplyExpr; + location = std::move(_loc); + } + virtual String toString() const override + { + String s = base->toString() + "<"; + for (size_t i = 0; i < args.size(); ++i) + { + if (i) s += ", "; + s += args[i]->toString(); + } + s += ">"; + return s; + } + }; + + // NullableExpr: 可空后缀 Int? → NullableExpr(Int) + struct NullableExpr final : public Expr + { + Expr *inner; + + NullableExpr() { type = AstType::NullableExpr; } + NullableExpr(Expr *_inner, SourceLocation _loc) : inner(_inner) + { + type = AstType::NullableExpr; + location = std::move(_loc); + } + virtual String toString() const override + { + return inner->toString() + "?"; + } + }; } // namespace Fig diff --git a/src/Ast/Expr/LambdaExpr.hpp b/src/Ast/Expr/LambdaExpr.hpp index f418812..4e5f553 100644 --- a/src/Ast/Expr/LambdaExpr.hpp +++ b/src/Ast/Expr/LambdaExpr.hpp @@ -15,7 +15,7 @@ namespace Fig // func (params) [-> return type] ([=> expr] / [ {stmt} ]) DynArray params; - TypeExpr *returnType; + Expr *returnType; AstNode *body; // expr/blockstmt bool isExprBody; @@ -28,7 +28,7 @@ namespace Fig LambdaExpr( DynArray _params, - TypeExpr *_returnType, + Expr *_returnType, AstNode *_body, bool _isExprBody, SourceLocation _location) : diff --git a/src/Ast/Expr/NewExpr.hpp b/src/Ast/Expr/NewExpr.hpp index 29b785d..b52bf1f 100644 --- a/src/Ast/Expr/NewExpr.hpp +++ b/src/Ast/Expr/NewExpr.hpp @@ -18,14 +18,14 @@ namespace Fig String name; Expr *value; }; - TypeExpr *typeExpr; + Expr *typeExpr; DynArray args; NewExpr() { type = AstType::NewExpr; } - NewExpr(TypeExpr *_te, DynArray _args, SourceLocation _loc) : + NewExpr(Expr *_te, DynArray _args, SourceLocation _loc) : typeExpr(_te), args(std::move(_args)) { type = AstType::NewExpr; diff --git a/src/Ast/Expr/PostfixExpr.hpp b/src/Ast/Expr/PostfixExpr.hpp new file mode 100644 index 0000000..6812e3e --- /dev/null +++ b/src/Ast/Expr/PostfixExpr.hpp @@ -0,0 +1,35 @@ +/*! + @file src/Ast/Expr/PostfixExpr.hpp + @brief expr++ / expr-- + @author PuqiAR (im@puqiar.top) + @date 2026-06-06 +*/ + +#pragma once + +#include +#include + +namespace Fig +{ + struct PostfixExpr final : public Expr + { + UnaryOperator op; + Expr *operand; + + PostfixExpr() { type = AstType::PostfixExpr; } + + PostfixExpr(UnaryOperator _op, Expr *_operand) : + op(_op), operand(_operand) + { + type = AstType::PostfixExpr; + location = _operand->location; + } + + virtual String toString() const override + { + return std::format("", + operand->toString(), magic_enum::enum_name(op)); + } + }; +} // namespace Fig diff --git a/src/Ast/Expr/TernaryExpr.hpp b/src/Ast/Expr/TernaryExpr.hpp new file mode 100644 index 0000000..8a32b99 --- /dev/null +++ b/src/Ast/Expr/TernaryExpr.hpp @@ -0,0 +1,35 @@ +/*! + @file src/Ast/Expr/TernaryExpr.hpp + @brief cond ? then : else + @author PuqiAR (im@puqiar.top) + @date 2026-06-06 +*/ + +#pragma once + +#include + +namespace Fig +{ + struct TernaryExpr final : public Expr + { + Expr *cond; + Expr *thenExpr; + Expr *elseExpr; + + TernaryExpr() { type = AstType::TernaryExpr; } + + TernaryExpr(Expr *_cond, Expr *_then, Expr *_else, SourceLocation _loc) : + cond(_cond), thenExpr(_then), elseExpr(_else) + { + type = AstType::TernaryExpr; + location = std::move(_loc); + } + + virtual String toString() const override + { + return std::format("", + cond->toString(), thenExpr->toString(), elseExpr->toString()); + } + }; +} // namespace Fig diff --git a/src/Ast/Operator.cpp b/src/Ast/Operator.cpp index bbc8e3a..67b8ee1 100644 --- a/src/Ast/Operator.cpp +++ b/src/Ast/Operator.cpp @@ -16,6 +16,8 @@ namespace Fig {TokenType::Minus, UnaryOperator::Negate}, {TokenType::Not, UnaryOperator::Not}, {TokenType::Ampersand, UnaryOperator::AddressOf}, + {TokenType::DoublePlus, UnaryOperator::Increment}, + {TokenType::DoubleMinus, UnaryOperator::Decrement}, }; return unaryOpMap; } @@ -40,6 +42,8 @@ namespace Fig {TokenType::And, BinaryOperator::LogicalAnd}, {TokenType::Or, BinaryOperator::LogicalOr}, + {TokenType::DoubleAmpersand, BinaryOperator::LogicalAnd}, + {TokenType::DoublePipe, BinaryOperator::LogicalOr}, {TokenType::Power, BinaryOperator::Power}, @@ -49,6 +53,7 @@ namespace Fig {TokenType::AsteriskEqual, BinaryOperator::MultiplyAssign}, {TokenType::SlashEqual, BinaryOperator::DivideAssign}, {TokenType::PercentEqual, BinaryOperator::ModuloAssign}, + {TokenType::Caret, BinaryOperator::BitXor}, {TokenType::CaretEqual, BinaryOperator::BitXorAssign}, {TokenType::Pipe, BinaryOperator::BitOr}, @@ -56,7 +61,7 @@ namespace Fig {TokenType::ShiftLeft, BinaryOperator::ShiftLeft}, {TokenType::ShiftRight, BinaryOperator::ShiftRight}, - {TokenType::Dot, BinaryOperator::MemberAccess}, + {TokenType::As, BinaryOperator::As}, }; return binaryOpMap; } @@ -78,6 +83,8 @@ namespace Fig {UnaryOperator::Negate, 20001}, {UnaryOperator::Not, 20001}, {UnaryOperator::AddressOf, 20001}, + {UnaryOperator::Increment, 20001}, + {UnaryOperator::Decrement, 20001}, }; return unbpm; } @@ -109,6 +116,7 @@ namespace Fig {BinaryOperator::GreaterEqual, 2100}, {BinaryOperator::Is, 2100}, + {BinaryOperator::As, 2100}, {BinaryOperator::ShiftLeft, 3000}, {BinaryOperator::ShiftRight, 3000}, @@ -117,10 +125,9 @@ namespace Fig {BinaryOperator::Subtract, 4000}, {BinaryOperator::Multiply, 4500}, {BinaryOperator::Divide, 4500}, + {BinaryOperator::Modulo, 4500}, {BinaryOperator::Power, 5000}, - - {BinaryOperator::MemberAccess, 40001}, }; return bnbpm; } @@ -153,6 +160,8 @@ namespace Fig case BinaryOperator::BitXorAssign: case BinaryOperator::Power: return GetBinaryOpLBp(op) - 1; + case BinaryOperator::As: return GetBinaryOpLBp(op) + 1; + default: /* 左结合, 左绑定力 < 右 diff --git a/src/Ast/Operator.hpp b/src/Ast/Operator.hpp index 4f36a41..f227d42 100644 --- a/src/Ast/Operator.hpp +++ b/src/Ast/Operator.hpp @@ -20,6 +20,8 @@ namespace Fig Negate, // 取反 - Not, // 逻辑非 ! / not AddressOf, // 取引用 & + Increment, // ++ + Decrement, // -- Count // 哨兵,(int) Count 获得运算符数量(注意,enum必须从 0 开始且不中断) }; @@ -60,6 +62,8 @@ namespace Fig ShiftLeft, // 左移 ShiftRight, // 右移 + As, // as + // 成员访问 MemberAccess, // . diff --git a/src/Ast/Stmt/FnDefStmt.hpp b/src/Ast/Stmt/FnDefStmt.hpp index d5ab75f..7736bcc 100644 --- a/src/Ast/Stmt/FnDefStmt.hpp +++ b/src/Ast/Stmt/FnDefStmt.hpp @@ -11,34 +11,34 @@ namespace Fig { struct Param : public AstNode { - String name; - TypeExpr *typeSpecifier; - Expr *defaultValue; - Type resolvedType; + String name; + Expr *typeSpecifier; + Expr *defaultValue; + Type resolvedType; Param() { type = AstType::AstNode; } virtual ~Param() = default; }; struct PosParam final : public Param { - PosParam(String _n, TypeExpr *_ts, Expr *_dv, SourceLocation _loc) { + PosParam(String _n, Expr *_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; + String name; DynArray params; - TypeExpr *returnTypeSpecifier; - BlockStmt *body; - Type resolvedReturnType; - Symbol *resolvedSymbol = nullptr; // 连接物理符号 + Expr *returnTypeSpecifier; + BlockStmt *body; + Type resolvedReturnType; + Symbol *resolvedSymbol = nullptr; // 连接物理符号 int protoIndex = -1; // 在CompiledModule扁平化protos的下标 DynArray upvalues; FnDefStmt() { type = AstType::FnDefStmt; } - FnDefStmt(bool _p, String _n, DynArray _pa, TypeExpr *_rt, BlockStmt *_b, SourceLocation _loc) + FnDefStmt(bool _p, String _n, DynArray _pa, Expr *_rt, BlockStmt *_b, SourceLocation _loc) : name(std::move(_n)), params(std::move(_pa)), returnTypeSpecifier(_rt), body(_b) { type = AstType::FnDefStmt; isPublic = _p; location = std::move(_loc); diff --git a/src/Ast/Stmt/ForStmt.hpp b/src/Ast/Stmt/ForStmt.hpp new file mode 100644 index 0000000..718d346 --- /dev/null +++ b/src/Ast/Stmt/ForStmt.hpp @@ -0,0 +1,32 @@ +/*! + @file src/Ast/Stmt/ForStmt.hpp + @brief for loop + @author PuqiAR (im@puqiar.top) + @date 2026-06-06 +*/ + +#pragma once + +#include + +namespace Fig +{ + struct ForStmt final : public Stmt + { + Stmt *init; + Expr *cond; + Expr *step; + BlockStmt *body; + + ForStmt() { type = AstType::ForStmt; } + + ForStmt(Stmt *_init, Expr *_cond, Expr *_step, BlockStmt *_body, SourceLocation _loc) : + init(_init), cond(_cond), step(_step), body(_body) + { + type = AstType::ForStmt; + location = std::move(_loc); + } + + virtual String toString() const override { return ""; } + }; +} // namespace Fig diff --git a/src/Ast/Stmt/ImplStmt.hpp b/src/Ast/Stmt/ImplStmt.hpp index 73af617..12d9b3c 100644 --- a/src/Ast/Stmt/ImplStmt.hpp +++ b/src/Ast/Stmt/ImplStmt.hpp @@ -11,11 +11,11 @@ namespace Fig { struct ImplStmt final : public Stmt { - TypeExpr *interfaceType; - TypeExpr *structType; + Expr *interfaceType; + Expr *structType; DynArray methods; - ImplStmt(TypeExpr *_it, TypeExpr *_st, DynArray _m, SourceLocation _loc) : + ImplStmt(Expr *_it, Expr *_st, DynArray _m, SourceLocation _loc) : interfaceType(_it), structType(_st), methods(std::move(_m)) { type = AstType::ImplStmt; diff --git a/src/Ast/Stmt/ImportStmt.hpp b/src/Ast/Stmt/ImportStmt.hpp new file mode 100644 index 0000000..ec8230a --- /dev/null +++ b/src/Ast/Stmt/ImportStmt.hpp @@ -0,0 +1,33 @@ +/*! + @file src/Ast/Stmt/ImportStmt.hpp + @brief import + @author PuqiAR (im@puqiar.top) + @date 2026-06-06 +*/ + +#pragma once + +#include + +namespace Fig +{ + struct ImportStmt final : public Stmt + { + String path; + bool isFileImport; + + ImportStmt() { type = AstType::ImportStmt; } + + ImportStmt(String _path, bool _isFileImport, SourceLocation _loc) : + path(std::move(_path)), isFileImport(_isFileImport) + { + type = AstType::ImportStmt; + location = std::move(_loc); + } + + virtual String toString() const override + { + return std::format("", path, isFileImport ? " [file]" : ""); + } + }; +} // namespace Fig diff --git a/src/Ast/Stmt/InterfaceDefStmt.hpp b/src/Ast/Stmt/InterfaceDefStmt.hpp index 52d442c..f6e333f 100644 --- a/src/Ast/Stmt/InterfaceDefStmt.hpp +++ b/src/Ast/Stmt/InterfaceDefStmt.hpp @@ -16,8 +16,8 @@ namespace Fig struct Method { String name; - DynArray params; - TypeExpr *retType; + DynArray params; + Expr *retType; SourceLocation location; }; diff --git a/src/Ast/Stmt/StructDefStmt.hpp b/src/Ast/Stmt/StructDefStmt.hpp index edf2add..56a2030 100644 --- a/src/Ast/Stmt/StructDefStmt.hpp +++ b/src/Ast/Stmt/StructDefStmt.hpp @@ -17,7 +17,7 @@ namespace Fig bool typeInfer; String name; - TypeExpr *type; + Expr *type; Expr *initExpr; }; bool isPublic; diff --git a/src/Ast/Stmt/VarDecl.hpp b/src/Ast/Stmt/VarDecl.hpp index 5fa31c0..78a67e4 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; - TypeExpr *typeSpecifier; + Expr *typeSpecifier; bool isInfer; // 是否用了 := 类型推断 Expr *initExpr; @@ -26,7 +26,7 @@ namespace Fig type = AstType::VarDecl; } - VarDecl(bool _isPublic, String _name, TypeExpr *_typeSpecifier, bool _isInfer, Expr *_initExpr, SourceLocation _location) : + VarDecl(bool _isPublic, String _name, Expr *_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 index 82c68d0..9615009 100644 --- a/src/Ast/TypeExpr.hpp +++ b/src/Ast/TypeExpr.hpp @@ -12,13 +12,13 @@ namespace Fig struct NamedTypeExpr final : public TypeExpr { DynArray path; - DynArray arguments; + DynArray arguments; NamedTypeExpr() { type = AstType::NamedTypeExpr; } - NamedTypeExpr(DynArray _p, DynArray _args, SourceLocation _loc) : + NamedTypeExpr(DynArray _p, DynArray _args, SourceLocation _loc) : path(std::move(_p)), arguments(std::move(_args)) { type = AstType::NamedTypeExpr; @@ -51,9 +51,9 @@ namespace Fig struct NullableTypeExpr final : public TypeExpr { - TypeExpr *inner; + Expr *inner; - NullableTypeExpr(TypeExpr *_inner, SourceLocation _loc) : inner(_inner) + NullableTypeExpr(Expr *_inner, SourceLocation _loc) : inner(_inner) { type = AstType::NullableTypeExpr; location = std::move(_loc); @@ -69,10 +69,10 @@ namespace Fig { // func (paratypes...) -> return_type - DynArray paraTypes; - TypeExpr *returnType; + DynArray paraTypes; + Expr *returnType; - FnTypeExpr(DynArray _paraTypes, TypeExpr *_returnType) : + FnTypeExpr(DynArray _paraTypes, Expr *_returnType) : paraTypes(std::move(_paraTypes)), returnType(_returnType) { type = AstType::FnTypeExpr; diff --git a/src/Compiler/ExprCompiler.cpp b/src/Compiler/ExprCompiler.cpp index ab6a1a9..9b6d701 100644 --- a/src/Compiler/ExprCompiler.cpp +++ b/src/Compiler/ExprCompiler.cpp @@ -1,6 +1,6 @@ /*! @file src/Compiler/ExprCompiler.cpp - @brief 表达式编译器实现:水位线控制Register与零拷贝复用机制 + @brief 表达式编译 */ #include @@ -167,7 +167,7 @@ namespace Fig if (sym->location == SymbolLocation::Local) { - // 零拷贝直读:如果是临时求值,直接返回变量的物理槽位,禁止产生副本 + // no-copy for temp eval if (target == NO_REG) return static_cast(sym->index); @@ -253,7 +253,7 @@ namespace Fig &c->location); } - // 回滚水位线, 释放传参时的临时占用 + // free arg temps current->freereg = mark; // 目若 target 未指定,allocateReg 将复用 baseReg,实现零开销回写 @@ -317,7 +317,7 @@ namespace Fig return r_val; } - Register mark = current->freereg; // 记录水位线 + Register mark = current->freereg; // mark auto r_l = compileExpr(in->left); if (!r_l) diff --git a/src/Compiler/StmtCompiler.cpp b/src/Compiler/StmtCompiler.cpp index 6e1ace7..2556545 100644 --- a/src/Compiler/StmtCompiler.cpp +++ b/src/Compiler/StmtCompiler.cpp @@ -1,6 +1,6 @@ /*! @file src/Compiler/StmtCompiler.cpp - @brief 语句编译器实现:实装水位线机制,彻底消灭硬编码寄存器释放 + @brief 语句编译 */ #include @@ -35,7 +35,7 @@ namespace Fig auto *v = static_cast(stmt); if (current->enclosing == nullptr) // 处理全局变量 { - Register mark = current->freereg; // 记录水位线 + Register mark = current->freereg; // mark auto regRes = compileExpr(v->initExpr); if (!regRes) return std::unexpected(regRes.error()); @@ -74,7 +74,7 @@ namespace Fig Proto *newProto = new Proto(); newProto->name = f->name; newProto->numParams = static_cast(f->params.size()); - newProto->maxRegisters = newProto->numParams; // 同步水位线 + newProto->maxRegisters = newProto->numParams; // sync f->protoIndex = static_cast(module->protos.size()); module->protos.push_back(newProto); @@ -141,7 +141,7 @@ namespace Fig auto *i = static_cast(stmt); DynArray exitJumps; - Register mark = current->freereg; // 记录水位线 + Register mark = current->freereg; // mark auto r_cond = compileExpr(i->cond); if (!r_cond) return std::unexpected(r_cond.error()); @@ -204,7 +204,7 @@ namespace Fig auto *w = static_cast(stmt); int startIdx = static_cast(current->proto->code.size()); - Register mark = current->freereg; // 记录水位线 + Register mark = current->freereg; // mark auto r_cond = compileExpr(w->cond); if (!r_cond) return std::unexpected(r_cond.error()); @@ -228,7 +228,7 @@ namespace Fig case AstType::ReturnStmt: { auto *rs = static_cast(stmt); - Register mark = current->freereg; // 记录水位线 + Register mark = current->freereg; // mark Register retReg; if (rs->value) @@ -253,7 +253,7 @@ namespace Fig } case AstType::ExprStmt: { - Register mark = current->freereg; // 记录水位线 + Register mark = current->freereg; // mark auto reg = compileExpr(static_cast(stmt)->expr); if (!reg) return std::unexpected(reg.error()); diff --git a/src/Parser/ExprParser.cpp b/src/Parser/ExprParser.cpp index d9f4f6f..6bad03b 100644 --- a/src/Parser/ExprParser.cpp +++ b/src/Parser/ExprParser.cpp @@ -161,7 +161,7 @@ namespace Fig { return std::unexpected(type_result.error()); } - TypeExpr *type = *type_result; + Expr *type = *type_result; if (!match(TokenType::LeftBrace)) { @@ -175,6 +175,8 @@ namespace Fig new Point{1, 2} Named: new Point{x = 1, y = 2} + Shorthand: + new Point{y, x} */ DynArray args; @@ -195,11 +197,12 @@ namespace Fig break; } - if (currentToken().isIdentifier() && peekToken().type == TokenType::Assign) + // named arg + if (currentToken().isIdentifier() && peekToken().type == TokenType::Colon) { const Token &name_token = consumeToken(); const String &name = srcManager.GetSub(name_token.index, name_token.length); - consumeToken(); // consume `=` + consumeToken(); // consume `:` SET_STOP_AT(TokenType::Comma, TokenType::RightBrace); // , / } auto result = parseExpression(); @@ -213,7 +216,20 @@ namespace Fig *result }); } - else + // shorthand + else if (currentToken().isIdentifier() + && (peekToken().type == TokenType::Comma || peekToken().type == TokenType::RightBrace)) + { + const Token &name_token = consumeToken(); + const String &name = srcManager.GetSub(name_token.index, name_token.length); + + + + IdentiExpr *ident = + arena.Allocate(name, makeSourceLocation(name_token)); + args.push_back(NewExpr::Arg{name, ident}); + } + else { SET_STOP_AT(TokenType::Comma, TokenType::RightBrace); // , / } auto result = parseExpression(); @@ -226,7 +242,7 @@ namespace Fig .value = *result }); } - + if (match(TokenType::Comma)) { @@ -273,7 +289,7 @@ namespace Fig } params = *paraResult; - TypeExpr *returnType = nullptr; + Expr *returnType = nullptr; Token rightArrowToken; if (match(TokenType::RightArrow)) // -> { @@ -332,6 +348,7 @@ namespace Fig Expr *lhs = nullptr; Token token = currentToken(); + // NUD if (token.isIdentifier()) { const auto &lhs_result = parseIdentiExpr(); @@ -350,7 +367,7 @@ namespace Fig } lhs = *lhs_result; } - else if (IsTokenOp(token.type, false)) // 是否是一元运算符 + else if (IsTokenOp(token.type, false)) // 是否是一元前缀运算符 { const auto &lhs_result = parsePrefixExpr(); if (!lhs_result) @@ -408,6 +425,7 @@ namespace Fig makeSourceLocation(prevToken()))); } + // LED while (true) { token = currentToken(); @@ -416,57 +434,116 @@ namespace Fig break; } - if (IsTokenOp(token.type /* isBinary = true */)) // 是否为二元运算符 + // is / as + if (token.type == TokenType::Is || token.type == TokenType::As) + { + BinaryOperator op = TokenToBinaryOp(token); + BindingPower lbp = GetBinaryOpLBp(op); + if (rbp >= lbp) + { + break; + } + consumeToken(); // consume `is` or `as` + auto typeRes = parseTypeExpr(); + if (!typeRes) + { + return std::unexpected(typeRes.error()); + } + lhs = arena.Allocate(lhs, op, *typeRes); + } + // binary + else if (IsTokenOp(token.type /* isBinary = true */)) { BinaryOperator op = TokenToBinaryOp(token); BindingPower lbp = GetBinaryOpLBp(op); if (rbp >= lbp) { - // 前操作数的右绑定力比当前操作数的左绑定力大 - // lhs被吸走 break; } auto result = parseInfixExpr(lhs); if (!result) { - resetTermintors(); return result; } lhs = *result; } - // 后缀运算符优先级非常大,几乎永远跟在操作数后面,因此我们可以直接结合 - // 而不用走正常路径 - else if (token.type == TokenType::LeftBracket) // `[` + // [index] + else if (token.type == TokenType::LeftBracket) { const auto &expr_result = parseIndexExpr(lhs); if (!expr_result) { - resetTermintors(); return expr_result; } lhs = *expr_result; } - else if (token.type == TokenType::LeftParen) // `(` + // call + else if (token.type == TokenType::LeftParen) { const auto &expr_result = parseCallExpr(lhs); if (!expr_result) { - resetTermintors(); return expr_result; } lhs = *expr_result; } + // .member + else if (token.type == TokenType::Dot) + { + consumeToken(); // consume `.` + if (!currentToken().isIdentifier()) + { + return std::unexpected( + makeUnexpectTokenError("MemberExpr", "identifier after `.`", currentToken())); + } + const Token &nameToken = consumeToken(); + const String &name = + srcManager.GetSub(nameToken.index, nameToken.length); + SourceLocation loc = makeSourceLocation(nameToken); + lhs = arena.Allocate(lhs, name, loc); + } + // x++ x-- + else if (token.type == TokenType::DoublePlus || token.type == TokenType::DoubleMinus) + { + UnaryOperator op = TokenToUnaryOp(consumeToken()); + lhs = arena.Allocate(op, lhs); + } + // ?: + else if (token.type == TokenType::Question) + { + // ?: 最低优先 + // 赋值 rbp = 101,所以只有当 rbp < 100 时才可能进到三元 + // 实际上三元是最低优先级的非赋值运算符,我们给一个很小的 lbp + constexpr BindingPower TERNARY_LBP = 150; + if (rbp >= TERNARY_LBP) + { + break; + } + consumeToken(); // consume `?` + auto thenRes = parseExpression(0); // 重置绑定力,右结合 + if (!thenRes) + { + return std::unexpected(thenRes.error()); + } + if (!match(TokenType::Colon)) + { + return std::unexpected( + makeUnexpectTokenError("TernaryExpr", "`:` for else branch", currentToken())); + } + auto elseRes = parseExpression(TERNARY_LBP - 1); // 右结合 + if (!elseRes) + { + return std::unexpected(elseRes.error()); + } + lhs = arena.Allocate(lhs, *thenRes, *elseRes, lhs->location); + } else { - // return std::unexpected(Error(ErrorType::ExpectedExpression, - // "expression unexpectedly ended", - // "insert expressions", - // makeSourceLocation(token))); return lhs; } } return lhs; } -}; // namespace Fig \ No newline at end of file +}; // namespace Fig diff --git a/src/Parser/Parser.cpp b/src/Parser/Parser.cpp index 5ab24ff..f30c730 100644 --- a/src/Parser/Parser.cpp +++ b/src/Parser/Parser.cpp @@ -15,12 +15,16 @@ namespace Fig while (currentToken().type != TokenType::EndOfFile) { + if (lexerError) + { + return std::unexpected(*lexerError); + } auto result = parseStatement(); if (!result) { return std::unexpected(result.error()); } - + Stmt *stmt = *result; if (stmt) { diff --git a/src/Parser/Parser.hpp b/src/Parser/Parser.hpp index e80ec37..fabc521 100644 --- a/src/Parser/Parser.hpp +++ b/src/Parser/Parser.hpp @@ -35,6 +35,7 @@ namespace Fig bool isEOF = false; Diagnostics &diagnostics; + std::optional lexerError; // 词法错误缓存,避免 exit/abort // 惰性获取下一个 Token,跳过注释 Token nextToken() @@ -49,8 +50,12 @@ namespace Fig auto result = lexer.NextToken(); if (!result) { - ReportError(result.error(), srcManager); - std::exit(-1); + lexerError = result.error(); + isEOF = true; + Token eof = {0, 0, TokenType::EndOfFile}; + buffer.push_back(eof); + index = buffer.size() - 1; + return buffer[index]; } const Token &token = result.value(); if (token.type == TokenType::Comments) @@ -84,8 +89,12 @@ namespace Fig auto result = lexer.NextToken(); if (!result) { - ReportError(result.error(), srcManager); - std::abort(); + lexerError = result.error(); + isEOF = true; + Token eof = {0, 0, TokenType::EndOfFile}; + buffer.push_back(eof); + index = buffer.size() - 1; + return buffer.back(); } if (result->type == TokenType::Comments) continue; @@ -158,20 +167,10 @@ namespace Fig return baseTerminators; } - std::unordered_set &getTerminators() - { - static std::unordered_set terminators(getBaseTerminators()); - return terminators; - } - void resetTermintors() - { - getTerminators() = getBaseTerminators(); - } - bool shouldTerminate() { const Token &token = currentToken(); - if (getTerminators().contains(token.type)) + if (getBaseTerminators().contains(token.type)) return true; for (auto it = stateStack.rbegin(); it < stateStack.rend(); ++it) { @@ -261,9 +260,9 @@ namespace Fig Result parseTypeParameters(); - Result parseTypeExpr(); - Result parseNamedTypeExpr(); - Result parseFnTypeExpr(); + Result parseTypeExpr(); + Result parseNamedTypeExpr(); + Result parseFnTypeExpr(); Result parseExpression(BindingPower = 0); Result parseLiteralExpr(); @@ -277,6 +276,7 @@ namespace Fig Result parseBlockStmt(); Result parseVarDecl(bool); + Result parseConstDecl(bool); Result parseIfStmt(); Result parseWhileStmt(); Result, Error> parseFnParams(); @@ -286,6 +286,8 @@ namespace Fig Result parseStructDef(bool); Result parseInterfaceDef(bool); Result parseImpl(); + Result parseForStmt(); + Result parseImportStmt(); Result parseStatement(); diff --git a/src/Parser/ParserTest.cpp b/src/Parser/ParserTest.cpp index 2c3da36..de096d0 100644 --- a/src/Parser/ParserTest.cpp +++ b/src/Parser/ParserTest.cpp @@ -5,24 +5,25 @@ int main() { using namespace Fig; - String fileName = "test.fig"; - String filePath = "T:/Files/Maker/Code/MyCodingLanguage/The Fig Project/Fig/test.fig"; + String fileName = "test.fig"; + String filePath = + "T:/Files/Maker/Code/MyCodingLanguage/The Fig Project/Fig/" + fileName; SourceManager srcManager(filePath); String source = srcManager.Read(); if (!srcManager.read) { - std::cerr << "Couldn't read file"; + std::cerr << "Couldn't read file: " << filePath << '\n'; return 1; } - Lexer lexer(source, fileName); + Lexer lexer(source, fileName); Diagnostics diagnostics; Parser parser(lexer, srcManager, fileName, diagnostics); - auto result = parser.Parse(); + auto result = parser.Parse(); if (!result) { ReportError(result.error(), srcManager); @@ -32,8 +33,11 @@ int main() diagnostics.EmitAll(srcManager); Program *program = *result; - for (Stmt *stmt : program->nodes) + std::cout << "Parsed " << program->nodes.size() << " statements\n"; + for (size_t i = 0; i < program->nodes.size(); ++i) { - std::cout << stmt->toString() << '\n'; + std::cout << '[' << i << "] " << program->nodes[i]->toString() << '\n'; } -} \ No newline at end of file + + return 0; +} diff --git a/src/Parser/StmtParser.cpp b/src/Parser/StmtParser.cpp index a26aed2..a774126 100644 --- a/src/Parser/StmtParser.cpp +++ b/src/Parser/StmtParser.cpp @@ -50,7 +50,7 @@ namespace Fig const String &name = srcManager.GetSub(currentToken().index, currentToken().length); consumeToken(); - TypeExpr *typeSpeicifer = nullptr; + Expr *typeSpeicifer = nullptr; if (match(TokenType::Colon)) { auto result = parseTypeExpr(); @@ -99,6 +99,79 @@ namespace Fig return varDecl; } + Result Parser::parseConstDecl(bool isPublic) + { + // must init + StateProtector p(this, {State::ParsingVarDecl}); + + SourceLocation location = makeSourceLocation(consumeToken()); // consume `const` + + if (currentToken().type != TokenType::Identifier) + { + return std::unexpected(makeUnexpectTokenError("ConstDecl", "const name", currentToken())); + } + const String &name = srcManager.GetSub(currentToken().index, currentToken().length); + consumeToken(); + + Expr *typeSpecifier = nullptr; + if (match(TokenType::Colon)) + { + auto result = parseTypeExpr(); + if (!result) + { + return std::unexpected(result.error()); + } + typeSpecifier = *result; + } + + Expr *initExpr = nullptr; + bool isInfer = false; + if (match(TokenType::Assign)) + { + auto result = parseExpression(); + if (!result) + { + return std::unexpected(result.error()); + } + initExpr = *result; + } + else if (match(TokenType::Walrus)) + { + if (typeSpecifier) + { + return std::unexpected(Error( + ErrorType::SyntaxError, + "used type infer but specifying the type", + "change `:=` to '='", + makeSourceLocation(prevToken()))); + } + auto result = parseExpression(); + if (!result) + { + return std::unexpected(result.error()); + } + initExpr = *result; + isInfer = true; + } + else + { + return std::unexpected(Error( + ErrorType::SyntaxError, + "const must be initialized", + "add '=' and an initializer expression", + makeSourceLocation(prevToken()))); + } + + if (!match(TokenType::Semicolon)) + { + return std::unexpected(makeExpectSemicolonError()); + } + + VarDecl *varDecl = + arena.Allocate(isPublic, name, typeSpecifier, isInfer, initExpr, location); + return varDecl; + } + Result Parser::parseIfStmt() { StateProtector p(this, {State::ParsingIf}); @@ -294,6 +367,123 @@ namespace Fig return whileStmt; } + Result Parser::parseForStmt() + { + SourceLocation location = makeSourceLocation(consumeToken()); // consume `for` + + // 括号可选 + bool hasParen = match(TokenType::LeftParen); + + // init: var decl 或 表达式语句(或空) + Stmt *init = nullptr; + if (currentToken().type == TokenType::Variable) + { + auto result = parseVarDecl(false); + if (!result) + return std::unexpected(result.error()); + init = *result; + } + else if (currentToken().type == TokenType::Semicolon) + { + // 空 init,跳过 + } + else if (!isEOF) + { + // 表达式作为 init + auto result = parseExpression(); + if (!result) + return std::unexpected(result.error()); + init = arena.Allocate(*result); + if (!match(TokenType::Semicolon)) + return std::unexpected(makeExpectSemicolonError()); + } + + // 要求分号分隔 + if (!init && currentToken().type != TokenType::Semicolon) + { + // 如果不是 var decl 且下一个不是分号,尝试作为表达式解析并消耗分号 + // 实际上 init 为 nullptr 的情况就是空 init,此时应该已经有分号了 + } + if (init) + { + + } + else + { + if (!match(TokenType::Semicolon)) + { + return std::unexpected(makeExpectSemicolonError()); + } + } + + // cond: 表达式(或空) + Expr *cond = nullptr; + SET_STOP_AT(TokenType::Semicolon); + if (currentToken().type != TokenType::Semicolon) + { + auto result = parseExpression(); + if (!result) + return std::unexpected(result.error()); + cond = *result; + } + // 确保下一个是分号 + if (currentToken().type == TokenType::Semicolon) + { + // continue + } + if (!match(TokenType::Semicolon)) + { + return std::unexpected(makeExpectSemicolonError()); + } + + // step: 表达式(或空) + Expr *step = nullptr; + if (hasParen) + { + SET_STOP_AT(TokenType::RightParen); + } + else + { + SET_STOP_AT(TokenType::LeftBrace); + } + if (hasParen && currentToken().type == TokenType::RightParen) + { + // 空 step + } + else if (!hasParen && currentToken().type == TokenType::LeftBrace) + { + // 空 step,直接进入 body + } + else if (!isEOF) + { + auto result = parseExpression(); + if (!result) + return std::unexpected(result.error()); + step = *result; + } + + if (hasParen && !match(TokenType::RightParen)) + { + return std::unexpected( + makeUnexpectTokenError("for stmt", "`)` to close", currentToken())); + } + + if (currentToken().type != TokenType::LeftBrace) + { + return std::unexpected( + makeUnexpectTokenError("for stmt", "left brace `{`", currentToken())); + } + + auto bodyRes = parseBlockStmt(); + if (!bodyRes) + { + return std::unexpected(bodyRes.error()); + } + + ForStmt *forStmt = arena.Allocate(init, cond, step, *bodyRes, location); + return forStmt; + } + Result, Error> Parser::parseFnParams() { const Token &lpToken = consumeToken(); @@ -318,7 +508,7 @@ namespace Fig SourceLocation location = makeSourceLocation(nToken); const String &name = srcManager.GetSub(nToken.index, nToken.length); - TypeExpr *type = nullptr; + Expr *type = nullptr; if (match(TokenType::Colon)) { auto result = parseTypeExpr(); @@ -345,8 +535,32 @@ namespace Fig PosParam *posParam = arena.Allocate(name, type, defaultValue, location); params.push_back(posParam); + // 可变参数: ... (跟在最后一个参数后面) + if (match(TokenType::TripleDot)) + { + // 标记最后一个参数为可变参数 + // 通过 VarParam 标记 + // 当前用 VarParam 包装最后一个 param + // 简单方案:创建一个带 variadic 标记的 param + // TODO: 改用专门的 VarParam AST 节点 + // 暂时用 flag 标记在 posParam 上 + + if (!match(TokenType::RightParen)) + { + return std::unexpected( + makeUnexpectTokenError("fn params", "`)` after `...`", currentToken())); + } + // 直接返回,可变参数后面不能再有参数 + break; + } + if (match(TokenType::Comma)) { + if (match(TokenType::RightParen)) + { + // 尾部逗号允许,如 func(a, b,) + break; + } if (!currentToken().isIdentifier()) { return std::unexpected( @@ -385,7 +599,7 @@ namespace Fig } params = *paraResult; - TypeExpr *returnType = nullptr; + Expr *returnType = nullptr; if (match(TokenType::RightArrow)) { auto result = parseTypeExpr(); @@ -405,11 +619,6 @@ namespace Fig return std::unexpected(result.error()); } - // if (!match(TokenType::Semicolon)) // ; - // { - // return std::unexpected(makeExpectSemicolonError(prevToken())); - // } - if (match(TokenType::Semicolon)) { diagnostics.Report(Error( @@ -518,7 +727,7 @@ namespace Fig // (public) field_name (: Type) (= expr) / (:= expr) - bool isPublic = match(TokenType::Public); + bool isPublicField = match(TokenType::Public); if (currentToken().isIdentifier()) { const Token &name_tok = consumeToken(); @@ -533,11 +742,11 @@ namespace Fig } stDef->fields.push_back( - StructDefStmt::Field{isPublic, true, field_name, nullptr, *result}); + StructDefStmt::Field{isPublicField, true, field_name, nullptr, *result}); } else { - TypeExpr *type = nullptr; + Expr *type = nullptr; Expr *initExpr = nullptr; if (match(TokenType::Colon)) // : @@ -560,7 +769,7 @@ namespace Fig initExpr = *result; } stDef->fields.push_back( - StructDefStmt::Field{isPublic, false, field_name, type, initExpr}); + StructDefStmt::Field{isPublicField, false, field_name, type, initExpr}); } if (!match(TokenType::Semicolon)) { @@ -569,7 +778,7 @@ namespace Fig } else if (currentToken().type == TokenType::Function) { - auto result = parseFnDefStmt(isPublic); + auto result = parseFnDefStmt(isPublicField); if (!result) { return result; @@ -587,113 +796,444 @@ namespace Fig return stDef; } - Result Parser::parseStatement() + Result Parser::parseInterfaceDef(bool isPublic) { - StateProtector p(this, {State::Standby}); + SourceLocation location = makeSourceLocation(consumeToken()); // consume `interface` - if (currentToken().type == TokenType::Public) + if (!currentToken().isIdentifier()) { - consumeToken(); - if (currentToken().type == TokenType::Variable) - { - return parseVarDecl(true); - } - - if (currentToken().type == TokenType::Function) - { - return parseFnDefStmt(true); - } - - if (currentToken().type == TokenType::Struct) - { - return parseStructDef(true); - } - return std::unexpected( - makeUnexpectTokenError("public", "var/const/func/struct", currentToken())); + makeUnexpectTokenError("InterfaceDef", "interface name", currentToken())); } - if (currentToken().type == TokenType::LeftBrace) + const Token &nameToken = consumeToken(); + const String &name = srcManager.GetSub(nameToken.index, nameToken.length); + + if (!match(TokenType::LeftBrace)) { - return parseBlockStmt(); + return std::unexpected( + makeUnexpectTokenError("InterfaceDef", "lbrace '{'", currentToken())); } - if (currentToken().type == TokenType::Variable) - { - return parseVarDecl(false); - } + const Token &lbToken = prevToken(); - if (currentToken().type == TokenType::If) - { - return parseIfStmt(); - } + InterfaceDefStmt *ifaceDef = arena.Allocate(); + ifaceDef->isPublic = isPublic; + ifaceDef->name = name; + ifaceDef->location = location; - if (currentToken().type == TokenType::While) + while (true) { - return parseWhileStmt(); - } + if (isEOF) + { + return std::unexpected(Error( + ErrorType::SyntaxError, + "unclosed braces in interface def", + "insert '}'", + makeSourceLocation(lbToken))); + } + if (match(TokenType::RightBrace)) + { + break; + } - if (currentToken().type == TokenType::Function && peekToken().isIdentifier()) - { - return parseFnDefStmt(false); - } + // interface 方法需要 `func` 关键字 + if (currentToken().type != TokenType::Function) + { + return std::unexpected( + makeUnexpectTokenError("InterfaceDef", "`func` for method", currentToken())); + } + consumeToken(); // consume `func` - if (currentToken().type == TokenType::Struct) - { - return parseStructDef(false); - } + if (!currentToken().isIdentifier()) + { + return std::unexpected( + makeUnexpectTokenError("InterfaceDef", "method name", currentToken())); + } - if (currentToken().type == TokenType::Return) - { - return parseReturnStmt(); - } + const Token &methodNameToken = consumeToken(); + const String &methodName = + srcManager.GetSub(methodNameToken.index, methodNameToken.length); - if (match(TokenType::Break)) - { - SourceLocation location = makeSourceLocation(prevToken()); - if (!match(TokenType::Semicolon)) + // 参数列表 + if (!match(TokenType::LeftParen)) + { + return std::unexpected( + makeUnexpectTokenError("InterfaceDef", "`(` for method params", currentToken())); + } + + // 解析参数类型(接口方法只声明类型,无参数名) + DynArray methods; // placeholder + DynArray paramTypes; + + while (true) + { + if (isEOF) + { + return std::unexpected(Error( + ErrorType::SyntaxError, + "unclosed parenthese in interface method", + "insert ')'", + makeSourceLocation(methodNameToken))); + } + if (match(TokenType::RightParen)) + { + break; + } + + // 参数: name : Type + if (!currentToken().isIdentifier()) + { + return std::unexpected( + makeUnexpectTokenError("InterfaceDef", "param name", currentToken())); + } + consumeToken(); // consume param name (unused in interface) + + Expr *paramType = nullptr; + if (match(TokenType::Colon)) + { + auto res = parseTypeExpr(); + if (!res) + return std::unexpected(res.error()); + paramType = *res; + } + // 接口方法参数类型可选(如果没有标注则默认 Any) + paramTypes.push_back(paramType); + + if (match(TokenType::Comma)) + { + if (match(TokenType::RightParen)) + break; // 尾部逗号 + } + } + + // 返回类型(接口方法必须有返回类型) + Expr *returnType = nullptr; + if (match(TokenType::RightArrow)) + { + auto res = parseTypeExpr(); + if (!res) + return std::unexpected(res.error()); + returnType = *res; + } + else + { + return std::unexpected(Error( + ErrorType::SyntaxError, + "interface method must specify return type with `->`", + "add `-> ReturnType`", + makeSourceLocation(methodNameToken))); + } + + // 默认实现?(方法签名后直接跟 `{` 表示默认实现) + BlockStmt *defaultBody = nullptr; + if (currentToken().type == TokenType::LeftBrace) + { + auto bodyRes = parseBlockStmt(); + if (!bodyRes) + return std::unexpected(bodyRes.error()); + defaultBody = *bodyRes; + } + else if (!match(TokenType::Semicolon)) { return std::unexpected(makeExpectSemicolonError()); } - BreakStmt *breakStmt = arena.Allocate(location); - return breakStmt; + + // 构建方法签名 + InterfaceDefStmt::Method method; + method.name = methodName; + method.params = paramTypes; + method.retType = returnType; + method.location = makeSourceLocation(methodNameToken); + ifaceDef->methods.push_back(std::move(method)); + + // TODO: 存储默认实现体的 AST + // 当前 InterfaceDefStmt::Method 没有 body 字段 + // 如果需要默认实现,需要扩展 AST + (void) defaultBody; } - if (match(TokenType::Continue)) + return ifaceDef; + } + + Result Parser::parseImpl() + { + SourceLocation location = makeSourceLocation(consumeToken()); // consume `impl` + + // impl InterfaceName for StructName { methods... } + auto interfaceTypeRes = parseTypeExpr(); + if (!interfaceTypeRes) + return std::unexpected(interfaceTypeRes.error()); + Expr *interfaceType = *interfaceTypeRes; + + if (!match(TokenType::For)) { - SourceLocation location = makeSourceLocation(prevToken()); - if (!match(TokenType::Semicolon)) + return std::unexpected( + makeUnexpectTokenError("ImplStmt", "`for` keyword", currentToken())); + } + + auto structTypeRes = parseTypeExpr(); + if (!structTypeRes) + return std::unexpected(structTypeRes.error()); + Expr *structType = *structTypeRes; + + if (!match(TokenType::LeftBrace)) + { + return std::unexpected( + makeUnexpectTokenError("ImplStmt", "lbrace `{`", currentToken())); + } + + const Token &lbToken = prevToken(); + + DynArray methods; + + while (true) + { + if (isEOF) { - return std::unexpected(makeExpectSemicolonError()); + return std::unexpected(Error( + ErrorType::SyntaxError, + "unclosed braces in impl block", + "insert '}'", + makeSourceLocation(lbToken))); } - ContinueStmt *continueStmt = arena.Allocate(location); - return continueStmt; + if (match(TokenType::RightBrace)) + { + break; + } + + // impl 方法需要 `func` 关键字 + if (currentToken().type != TokenType::Function) + { + return std::unexpected( + makeUnexpectTokenError("ImplStmt", "`func` for method", currentToken())); + } + consumeToken(); // consume `func` + + if (!currentToken().isIdentifier()) + { + return std::unexpected( + makeUnexpectTokenError("ImplStmt", "method name", currentToken())); + } + + const Token &methodNameToken = consumeToken(); + const String &methodName = + srcManager.GetSub(methodNameToken.index, methodNameToken.length); + + // 参数列表 + if (!match(TokenType::LeftParen)) + { + return std::unexpected( + makeUnexpectTokenError("ImplStmt", "`(` for method params", currentToken())); + } + + // 复用 FnDefStmt 来解析 impl 方法 + // 但我们不使用 parseFnDefStmt,因为 impl 方法: + // 1. 不写返回类型(由 interface 约束) + // 2. 必须有函数体({ }) + + DynArray fnParams; + + while (true) + { + if (isEOF) + { + return std::unexpected(Error( + ErrorType::SyntaxError, + "unclosed parenthese in impl method params", + "insert ')'", + makeSourceLocation(methodNameToken))); + } + if (match(TokenType::RightParen)) + { + break; + } + + if (!currentToken().isIdentifier()) + { + return std::unexpected( + makeUnexpectTokenError("ImplStmt", "param name", currentToken())); + } + + const Token &pToken = consumeToken(); + const String &pName = srcManager.GetSub(pToken.index, pToken.length); + + Expr *pType = nullptr; + if (match(TokenType::Colon)) + { + auto res = parseTypeExpr(); + if (!res) + return std::unexpected(res.error()); + pType = *res; + } + + PosParam *param = arena.Allocate( + pName, pType, nullptr, makeSourceLocation(pToken)); + fnParams.push_back(param); + + if (match(TokenType::Comma)) + { + if (match(TokenType::RightParen)) + break; // 尾部逗号 + } + } + + // impl 方法不写返回类型,必须有函数体 + BlockStmt *methodBody = nullptr; + if (currentToken().type == TokenType::LeftBrace) + { + auto bodyRes = parseBlockStmt(); + if (!bodyRes) + return std::unexpected(bodyRes.error()); + methodBody = *bodyRes; + } + else + { + return std::unexpected( + makeUnexpectTokenError("ImplStmt", "`{` for method body", currentToken())); + } + + FnDefStmt *fnDef = arena.Allocate( + false, methodName, fnParams, nullptr /* no return type */, methodBody, + makeSourceLocation(methodNameToken)); + methods.push_back(fnDef); } - if (isEOF) + ImplStmt *implStmt = arena.Allocate(interfaceType, structType, methods, location); + return implStmt; + } + + Result Parser::parseImportStmt() + { + SourceLocation location = makeSourceLocation(consumeToken()); // consume `import` + + bool isFileImport = false; + String path; + + if (currentToken().type == TokenType::LiteralString) { - return nullptr; + // import "path/to/file.fig" — 文件导入 + isFileImport = true; + const Token &strToken = consumeToken(); + path = srcManager.GetSub(strToken.index, strToken.length); + } + else if (currentToken().isIdentifier()) + { + // import std.io — Module 导入 + isFileImport = false; + // 收集完整的路径: a.b.c + while (true) + { + const Token &tok = consumeToken(); + path += srcManager.GetSub(tok.index, tok.length); + if (currentToken().type == TokenType::Dot) + { + path += "."; + consumeToken(); // consume `.` + } + else + { + break; + } + } + } + else + { + return std::unexpected( + makeUnexpectTokenError("ImportStmt", "module path or file string", currentToken())); } - if (currentToken().type == TokenType::Semicolon) - { - return std::unexpected(Error( - ErrorType::SyntaxError, - "null statement is not allowed here", - "remove `;`", - makeSourceLocation(currentToken()))); - } - - const auto &expr_result = parseExpression(); - if (!expr_result) - { - return std::unexpected(expr_result.error()); - } - ExprStmt *exprStmt = arena.Allocate(*expr_result); if (!match(TokenType::Semicolon)) { return std::unexpected(makeExpectSemicolonError()); } + + ImportStmt *importStmt = arena.Allocate(path, isFileImport, location); + return importStmt; + } + + Result Parser::parseStatement() + { + StateProtector p(this, {State::Standby}); + + bool isPublic = match(TokenType::Public); + + TokenType tt = currentToken().type; + + + switch (tt) + { + case TokenType::LeftBrace: return parseBlockStmt(); + case TokenType::If: return parseIfStmt(); + case TokenType::While: return parseWhileStmt(); + case TokenType::For: return parseForStmt(); + case TokenType::Import: return parseImportStmt(); + case TokenType::Interface: return parseInterfaceDef(isPublic); + case TokenType::Implement: return parseImpl(); + + case TokenType::Variable: return parseVarDecl(isPublic); + case TokenType::Const: return parseConstDecl(isPublic); + + case TokenType::Return: + { + return parseReturnStmt(); + } + + case TokenType::Function: + { + // 需要 lookahead: `func identifier` → 函数定义 + // `func (` 或 `func {` → Lambda 表达式语句 + if (peekToken().isIdentifier()) + return parseFnDefStmt(isPublic); + goto expr_stmt; + } + + case TokenType::Struct: + return parseStructDef(isPublic); + + case TokenType::Break: + { + consumeToken(); + SourceLocation loc = makeSourceLocation(prevToken()); + if (!match(TokenType::Semicolon)) + return std::unexpected(makeExpectSemicolonError()); + return static_cast(arena.Allocate(loc)); + } + + case TokenType::Continue: + { + consumeToken(); + SourceLocation loc = makeSourceLocation(prevToken()); + if (!match(TokenType::Semicolon)) + return std::unexpected(makeExpectSemicolonError()); + return static_cast(arena.Allocate(loc)); + } + + case TokenType::EndOfFile: + return nullptr; + + case TokenType::Semicolon: + return std::unexpected(Error( + ErrorType::SyntaxError, + "null statement is not allowed here", + "remove `;`", + makeSourceLocation(currentToken()))); + + default: + break; + } + + expr_stmt: + { + // 表达式语句 (fallback) + const auto &expr_result = parseExpression(); + if (!expr_result) + return std::unexpected(expr_result.error()); + ExprStmt *exprStmt = arena.Allocate(*expr_result); + if (!match(TokenType::Semicolon)) + return std::unexpected(makeExpectSemicolonError()); return exprStmt; } -}; // namespace Fig \ No newline at end of file + } + +}; // namespace Fig diff --git a/src/Parser/TypeExprParser.cpp b/src/Parser/TypeExprParser.cpp index 34df7db..66f6ce3 100644 --- a/src/Parser/TypeExprParser.cpp +++ b/src/Parser/TypeExprParser.cpp @@ -1,8 +1,8 @@ /*! @file src/Parser/TypeExprParser.cpp - @brief 类型表达式解析器实现:支持泛型与空安全 + @brief 类型表达式解析器实现 — 类型即值,产生 Expr* 而非 TypeExpr* @author PuqiAR (im@puqiar.top) - @date 2026-03-08 + @date 2026-06-06 */ #include @@ -49,38 +49,51 @@ namespace Fig return tp; } - // 解析基础命名类型与泛型: List - Result Parser::parseNamedTypeExpr() + + + Result Parser::parseNamedTypeExpr() { StateProtector p(this, {State::ParsingNamedTypeExpr}); - SourceLocation location = makeSourceLocation(currentToken()); - DynArray path; - while (true) + + if (!currentToken().isIdentifier()) { - 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("Type", "identifier", currentToken())); - } - else - break; + return std::unexpected( + makeUnexpectTokenError("TypeExpr", "type name", currentToken())); } - DynArray arguments; - if (match(TokenType::Less)) // `<` + const Token &firstTok = consumeToken(); + SourceLocation firstLoc = makeSourceLocation(firstTok); + const String &firstName = srcManager.GetSub(firstTok.index, firstTok.length); + + IdentiExpr *ident = arena.Allocate(firstName, firstLoc); + Expr *base = ident; + + // a.b.c + while (match(TokenType::Dot)) { + if (!currentToken().isIdentifier()) + { + return std::unexpected( + makeUnexpectTokenError("TypeExpr", "identifier after `.`", currentToken())); + } + const Token &tok = consumeToken(); + const String &name = srcManager.GetSub(tok.index, tok.length); + SourceLocation loc = makeSourceLocation(tok); + base = arena.Allocate(base, name, loc); + } + + // generic args + if (match(TokenType::Less)) + { + DynArray args; + while (true) { auto result = parseTypeExpr(); if (!result) return std::unexpected(result.error()); - arguments.push_back(*result); + args.push_back(*result); if (match(TokenType::Greater)) break; // `>` @@ -88,12 +101,14 @@ namespace Fig return std::unexpected( makeUnexpectTokenError("TypeArgs", "'>' or ','", currentToken())); } + + base = arena.Allocate(base, std::move(args), firstLoc); } - return arena.Allocate(path, arguments, location); + return base; } - Result Parser::parseFnTypeExpr() + Result Parser::parseFnTypeExpr() { StateProtector p(this, {State::ParsingFnTypeExpr}); SourceLocation location = makeSourceLocation(consumeToken()); // consume `func` @@ -103,7 +118,7 @@ namespace Fig makeUnexpectTokenError("FnTypeExpr", "lparen (", currentToken())); } - DynArray paraTypes; + DynArray paraTypes; while (true) { @@ -130,7 +145,7 @@ namespace Fig } } - TypeExpr *returnType = nullptr; + Expr *returnType = nullptr; if (match(TokenType::RightArrow)) // -> { @@ -146,10 +161,10 @@ namespace Fig return fnTypeExpr; } - // 解析主入口: 处理 `?` 后缀 - Result Parser::parseTypeExpr() + + Result Parser::parseTypeExpr() { - TypeExpr *base = nullptr; + Expr *base = nullptr; if (currentToken().isIdentifier()) { @@ -174,10 +189,10 @@ namespace Fig return std::unexpected(makeUnexpectTokenError("TypeExpr", "name", currentToken())); } - // type (?) + // nullable if (currentToken().type == TokenType::Question) // ? { - base = arena.Allocate( + base = arena.Allocate( base, makeSourceLocation(consumeToken())); // consume `?` } diff --git a/src/Sema/Analyzer.cpp b/src/Sema/Analyzer.cpp index 6a96c6f..e2480be 100644 --- a/src/Sema/Analyzer.cpp +++ b/src/Sema/Analyzer.cpp @@ -678,7 +678,7 @@ namespace Fig return idx; } - Result Analyzer::resolveTypeExpr(TypeExpr *texpr) + Result Analyzer::resolveTypeExpr(Expr *texpr) { if (!texpr) return typeCtx.GetBasic(TypeTag::Any); diff --git a/src/Sema/Analyzer.hpp b/src/Sema/Analyzer.hpp index 15a9b1b..67f9cd2 100644 --- a/src/Sema/Analyzer.hpp +++ b/src/Sema/Analyzer.hpp @@ -32,7 +32,7 @@ namespace Fig // 核心递归查找:解决跨越函数边界的捕获问题 Result resolveSymbolInternal(const String &name, const SourceLocation &loc, Scope* startScope); - Result resolveTypeExpr(TypeExpr *texpr); + Result resolveTypeExpr(Expr *texpr); Result pass1(Program *prog); Result resolveTypes(Program *prog); Result checkBodies(Program *prog); diff --git a/tests/Parser/parser_comprehensive_test.fig b/tests/Parser/parser_comprehensive_test.fig new file mode 100644 index 0000000..74d5a8e --- /dev/null +++ b/tests/Parser/parser_comprehensive_test.fig @@ -0,0 +1,232 @@ +/* ============================== + Fig Parser Comprehensive Test + ============================== */ + +// --- 单行注释 --- + +/* --- + 多行注释 + --- */ + +// ───────────────────────────────── +// 1. 变量声明 var +// ───────────────────────────────── +var x; // Any, 无初始化 +var a = 10; // 推断 Int +var b: Int = 20; // 显式类型 +var c := 30; // 类型推断锁定 +var d: Int; // 显式类型,无初始化 +var e = "hello"; // 推断 String +var f = true; // 推断 Bool +var g = null; // 推断 Null + +// ───────────────────────────────── +// 2. 常量声明 const +// ───────────────────────────────── +const PI = 3.14159; // 推断 Double +const MAX: Int = 100; // 显式类型 +const NAME := "Fig"; // 类型推断锁定 +const T: Double = 2.718; // 显式类型 + +// ───────────────────────────────── +// 3. 函数定义 func +// ───────────────────────────────── +func noop() {} +func add(a: Int, b: Int) -> Int { return a + b; } +func greet(name: String) -> String { return "Hello " + name + "!"; } +func quick(x) => x * 2; // 箭头简写 +func noReturn() -> Null { return null; } + +// ───────────────────────────────── +// 4. Lambda 表达式 +// ───────────────────────────────── +var lambda1 = func(x, y) => x + y; +var lambda2 = func(x: Int) { return x * x; }; + +// ───────────────────────────────── +// 5. 控制流 if / while / for +// ───────────────────────────────── +func testControlFlow() { + // if-else + if true { var z = 1; } + if (x > 0) { var z = 2; } + if a > 10 { return 1; } + else if a > 5 { return 2; } + else { return 3; } + + // while + while a < 10 { a = a + 1; } + while (a > 0) { a = a - 1; } + + // for (C风格,括号可选) + for var i = 0; i < 10; i = i + 1 { var _ = i; } + for (var j = 0; j < 5; j += 1) { var _ = j; } + for ; ; { break; } // 无限循环 + + // break / continue + while true { break; } + while true { continue; } + + return 0; +} + +// ───────────────────────────────── +// 6. 表达式运算符 +// ───────────────────────────────── +func testOperators() -> Int { + var r = 0; + + // 算术 + r = 1 + 2; + r = 3 - 1; + r = 2 * 3; + r = 6 / 2; + r = 7 % 3; + r = 2 ** 3; // 幂运算 + + // 比较 + var b1 = 1 == 1; + var b2 = 1 != 2; + var b3 = 1 < 2; + var b4 = 2 > 1; + var b5 = 1 <= 1; + var b6 = 2 >= 1; + + // 逻辑 + var l1 = true and false; + var l2 = true or false; + var l3 = not true; + var l4 = true && false; // && + var l5 = true || false; // || + + // 复合赋值 + r += 1; + r -= 1; + r *= 2; + r /= 2; + r %= 1; + r ^= 1; + + // 位运算 + var w1 = 1 & 2; + var w2 = 1 | 2; + var w3 = 1 ^ 2; + var w4 = ~1; + var w5 = 1 << 2; + var w6 = 4 >> 1; + + // 前后缀 ++/-- + var p = 0; + var pre = ++p; + var post = p--; + var n = --p; + + // 前缀取反 + var neg = -100; + var notExpr = not true; + + // 三元 + var t = a > 5 ? 1 : 0; + + // 成员访问 + var m = someObj.field; + + // 类型检查 / 转换 + var check = x is Int; + var cast = x as String; + + // 索引 + var idx = arr[0]; + + // 函数调用 + var callRes = add(1, 2); + + // 分组 + var grouped = (1 + 2) * 3; + + return r; +} + +// ───────────────────────────────── +// 7. struct 结构体 +// ───────────────────────────────── +struct Point { + public x: Int; + public y: Int; + + public func toString() -> String { + return "(" + "x" + "," + "y" + ")"; + } +} + +struct Person { + name: String; + age: Int = 18; // 默认值 + + public func getName() -> String { + return name; + } +} + +// ───────────────────────────────── +// 8. new 表达式 +// ───────────────────────────────── +func testNewExpr() { + var p1 = new Point{1, 2}; // 位置参数 + var p2 = new Point{x: 2, y: 3}; // 命名参数 + var xx = 114; + var yy = 514; + var p3 = new Point{yy, xx}; // 简写 + var p4 = new Point{}; // 空构造 +} + +// ───────────────────────────────── +// 9. interface 接口 +// ───────────────────────────────── +interface Drawable { + func draw() -> String; + func getLayer() -> Int; +} + +interface Printable { + func toString() -> String; + func getVersion() -> Int { + return 1; + } +} + +// ───────────────────────────────── +// 10. impl 实现 +// ───────────────────────────────── +struct Circle { + public radius: Double; +} + +impl Drawable for Circle { + func draw() { + return "circle"; + } + func getLayer() { + return 0; + } +} + +// ───────────────────────────────── +// 11. import 导入 +// ───────────────────────────────── +import std.io; +import "path/to/file.fig"; + +// ───────────────────────────────── +// 12. 闭包与嵌套函数 +// ───────────────────────────────── +func outer(x: Int) -> Function { + func inner(n: Int) -> Int { + return n * x; + } + return inner; +} + +var closureMaker = func(factor: Int) { + return func(n) => n * factor; +};