修复EOF飘逸(去除末尾\n)以及其他修复...
This commit is contained in:
@@ -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>
|
||||||
@@ -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
60
src/Ast/Expr/CallExpr.hpp
Normal 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
|
||||||
34
src/Ast/Expr/IndexExpr.hpp
Normal file
34
src/Ast/Expr/IndexExpr.hpp
Normal 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
42
src/Ast/Stmt/VarDecl.hpp
Normal 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
29
src/Bytecode/Bytecode.hpp
Normal 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
|
||||||
@@ -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);
|
||||||
|
}
|
||||||
};
|
};
|
||||||
@@ -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
|
||||||
@@ -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)
|
||||||
|
|||||||
@@ -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)
|
||||||
|
|||||||
@@ -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'/')
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -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
|
||||||
{
|
{
|
||||||
@@ -35,7 +36,10 @@ namespace Fig
|
|||||||
pos.line = pos.column = 1;
|
pos.line = pos.column = 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
SourcePosition ¤tPosition() { return pos; }
|
SourcePosition ¤tPosition()
|
||||||
|
{
|
||||||
|
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
|
||||||
|
|||||||
@@ -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';
|
||||||
|
|||||||
@@ -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;
|
||||||
|
|||||||
@@ -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
|
||||||
@@ -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';
|
||||||
}
|
}
|
||||||
@@ -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()); // 填充一个空的
|
||||||
|
|||||||
@@ -0,0 +1,4 @@
|
|||||||
|
int main()
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user