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:
@@ -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;
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
};
|
||||
@@ -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
|
||||
@@ -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
82
src/Parser/StmtParser.cpp
Normal 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
|
||||
Reference in New Issue
Block a user