feat: Implement compiler and virtual machine for Fig language

- Added Compiler class with methods for compiling programs, statements, and expressions.
- Introduced Proto structure to hold compiled bytecode and constants.
- Implemented expression compilation including literals, identifiers, and infix expressions.
- Developed statement compilation for variable declarations and expression statements.
- Created a VM class to execute compiled bytecode with support for arithmetic and comparison operations.
- Added Object and Value classes for handling different data types and memory management.
- Implemented String and Struct objects for enhanced data representation.
- Established a parser for parsing variable declarations and statements.
- Included tests for the VM and object representations.
This commit is contained in:
2026-02-20 14:05:56 +08:00
parent f2e899c7a7
commit 2631f76da1
31 changed files with 1722 additions and 94 deletions

View File

@@ -13,7 +13,7 @@ namespace Fig
{
state = State::ParsingLiteralExpr;
const Token &literal_token = consumeToken();
LiteralExpr *node = new LiteralExpr(literal_token, makeSourcelocation(literal_token));
LiteralExpr *node = new LiteralExpr(literal_token, makeSourceLocation(literal_token));
return node;
}
Result<IdentiExpr *, Error> Parser::parseIdentiExpr() // 当前token为Identifier调用
@@ -21,7 +21,7 @@ namespace Fig
state = State::ParsingIdentiExpr;
const Token &identifier = consumeToken();
IdentiExpr *node =
new IdentiExpr(srcManager.GetSub(identifier.index, identifier.length), makeSourcelocation(identifier));
new IdentiExpr(srcManager.GetSub(identifier.index, identifier.length), makeSourceLocation(identifier));
return node;
}
@@ -75,7 +75,7 @@ namespace Fig
if (currentToken().type != TokenType::RightBracket) // `]`
{
return std::unexpected(
Error(ErrorType::SyntaxError, "unclosed brackets", "insert `]`", makeSourcelocation(lbracket_token)));
Error(ErrorType::SyntaxError, "unclosed brackets", "insert `]`", makeSourceLocation(lbracket_token)));
}
consumeToken(); // consume `]`
@@ -104,7 +104,7 @@ namespace Fig
return std::unexpected(Error(ErrorType::SyntaxError,
"fn call has unclosed parenthese",
"insert `)`",
makeSourcelocation(lparen_token)));
makeSourceLocation(lparen_token)));
}
const auto &arg_result = parseExpression();
@@ -124,7 +124,7 @@ namespace Fig
return std::unexpected(Error(ErrorType::SyntaxError,
"expected `,` or `)` in argument list",
"insert `,`",
makeSourcelocation(currentToken())));
makeSourceLocation(currentToken())));
}
consumeToken(); // consume `,`
@@ -158,7 +158,7 @@ namespace Fig
return terminators.contains(token.type);
}
Result<Expr *, Error> Parser::parseExpression(BindingPower rbp)
Result<Expr *, Error> Parser::parseExpression(BindingPower rbp, TokenType stop, TokenType stop2)
{
Expr *lhs = nullptr;
Token token = currentToken();
@@ -202,7 +202,7 @@ namespace Fig
if (rparen_token.type != TokenType::RightParen)
{
return std::unexpected(Error(
ErrorType::SyntaxError, "unclosed parenthese", "insert `)`", makeSourcelocation(lparen_token)));
ErrorType::SyntaxError, "unclosed parenthese", "insert `)`", makeSourceLocation(lparen_token)));
}
lhs = *expr_result;
}
@@ -212,7 +212,7 @@ namespace Fig
return std::unexpected(Error(ErrorType::ExpectedExpression,
"expected expression",
"insert expressions",
makeSourcelocation(prevToken())));
makeSourceLocation(prevToken())));
}
while (true)
@@ -222,6 +222,10 @@ namespace Fig
{
break;
}
if (token.type == stop || token.type == stop2)
{
break;
}
if (IsTokenOp(token.type /* isBinary = true */)) // 是否为二元运算符
{
@@ -266,7 +270,7 @@ namespace Fig
return std::unexpected(Error(ErrorType::ExpectedExpression,
"expression unexpectedly ended",
"insert expressions",
makeSourcelocation(token)));
makeSourceLocation(token)));
}
}
return lhs;

View File

@@ -10,9 +10,18 @@
namespace Fig
{
DynArray<AstNode *> Parser::parseAll()
Result<Program *, Error> Parser::Parse()
{
DynArray<AstNode *> nodes;
return nodes;
Program *program = new Program;
while (!isEOF)
{
const auto &result = parseStatement();
if (!result)
{
return std::unexpected(result.error());
}
program->nodes.push_back(*result);
}
return program;
}
};

View File

@@ -111,6 +111,38 @@ namespace Fig
return current;
}
inline bool match(TokenType type)
{
if (currentToken().type == type)
{
consumeToken();
return true;
}
return false;
}
inline Error makeUnexpectTokenError(const String &stmtType, const String &expect, const Token &tokenGot, std::source_location loc = std::source_location::current())
{
return Error(
ErrorType::SyntaxError,
std::format("expect '{}' in {}, got `{}`", expect, stmtType, magic_enum::enum_name(tokenGot.type)),
"none",
makeSourceLocation(tokenGot),
loc
);
}
inline Error makeExpectSemicolonError(std::source_location loc = std::source_location::current())
{
return Error(
ErrorType::SyntaxError,
"expect ';' after statement",
"insert ';'",
makeSourceLocation(currentToken()),
loc
);
}
public:
enum class State : std::uint8_t
{
@@ -125,6 +157,8 @@ namespace Fig
ParsingIndexExpr,
ParsingCallExpr,
ParsingVarDecl,
} state;
Parser(Lexer &_lexer, SourceManager &_srcManager, String _fileName) :
@@ -134,37 +168,36 @@ namespace Fig
}
private:
SourceLocation makeSourcelocation(const Token &tok)
SourceLocation makeSourceLocation(const Token &tok)
{
auto [line, column] = srcManager.GetLineColumn(tok.index);
return SourceLocation(
SourcePosition(
line,
column,
tok.length
), fileName, "[internal parser]", magic_enum::enum_name(state).data());
return SourceLocation(SourcePosition(line, column, tok.length),
fileName,
"[internal parser]",
magic_enum::enum_name(state).data());
}
/* Expressions */
Result<LiteralExpr *, Error> parseLiteralExpr(); // 当前token为literal时调用
Result<IdentiExpr *, Error> parseIdentiExpr(); // 当前token为Identifier调用
Result<InfixExpr *, Error> parseInfixExpr(Expr *); // 由 parseExpression递归调用, 当前token为op
Result<PrefixExpr *, Error> parsePrefixExpr(); // 由 parseExpression递归调用, 当前token为op
Result<InfixExpr *, Error> parseInfixExpr(Expr *); // 由 parseExpression递归调用, 当前token为op
Result<PrefixExpr *, Error> parsePrefixExpr(); // 由 parseExpression递归调用, 当前token为op
Result<IndexExpr *, Error> parseIndexExpr(Expr *); // 由 parseExpression调用, 当前token为 `[`
Result<CallExpr *, Error> parseCallExpr(Expr *); // 由 parseExpression调用, 当前token为 `(`
Result<CallExpr *, Error> parseCallExpr(Expr *); // 由 parseExpression调用, 当前token为 `(`
std::unordered_set<TokenType> getTerminators(); // 返回固定的终止符
bool shouldTerminate(); // 判断是否终结
std::unordered_set<TokenType> getTerminators(); // 返回固定的终止符
bool shouldTerminate(); // 判断是否终结
// Result<Expr *, Error> parseExpression(BindingPower = 0);
Result<Expr *, Error> parseExpression(BindingPower = 0, TokenType stop = TokenType::Semicolon, TokenType stop2 = TokenType::Semicolon);
/* Statements */
public:
Result<VarDecl *, Error> parseVarDecl(bool); // 由 parseStatement调用, 当前token为 var
Result<Expr *, Error> parseExpression(BindingPower = 0);
DynArray<AstNode *> parseAll();
Result<Stmt *, Error> parseStatement();
public:
Result<Program *, Error> Parse();
};
}; // namespace Fig

View File

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

82
src/Parser/StmtParser.cpp Normal file
View File

@@ -0,0 +1,82 @@
/*!
@file src/Parser/StmtParser.hpp
@brief 语法分析器(Pratt + 手动递归下降) 语句解析实现
@author PuqiAR (im@puqiar.top)
@date 2026-02-19
*/
#include <Parser/Parser.hpp>
namespace Fig
{
Result<VarDecl *, Error> Parser::parseVarDecl(bool isPublic) // 由 parseStatement调用, 当前token为 var
{
state = State::ParsingVarDecl;
SourceLocation location = makeSourceLocation(consumeToken()); // consume `var`
if (currentToken().type != TokenType::Identifier)
{
return std::unexpected(makeUnexpectTokenError("VarDecl", "var name", currentToken()));
}
const String &name = srcManager.GetSub(currentToken().index, currentToken().length);
consumeToken(); // consume name
Expr *typeSpeicifer = nullptr;
if (match(TokenType::Colon)) // `:`
{
const auto &result = parseExpression(0, TokenType::Assign);
if (!result)
{
return std::unexpected(result.error());
}
typeSpeicifer = *result;
}
Expr *initExpr = nullptr;
if (match(TokenType::Assign))
{
const auto &result = parseExpression();
if (!result)
{
return std::unexpected(result.error());
}
initExpr = *result;
}
if (!match(TokenType::Semicolon))
{
makeExpectSemicolonError();
}
VarDecl *varDecl = new VarDecl(isPublic, name, typeSpeicifer, initExpr, location);
return varDecl;
}
Result<Stmt *, Error> Parser::parseStatement()
{
if (currentToken().type == TokenType::Public)
{
consumeToken(); // consume `public`
if (currentToken().type == TokenType::Variable)
{
return parseVarDecl(true);
}
}
else if (currentToken().type == TokenType::Variable)
{
return parseVarDecl(false);
}
else
{
const auto &expr_result = parseExpression(0);
if (!expr_result)
{
return std::unexpected(expr_result.error());
}
ExprStmt *exprStmt = new ExprStmt(*expr_result);
if (!match(TokenType::Semicolon))
{
return std::unexpected(makeExpectSemicolonError());
}
return exprStmt;
}
}
}; // namespace Fig