修复EOF飘逸(去除末尾\n)以及其他修复...

This commit is contained in:
2026-02-18 00:16:59 +08:00
parent 663fe39070
commit c81da16dfb
18 changed files with 404 additions and 65 deletions

View File

@@ -2,13 +2,16 @@
@file src/Ast/Ast.hpp @file src/Ast/Ast.hpp
@brief Ast总链接 @brief Ast总链接
@author PuqiAR (im@puqiar.top) @author PuqiAR (im@puqiar.top)
@date 2026-02-14 @date 2026-02-17
*/ */
#pragma once #pragma once
#include <Ast/Expr/CallExpr.hpp>
#include <Ast/Expr/IdentiExpr.hpp> #include <Ast/Expr/IdentiExpr.hpp>
#include <Ast/Expr/IndexExpr.hpp>
#include <Ast/Expr/InfixExpr.hpp> #include <Ast/Expr/InfixExpr.hpp>
#include <Ast/Expr/LiteralExpr.hpp> #include <Ast/Expr/LiteralExpr.hpp>
#include <Ast/Expr/PrefixExpr.hpp> #include <Ast/Expr/PrefixExpr.hpp>
#include <Ast/Stmt/VarDecl.hpp>

View File

@@ -19,10 +19,17 @@ namespace Fig
Expr, // 表达式 Expr, // 表达式
Stmt, // 语句 Stmt, // 语句
/* Expressions */
IdentiExpr, // 标识符表达式 IdentiExpr, // 标识符表达式
LiteralExpr, // 字面量表达式 LiteralExpr, // 字面量表达式
PrefixExpr, // 一元 前缀表达式 PrefixExpr, // 一元 前缀表达式
InfixExpr, // 二元 中缀表达式 InfixExpr, // 二元 中缀表达式
IndexExpr, // 后缀表达式,索引
CallExpr, // 后缀表达式,函数调用
/* Statements */
VarDecl,
}; };
struct AstNode struct AstNode
{ {
@@ -42,10 +49,28 @@ namespace Fig
struct Stmt : public AstNode struct Stmt : public AstNode
{ {
bool isPublic;
Stmt() Stmt()
{ {
type = AstType::Stmt; type = AstType::Stmt;
} }
}; };
}; // namespace Fig
}; // namespace Fig namespace std
{
template <>
struct std::formatter<Fig::AstNode *, char>
{
constexpr auto parse(std::format_parse_context &ctx)
{
return ctx.begin();
}
template <typename FormatContext>
auto format(const Fig::AstNode *_node, FormatContext &ctx) const
{
return std::format_to(ctx.out(), "{}", _node->toString().toStdString());
}
};
};

60
src/Ast/Expr/CallExpr.hpp Normal file
View File

@@ -0,0 +1,60 @@
/*!
@file src/Ast/Expr/CallExpr.hpp
@brief CallExpr等定义
@author PuqiAR (im@puqiar.top)
@date 2026-02-17
*/
#pragma once
#include <Ast/Base.hpp>
#include <Deps/Deps.hpp>
namespace Fig
{
struct FnCallArgs
{
DynArray<Expr *> 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("<CallExpr: '{}{}'>", callee->toString(), args.toString());
}
};
} // namespace Fig

View File

@@ -0,0 +1,34 @@
/*!
@file src/Ast/Expr/IndexExpr.hpp
@brief IndexExpr定义
@author PuqiAR (im@puqiar.top)
@date 2026-02-17
*/
#pragma once
#include <Ast/Base.hpp>
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("<IndexExpr: '{}[{}]'>", base->toString(), index->toString());
}
};
}; // namespace Fig

42
src/Ast/Stmt/VarDecl.hpp Normal file
View File

@@ -0,0 +1,42 @@
/*!
@file src/Ast/Stmt/VarDecl.hpp
@brief VarDecl定义
@author PuqiAR (im@puqiar.top)
@date 2026-02-17
*/
#pragma once
#include <Ast/Base.hpp>
#include <Deps/Deps.hpp>
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("<VarDecl {}: {} = {}>", name, typeSpecifierString, initExprString);
}
};
}; // namespace Fig

29
src/Bytecode/Bytecode.hpp Normal file
View File

@@ -0,0 +1,29 @@
/*!
@file src/Bytecode/Bytecode.hpp
@brief 字节码Bytecode定义
@author PuqiAR (im@puqiar.top)
@date 2026-02-17
*/
#pragma once
#include <cstdint>
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

View File

@@ -8,6 +8,10 @@
#include <Core/CoreIO.hpp> #include <Core/CoreIO.hpp>
#include <Core/CoreInfos.hpp> #include <Core/CoreInfos.hpp>
#ifdef _WIN32
#include <windows.h>
#endif
namespace Fig::CoreIO namespace Fig::CoreIO
{ {
#if defined(_WIN32) || defined(__APPLE__) || defined (__linux__) || defined (__unix__) #if defined(_WIN32) || defined(__APPLE__) || defined (__linux__) || defined (__unix__)
@@ -34,4 +38,10 @@ namespace Fig::CoreIO
#else #else
// link // link
#endif #endif
void InitConsoleIO()
{
SetConsoleCP(CP_UTF8);
SetConsoleOutputCP(CP_UTF8);
}
}; };

View File

@@ -15,4 +15,6 @@ namespace Fig::CoreIO
std::ostream &GetStdErr(); std::ostream &GetStdErr();
std::ostream &GetStdLog(); std::ostream &GetStdLog();
std::istream &GetStdCin(); std::istream &GetStdCin();
};
void InitConsoleIO();
}; // namespace Fig::CoreIO

View File

@@ -373,26 +373,6 @@ namespace Fig::Deps
init(s.data(), s.size()); 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) String &operator=(const String &other)
{ {
if (this != &other) if (this != &other)

View File

@@ -141,6 +141,7 @@ namespace Fig
err << "" << TC::DarkGray << "Thrower: " << error.thrower_loc.function_name() << " (" err << "" << TC::DarkGray << "Thrower: " << error.thrower_loc.function_name() << " ("
<< error.thrower_loc.file_name() << ":" << error.thrower_loc.line() << ")" << TC::Reset << "\n"; << error.thrower_loc.file_name() << ":" << error.thrower_loc.line() << ")" << TC::Reset << "\n";
err << "💡 " << TC::Blue << "Suggestion: " << error.suggestion << TC::Reset; err << "💡 " << TC::Blue << "Suggestion: " << error.suggestion << TC::Reset;
err << '\n';
} }
void ReportError(const Error &error, const SourceManager &srcManager) void ReportError(const Error &error, const SourceManager &srcManager)

View File

@@ -152,18 +152,21 @@ namespace Fig
SourcePosition startPos = rd.currentPosition(); SourcePosition startPos = rd.currentPosition();
Token tok(rd.currentIndex(), 1, TokenType::LiteralString); // "
rd.next(); // skip " / ' rd.next(); // skip " / '
Token tok(rd.currentIndex(), 0, TokenType::LiteralString);
while (true) while (true)
{ {
if (state == State::ScanStringDQ && rd.current() == U'"') if (state == State::ScanStringDQ && rd.current() == U'"')
{ {
tok.length ++;
rd.next(); // skip '"' rd.next(); // skip '"'
break; break;
} }
else if (state == State::ScanStringSQ && rd.current() == U'\'') else if (state == State::ScanStringSQ && rd.current() == U'\'')
{ {
tok.length ++;
rd.next(); // skip `'` rd.next(); // skip `'`
break; break;
} }
@@ -230,7 +233,7 @@ namespace Fig
while (!rd.isAtEnd()) while (!rd.isAtEnd())
{ {
char32_t current = rd.current(); char32_t current = rd.current();
if (current == EOF || !CharUtils::isAsciiSpace(current)) // 检查 EOF if (!CharUtils::isAsciiSpace(current)) // 检查 EOF
break; break;
rd.next(); rd.next();
} }
@@ -240,11 +243,7 @@ namespace Fig
{ {
if (rd.isAtEnd()) if (rd.isAtEnd())
{ {
return Token(rd.currentIndex(), 0, TokenType::EndOfFile); return Token(rd.getEOFIndex(), 1, TokenType::EndOfFile);
}
if (rd.current() == U'\0')
{
return Token(rd.currentIndex(), 1, TokenType::EndOfFile);
} }
if (rd.current() == U'/' && rd.peekIf() == U'/') if (rd.current() == U'/' && rd.peekIf() == U'/')
{ {

View File

@@ -7,10 +7,11 @@
#pragma once #pragma once
#include <Deps/Deps.hpp>
#include <Token/Token.hpp>
#include <Core/SourceLocations.hpp> #include <Core/SourceLocations.hpp>
#include <Deps/Deps.hpp>
#include <Error/Error.hpp> #include <Error/Error.hpp>
#include <Token/Token.hpp>
namespace Fig namespace Fig
{ {
@@ -25,17 +26,20 @@ namespace Fig
public: public:
SourceReader() SourceReader()
{ {
index = 0; index = 0;
pos.line = pos.column = 1; pos.line = pos.column = 1;
} }
SourceReader(const String &_source) // copy SourceReader(const String &_source) // copy
{ {
source = _source; source = _source;
index = 0; index = 0;
pos.line = pos.column = 1; pos.line = pos.column = 1;
} }
SourcePosition &currentPosition() { return pos; } SourcePosition &currentPosition()
{
return pos;
}
inline char32_t current() const inline char32_t current() const
{ {
@@ -52,7 +56,10 @@ namespace Fig
return source[index]; 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 inline char32_t peek() const
{ {
@@ -62,7 +69,10 @@ namespace Fig
inline char32_t peekIf() const 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; return 0xFFFD;
} }
@@ -92,12 +102,26 @@ namespace Fig
inline void skip(size_t n) 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 class Lexer
@@ -125,7 +149,7 @@ namespace Fig
}; };
private: private:
String fileName; String fileName;
SourceReader rd; SourceReader rd;
protected: protected:
@@ -149,7 +173,7 @@ namespace Fig
Lexer() {} Lexer() {}
Lexer(const String &source, String _fileName) Lexer(const String &source, String _fileName)
{ {
rd = SourceReader(source); rd = SourceReader(source);
fileName = std::move(_fileName); fileName = std::move(_fileName);
} }

View File

@@ -35,7 +35,7 @@ int main()
const auto &type = magic_enum::enum_name(token.type); const auto &type = magic_enum::enum_name(token.type);
if (token.type == TokenType::EndOfFile) if (token.type == TokenType::EndOfFile)
{ {
std::cout << "EOF: " << type << '\n'; std::cout << "EOF: " << type << " at " << token.index << '\n';
break; break;
} }
std::cout << lexeme << " --> " << type << '\n'; std::cout << lexeme << " --> " << type << '\n';

View File

@@ -61,16 +61,95 @@ namespace Fig
return node; return node;
} }
std::unordered_set<TokenType> Parser::getTerminators() // 返回当前state的终止条件(终止符) Result<IndexExpr *, Error> 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<TokenType> baseTerminators = {TokenType::EndOfFile, TokenType::Semicolon}; if (!index_result)
switch (state)
{ {
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<CallExpr *, Error> 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<TokenType> Parser::getTerminators()
{
/*
Syntax terminators:
; ) ] } , EOF
*/
static const std::unordered_set<TokenType> baseTerminators = {TokenType::Semicolon,
TokenType::RightParen,
TokenType::RightBracket,
TokenType::RightBrace,
TokenType::Comma,
TokenType::EndOfFile
};
return baseTerminators;
} }
bool Parser::shouldTerminate() bool Parser::shouldTerminate()
{ {
@@ -111,6 +190,22 @@ namespace Fig
} }
lhs = *lhs_result; 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) if (!lhs)
{ {
@@ -122,12 +217,12 @@ namespace Fig
while (true) while (true)
{ {
token = currentToken();
if (shouldTerminate()) if (shouldTerminate())
{ {
return lhs; break;
} }
token = currentToken();
if (IsTokenOp(token.type /* isBinary = true */)) // 是否为二元运算符 if (IsTokenOp(token.type /* isBinary = true */)) // 是否为二元运算符
{ {
BinaryOperator op = TokenToBinaryOp(token); 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 else
{ {
return lhs; return std::unexpected(Error(ErrorType::ExpectedExpression,
"expression unexpectedly ended",
"insert expressions",
makeSourcelocation(token)));
} }
} }
return lhs; return lhs;

View File

@@ -121,6 +121,10 @@ namespace Fig
ParsingInfixExpr, ParsingInfixExpr,
ParsingPrefixExpr, ParsingPrefixExpr,
ParsingIndexExpr,
ParsingCallExpr,
} state; } state;
Parser(Lexer &_lexer, SourceManager &_srcManager, String _fileName) : Parser(Lexer &_lexer, SourceManager &_srcManager, String _fileName) :
@@ -148,15 +152,19 @@ namespace Fig
Result<InfixExpr *, Error> parseInfixExpr(Expr *); // 由 parseExpression递归调用, 当前token为op Result<InfixExpr *, Error> parseInfixExpr(Expr *); // 由 parseExpression递归调用, 当前token为op
Result<PrefixExpr *, Error> parsePrefixExpr(); // 由 parseExpression递归调用, 当前token为op Result<PrefixExpr *, Error> parsePrefixExpr(); // 由 parseExpression递归调用, 当前token为op
std::unordered_set<TokenType> getTerminators(); // 返回当前state的终止条件(终止符) Result<IndexExpr *, Error> parseIndexExpr(Expr *); // 由 parseExpression调用, 当前token为 `[`
bool shouldTerminate(); // 通过state判断该不该终止表达式解析 Result<CallExpr *, Error> parseCallExpr(Expr *); // 由 parseExpression调用, 当前token为 `(`
Result<Expr *, Error> parseExpression(BindingPower = 0); std::unordered_set<TokenType> getTerminators(); // 返回固定的终止符
bool shouldTerminate(); // 判断是否终结
// Result<Expr *, Error> parseExpression(BindingPower = 0);
/* Statements */ /* Statements */
public: public:
Result<Expr *, Error> parseExpression(BindingPower = 0);
DynArray<AstNode *> parseAll(); DynArray<AstNode *> parseAll();
}; };
}; // namespace Fig }; // namespace Fig

View File

@@ -18,12 +18,12 @@ int main()
Lexer lexer(source, fileName); Lexer lexer(source, fileName);
Parser parser(lexer, srcManager, fileName); Parser parser(lexer, srcManager, fileName);
// const auto &result = parser.parseExpression(); const auto &result = parser.parseExpression();
// if (!result) if (!result)
// { {
// ReportError(result.error(), srcManager); ReportError(result.error(), srcManager);
// return 1; return 1;
// } }
// Expr *expr = *result; Expr *expr = *result;
// std::cout << expr->toString() << '\n'; std::cout << expr->toString() << '\n';
} }

View File

@@ -60,6 +60,9 @@ namespace Fig
source += line + '\n'; source += line + '\n';
lines.push_back(String(line)); lines.push_back(String(line));
} }
if (!source.empty() && source.back() == U'\n')
source.pop_back();
if (lines.empty()) if (lines.empty())
{ {
lines.push_back(String()); // 填充一个空的 lines.push_back(String()); // 填充一个空的

View File

@@ -0,0 +1,4 @@
int main()
{
}