diff --git a/src/Ast/Ast.hpp b/src/Ast/Ast.hpp index cf33c15..ead985f 100644 --- a/src/Ast/Ast.hpp +++ b/src/Ast/Ast.hpp @@ -2,13 +2,16 @@ @file src/Ast/Ast.hpp @brief Ast总链接 @author PuqiAR (im@puqiar.top) - @date 2026-02-14 + @date 2026-02-17 */ #pragma once +#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 417ee97..7e5a7c5 100644 --- a/src/Ast/Base.hpp +++ b/src/Ast/Base.hpp @@ -19,10 +19,17 @@ namespace Fig Expr, // 表达式 Stmt, // 语句 + /* Expressions */ IdentiExpr, // 标识符表达式 LiteralExpr, // 字面量表达式 PrefixExpr, // 一元 前缀表达式 InfixExpr, // 二元 中缀表达式 + + IndexExpr, // 后缀表达式,索引 + CallExpr, // 后缀表达式,函数调用 + + /* Statements */ + VarDecl, }; struct AstNode { @@ -42,10 +49,28 @@ namespace Fig struct Stmt : public AstNode { + bool isPublic; Stmt() { type = AstType::Stmt; } }; +}; // namespace Fig -}; // namespace Fig \ No newline at end of file +namespace std +{ + template <> + struct std::formatter + { + constexpr auto parse(std::format_parse_context &ctx) + { + return ctx.begin(); + } + + template + auto format(const Fig::AstNode *_node, FormatContext &ctx) const + { + return std::format_to(ctx.out(), "{}", _node->toString().toStdString()); + } + }; +}; \ No newline at end of file diff --git a/src/Ast/Expr/CallExpr.hpp b/src/Ast/Expr/CallExpr.hpp new file mode 100644 index 0000000..e541445 --- /dev/null +++ b/src/Ast/Expr/CallExpr.hpp @@ -0,0 +1,60 @@ +/*! + @file src/Ast/Expr/CallExpr.hpp + @brief CallExpr等定义 + @author PuqiAR (im@puqiar.top) + @date 2026-02-17 +*/ + +#pragma once + +#include +#include + +namespace Fig +{ + struct FnCallArgs + { + DynArray args; + + size_t size() const + { + return args.size(); + } + + String toString() const + { + String str = "("; + for (const Expr *expr : args) + { + if (expr != args.front()) + { + str += ", "; + } + str += expr->toString(); + } + str += ")"; + return str; + } + }; + + struct CallExpr final : public Expr + { + Expr *callee; + FnCallArgs args; + + CallExpr() + { + type = AstType::CallExpr; + } + + CallExpr(Expr *_callee, FnCallArgs _args) : callee(_callee), args(std::move(_args)) + { + type = AstType::CallExpr; + } + + virtual String toString() const override + { + return std::format("", callee->toString(), args.toString()); + } + }; +} // namespace Fig \ No newline at end of file diff --git a/src/Ast/Expr/IndexExpr.hpp b/src/Ast/Expr/IndexExpr.hpp new file mode 100644 index 0000000..f1985be --- /dev/null +++ b/src/Ast/Expr/IndexExpr.hpp @@ -0,0 +1,34 @@ +/*! + @file src/Ast/Expr/IndexExpr.hpp + @brief IndexExpr定义 + @author PuqiAR (im@puqiar.top) + @date 2026-02-17 +*/ + +#pragma once + +#include + +namespace Fig +{ + struct IndexExpr final : public Expr + { + Expr *base; + Expr *index; + + IndexExpr() + { + type = AstType::IndexExpr; + } + + IndexExpr(Expr *_base, Expr *_index) : base(_base), index(_index) + { + location = base->location; + } + + virtual String toString() const override + { + return std::format("", base->toString(), index->toString()); + } + }; +}; // namespace Fig \ No newline at end of file diff --git a/src/Ast/Stmt/VarDecl.hpp b/src/Ast/Stmt/VarDecl.hpp new file mode 100644 index 0000000..a335978 --- /dev/null +++ b/src/Ast/Stmt/VarDecl.hpp @@ -0,0 +1,42 @@ +/*! + @file src/Ast/Stmt/VarDecl.hpp + @brief VarDecl定义 + @author PuqiAR (im@puqiar.top) + @date 2026-02-17 +*/ + +#pragma once + +#include +#include + +namespace Fig +{ + struct VarDecl final : public Stmt + { + String name; + Expr *typeSpecifier; + Expr *initExpr; + + VarDecl() + { + type = AstType::VarDecl; + } + + VarDecl(String _name, Expr *_typeSpecifier, Expr *_initExpr, SourceLocation _location) : + name(std::move(_name)), + typeSpecifier(_typeSpecifier), + initExpr(_initExpr) // location 指向关键字 var/const位置 + { + type = AstType::VarDecl; + location = std::move(_location); + } + + virtual String toString() const override + { + const String &typeSpecifierString = (typeSpecifier ? typeSpecifier->toString() : "Any"); + const String &initExprString = (initExpr ? initExpr->toString() : "(disprovided)"); + return std::format("", name, typeSpecifierString, initExprString); + } + }; +}; // namespace Fig \ No newline at end of file diff --git a/src/Bytecode/Bytecode.hpp b/src/Bytecode/Bytecode.hpp new file mode 100644 index 0000000..a71bfe8 --- /dev/null +++ b/src/Bytecode/Bytecode.hpp @@ -0,0 +1,29 @@ +/*! + @file src/Bytecode/Bytecode.hpp + @brief 字节码Bytecode定义 + @author PuqiAR (im@puqiar.top) + @date 2026-02-17 +*/ + +#pragma once + +#include + +namespace Fig +{ + using OpCodeType = uint8_t; + + enum class OpCode : OpCodeType + { + LoadConst, // dst, const id + LoadLocal, // dst, slot id + StoreLocal, // slot, src(reg) + + LoadLocalRef, // dst, slot + LoadRef, // dst, refReg + StoreRef, // refReg, srcReg + + Add, // dst, a, b + Move, // dst, src + }; +}; // namespace Fig \ No newline at end of file diff --git a/src/Core/CoreIO.cpp b/src/Core/CoreIO.cpp index c4fce9a..24505f0 100644 --- a/src/Core/CoreIO.cpp +++ b/src/Core/CoreIO.cpp @@ -8,6 +8,10 @@ #include #include +#ifdef _WIN32 + #include +#endif + namespace Fig::CoreIO { #if defined(_WIN32) || defined(__APPLE__) || defined (__linux__) || defined (__unix__) @@ -34,4 +38,10 @@ namespace Fig::CoreIO #else // link #endif + + void InitConsoleIO() + { + SetConsoleCP(CP_UTF8); + SetConsoleOutputCP(CP_UTF8); + } }; \ No newline at end of file diff --git a/src/Core/CoreIO.hpp b/src/Core/CoreIO.hpp index 9332621..3231918 100644 --- a/src/Core/CoreIO.hpp +++ b/src/Core/CoreIO.hpp @@ -15,4 +15,6 @@ namespace Fig::CoreIO std::ostream &GetStdErr(); std::ostream &GetStdLog(); std::istream &GetStdCin(); -}; \ No newline at end of file + + void InitConsoleIO(); +}; // namespace Fig::CoreIO \ No newline at end of file diff --git a/src/Deps/String/String.hpp b/src/Deps/String/String.hpp index 4ba073d..8018c8c 100644 --- a/src/Deps/String/String.hpp +++ b/src/Deps/String/String.hpp @@ -373,26 +373,6 @@ namespace Fig::Deps init(s.data(), s.size()); } - static String fromPureAscii(const char *str) - { - String string; - string._length = std::strlen(str); - if (string._length <= SSO_SIZE) - { - memcpy(string.sso, str, string._length); - } - else - { - string.ascii.reserve(string._length); - for (size_t i = 0; i < string._length; ++i) - { - string.ascii.push_back(str[i]); - } - } - - return string; - } - String &operator=(const String &other) { if (this != &other) diff --git a/src/Error/Error.cpp b/src/Error/Error.cpp index 4a4d426..3bddba9 100644 --- a/src/Error/Error.cpp +++ b/src/Error/Error.cpp @@ -141,6 +141,7 @@ namespace Fig err << "❓ " << TC::DarkGray << "Thrower: " << error.thrower_loc.function_name() << " (" << error.thrower_loc.file_name() << ":" << error.thrower_loc.line() << ")" << TC::Reset << "\n"; err << "💡 " << TC::Blue << "Suggestion: " << error.suggestion << TC::Reset; + err << '\n'; } void ReportError(const Error &error, const SourceManager &srcManager) diff --git a/src/Lexer/Lexer.cpp b/src/Lexer/Lexer.cpp index b472a5f..1a0154b 100644 --- a/src/Lexer/Lexer.cpp +++ b/src/Lexer/Lexer.cpp @@ -152,18 +152,21 @@ namespace Fig SourcePosition startPos = rd.currentPosition(); + + Token tok(rd.currentIndex(), 1, TokenType::LiteralString); // " rd.next(); // skip " / ' - Token tok(rd.currentIndex(), 0, TokenType::LiteralString); while (true) { if (state == State::ScanStringDQ && rd.current() == U'"') { + tok.length ++; rd.next(); // skip '"' break; } else if (state == State::ScanStringSQ && rd.current() == U'\'') { + tok.length ++; rd.next(); // skip `'` break; } @@ -230,7 +233,7 @@ namespace Fig while (!rd.isAtEnd()) { char32_t current = rd.current(); - if (current == EOF || !CharUtils::isAsciiSpace(current)) // 检查 EOF + if (!CharUtils::isAsciiSpace(current)) // 检查 EOF break; rd.next(); } @@ -240,11 +243,7 @@ namespace Fig { if (rd.isAtEnd()) { - return Token(rd.currentIndex(), 0, TokenType::EndOfFile); - } - if (rd.current() == U'\0') - { - return Token(rd.currentIndex(), 1, TokenType::EndOfFile); + return Token(rd.getEOFIndex(), 1, TokenType::EndOfFile); } if (rd.current() == U'/' && rd.peekIf() == U'/') { diff --git a/src/Lexer/Lexer.hpp b/src/Lexer/Lexer.hpp index 1dc3f9f..c74b06c 100644 --- a/src/Lexer/Lexer.hpp +++ b/src/Lexer/Lexer.hpp @@ -7,10 +7,11 @@ #pragma once -#include -#include #include +#include #include +#include + namespace Fig { @@ -25,17 +26,20 @@ namespace Fig public: SourceReader() { - index = 0; + index = 0; pos.line = pos.column = 1; } SourceReader(const String &_source) // copy { - source = _source; - index = 0; + source = _source; + index = 0; pos.line = pos.column = 1; } - SourcePosition ¤tPosition() { return pos; } + SourcePosition ¤tPosition() + { + return pos; + } inline char32_t current() const { @@ -52,7 +56,10 @@ namespace Fig return source[index]; } - inline bool hasNext() const { return index < source.length() - 1; } + inline bool hasNext() const + { + return index < source.length() - 1; + } inline char32_t peek() const { @@ -62,7 +69,10 @@ namespace Fig inline char32_t peekIf() const { - if ((index + 1) < source.length()) { return source[index + 1]; } + if ((index + 1) < source.length()) + { + return source[index + 1]; + } return 0xFFFD; } @@ -92,12 +102,26 @@ namespace Fig inline void skip(size_t n) { - for (size_t i = 0; i < n; ++i) { next(); } + for (size_t i = 0; i < n; ++i) + { + next(); + } } - inline size_t currentIndex() const { return index; } + inline size_t currentIndex() const + { + return index; + } - inline bool isAtEnd() const { return index >= source.length(); } + inline bool isAtEnd() const + { + return index >= source.length(); + } + + inline size_t getEOFIndex() const + { + return source.length(); + } }; class Lexer @@ -125,7 +149,7 @@ namespace Fig }; private: - String fileName; + String fileName; SourceReader rd; protected: @@ -149,7 +173,7 @@ namespace Fig Lexer() {} Lexer(const String &source, String _fileName) { - rd = SourceReader(source); + rd = SourceReader(source); fileName = std::move(_fileName); } diff --git a/src/Lexer/LexerTest.cpp b/src/Lexer/LexerTest.cpp index 35d68ca..915231a 100644 --- a/src/Lexer/LexerTest.cpp +++ b/src/Lexer/LexerTest.cpp @@ -35,7 +35,7 @@ int main() const auto &type = magic_enum::enum_name(token.type); if (token.type == TokenType::EndOfFile) { - std::cout << "EOF: " << type << '\n'; + std::cout << "EOF: " << type << " at " << token.index << '\n'; break; } std::cout << lexeme << " --> " << type << '\n'; diff --git a/src/Parser/ExprParser.cpp b/src/Parser/ExprParser.cpp index a18a893..84d5f70 100644 --- a/src/Parser/ExprParser.cpp +++ b/src/Parser/ExprParser.cpp @@ -61,16 +61,95 @@ namespace Fig return node; } - std::unordered_set Parser::getTerminators() // 返回当前state的终止条件(终止符) + Result Parser::parseIndexExpr(Expr *base) // 由 parseExpression调用, 当前token为 `[` { - using enum State; + state = State::ParsingIndexExpr; + const Token &lbracket_token = consumeToken(); // consume `[` + const auto &index_result = parseExpression(); - static const std::unordered_set baseTerminators = {TokenType::EndOfFile, TokenType::Semicolon}; - - switch (state) + if (!index_result) { - default: return baseTerminators; + return std::unexpected(index_result.error()); } + + if (currentToken().type != TokenType::RightBracket) // `]` + { + return std::unexpected( + Error(ErrorType::SyntaxError, "unclosed brackets", "insert `]`", makeSourcelocation(lbracket_token))); + } + consumeToken(); // consume `]` + + IndexExpr *indexExpr = new IndexExpr(base, *index_result); + return indexExpr; + } + + Result Parser::parseCallExpr(Expr *callee) // 由 parseExpression调用, 当前token为 `(` + { + state = State::ParsingCallExpr; + const Token &lparen_token = consumeToken(); // consume `(` + + FnCallArgs callArgs; + + // 空参数列表 + if (currentToken().type == TokenType::RightParen) + { + consumeToken(); // consume `)` + return new CallExpr(callee, callArgs); + } + + while (true) + { + if (currentToken().type == TokenType::EndOfFile) + { + return std::unexpected(Error(ErrorType::SyntaxError, + "fn call has unclosed parenthese", + "insert `)`", + makeSourcelocation(lparen_token))); + } + + const auto &arg_result = parseExpression(); + if (!arg_result) + return std::unexpected(arg_result.error()); + + callArgs.args.push_back(*arg_result); + + if (currentToken().type == TokenType::RightParen) + { + consumeToken(); // consume `)` + break; + } + + if (currentToken().type != TokenType::Comma) + { + return std::unexpected(Error(ErrorType::SyntaxError, + "expected `,` or `)` in argument list", + "insert `,`", + makeSourcelocation(currentToken()))); + } + + consumeToken(); // consume `,` + } + + return new CallExpr(callee, callArgs); + } + + std::unordered_set Parser::getTerminators() + { + /* + + Syntax terminators: + ; ) ] } , EOF + + */ + static const std::unordered_set baseTerminators = {TokenType::Semicolon, + TokenType::RightParen, + TokenType::RightBracket, + TokenType::RightBrace, + TokenType::Comma, + TokenType::EndOfFile + + }; + return baseTerminators; } bool Parser::shouldTerminate() { @@ -111,6 +190,22 @@ namespace Fig } lhs = *lhs_result; } + else if (token.type == TokenType::LeftParen) + { + const Token &lparen_token = consumeToken(); // consume `(` + const auto &expr_result = parseExpression(0); + if (!expr_result) + { + return expr_result; + } + const Token &rparen_token = consumeToken(); // consume `)` + if (rparen_token.type != TokenType::RightParen) + { + return std::unexpected(Error( + ErrorType::SyntaxError, "unclosed parenthese", "insert `)`", makeSourcelocation(lparen_token))); + } + lhs = *expr_result; + } if (!lhs) { @@ -122,12 +217,12 @@ namespace Fig while (true) { + token = currentToken(); if (shouldTerminate()) { - return lhs; + break; } - token = currentToken(); if (IsTokenOp(token.type /* isBinary = true */)) // 是否为二元运算符 { BinaryOperator op = TokenToBinaryOp(token); @@ -148,10 +243,30 @@ namespace Fig } // 后缀运算符优先级非常大,几乎永远跟在操作数后面,因此我们可以直接结合 // 而不用走正常路径 - else if (0) {} + else if (token.type == TokenType::LeftBracket) // `[` + { + const auto &expr_result = parseIndexExpr(lhs); + if (!expr_result) + { + return expr_result; + } + lhs = *expr_result; + } + else if (token.type == TokenType::LeftParen) // `(` + { + const auto &expr_result = parseCallExpr(lhs); + if (!expr_result) + { + return expr_result; + } + lhs = *expr_result; + } else { - return lhs; + return std::unexpected(Error(ErrorType::ExpectedExpression, + "expression unexpectedly ended", + "insert expressions", + makeSourcelocation(token))); } } return lhs; diff --git a/src/Parser/Parser.hpp b/src/Parser/Parser.hpp index 3f25173..63fc98c 100644 --- a/src/Parser/Parser.hpp +++ b/src/Parser/Parser.hpp @@ -121,6 +121,10 @@ namespace Fig ParsingInfixExpr, ParsingPrefixExpr, + + ParsingIndexExpr, + ParsingCallExpr, + } state; Parser(Lexer &_lexer, SourceManager &_srcManager, String _fileName) : @@ -148,15 +152,19 @@ namespace Fig Result parseInfixExpr(Expr *); // 由 parseExpression递归调用, 当前token为op Result parsePrefixExpr(); // 由 parseExpression递归调用, 当前token为op - std::unordered_set getTerminators(); // 返回当前state的终止条件(终止符) - bool shouldTerminate(); // 通过state判断该不该终止表达式解析 + Result parseIndexExpr(Expr *); // 由 parseExpression调用, 当前token为 `[` + Result parseCallExpr(Expr *); // 由 parseExpression调用, 当前token为 `(` - Result parseExpression(BindingPower = 0); + std::unordered_set getTerminators(); // 返回固定的终止符 + bool shouldTerminate(); // 判断是否终结 + + // Result parseExpression(BindingPower = 0); /* Statements */ public: + Result parseExpression(BindingPower = 0); DynArray parseAll(); }; }; // namespace Fig \ No newline at end of file diff --git a/src/Parser/ParserTest.cpp b/src/Parser/ParserTest.cpp index 68b8566..4db3de3 100644 --- a/src/Parser/ParserTest.cpp +++ b/src/Parser/ParserTest.cpp @@ -18,12 +18,12 @@ int main() Lexer lexer(source, fileName); Parser parser(lexer, srcManager, fileName); - // const auto &result = parser.parseExpression(); - // if (!result) - // { - // ReportError(result.error(), srcManager); - // return 1; - // } - // Expr *expr = *result; - // std::cout << expr->toString() << '\n'; + const auto &result = parser.parseExpression(); + if (!result) + { + ReportError(result.error(), srcManager); + return 1; + } + Expr *expr = *result; + std::cout << expr->toString() << '\n'; } \ No newline at end of file diff --git a/src/SourceManager/SourceManager.hpp b/src/SourceManager/SourceManager.hpp index 21c4736..3a44e7f 100644 --- a/src/SourceManager/SourceManager.hpp +++ b/src/SourceManager/SourceManager.hpp @@ -60,6 +60,9 @@ namespace Fig source += line + '\n'; lines.push_back(String(line)); } + if (!source.empty() && source.back() == U'\n') + source.pop_back(); + if (lines.empty()) { lines.push_back(String()); // 填充一个空的 diff --git a/src/main.cpp b/src/main.cpp index e69de29..b08a07e 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -0,0 +1,4 @@ +int main() +{ + +} \ No newline at end of file