Add metadata to AST

This commit is contained in:
Sofia 2026-04-10 23:58:06 +03:00
parent d902569f7b
commit a035d07505
4 changed files with 79 additions and 22 deletions

View File

@ -3,6 +3,7 @@
#include "codegen.h"
#include "types.h"
#include "tokens.h"
#include <string>
#include <vector>
@ -11,17 +12,22 @@
namespace AST {
class Node {
public:
token::Metadata m_meta;
Node(token::Metadata meta) : m_meta{ meta } {}
virtual std::string formatted() = 0;
virtual ~Node() = default;
};
class Expression : public Node {
public:
Expression(token::Metadata meta) : Node{ meta } {}
virtual codegen::StackValue codegen(codegen::Builder& builder, codegen::Scope& scope) = 0;
};
class Statement : public Node {
public:
Statement(token::Metadata meta) : Node{ meta } {}
virtual void codegen(codegen::Builder& builder, codegen::Scope& scope) = 0;
};
@ -29,7 +35,7 @@ namespace AST {
private:
int m_value;
public:
IntLiteralExpression(int value) : m_value{ value } {}
IntLiteralExpression(token::Metadata meta, int value) : Expression{ meta }, m_value{ value } {}
virtual ~IntLiteralExpression() override = default;
virtual std::string formatted() override;
virtual codegen::StackValue codegen(codegen::Builder& builder, codegen::Scope& scope) override;
@ -39,7 +45,7 @@ namespace AST {
private:
std::string m_name;
public:
ValueReferenceExpression(std::string name) : m_name{ name } {}
ValueReferenceExpression(token::Metadata meta, std::string name) : Expression{ meta }, m_name{ name } {}
virtual ~ValueReferenceExpression() override = default;
virtual std::string formatted() override;
virtual codegen::StackValue codegen(codegen::Builder& builder, codegen::Scope& scope) override;
@ -51,8 +57,15 @@ namespace AST {
types::BinOp m_binop;
std::unique_ptr<Expression> m_rhs;
public:
BinaryOperationExpression(std::unique_ptr<Expression> lhs, types::BinOp op, std::unique_ptr<Expression> rhs)
: m_lhs{ std::move(lhs) }, m_binop{ op }, m_rhs{ std::move(rhs) } {
BinaryOperationExpression(
token::Metadata meta,
std::unique_ptr<Expression> lhs,
types::BinOp op,
std::unique_ptr<Expression> rhs)
: Expression{ meta }
, m_lhs{ std::move(lhs) }
, m_binop{ op }
, m_rhs{ std::move(rhs) } {
}
virtual ~BinaryOperationExpression() override = default;
virtual std::string formatted() override;
@ -64,8 +77,13 @@ namespace AST {
std::unique_ptr<Expression> m_fn_expr;
std::vector<std::unique_ptr<Expression>> m_args;
public:
FunctionCallExpression(std::unique_ptr<Expression> fn_expr, std::vector<std::unique_ptr<Expression>> args)
: m_fn_expr{ std::move(fn_expr) }, m_args{ std::move(args) } {
FunctionCallExpression(
token::Metadata meta,
std::unique_ptr<Expression> fn_expr,
std::vector<std::unique_ptr<Expression>> args)
: Expression{ meta }
, m_fn_expr{ std::move(fn_expr) }
, m_args{ std::move(args) } {
}
virtual ~FunctionCallExpression() override = default;
virtual std::string formatted() override;
@ -77,7 +95,9 @@ namespace AST {
private:
std::unique_ptr<Expression> m_expr;
public:
ReturnStatement(std::unique_ptr<Expression> expr) : m_expr{ std::move(expr) } {}
ReturnStatement(token::Metadata meta, std::unique_ptr<Expression> expr)
: Statement{ meta }, m_expr{ std::move(expr) } {
}
virtual ~ReturnStatement() override = default;
virtual std::string formatted() override;
virtual void codegen(codegen::Builder& builder, codegen::Scope& scope) override;
@ -89,8 +109,15 @@ namespace AST {
std::string m_name;
std::optional<std::unique_ptr<Expression>> m_expr;
public:
InitializationStatement(std::unique_ptr<types::Type> ty, std::string name, std::optional<std::unique_ptr<Expression>> expr)
: m_type{ std::move(ty) }, m_name{ name }, m_expr{ std::move(expr) } {
InitializationStatement(
token::Metadata meta,
std::unique_ptr<types::Type> ty,
std::string name,
std::optional<std::unique_ptr<Expression>> expr)
: Statement{ meta }
, m_type{ std::move(ty) }
, m_name{ name }
, m_expr{ std::move(expr) } {
}
virtual ~InitializationStatement() override = default;
virtual std::string formatted() override;
@ -101,8 +128,8 @@ namespace AST {
private:
std::unique_ptr<Expression> m_expr;
public:
ExpressionStatement(std::unique_ptr<Expression> expr)
: m_expr{ std::move(expr) } {
ExpressionStatement(token::Metadata meta, std::unique_ptr<Expression> expr)
: Statement{ meta }, m_expr{ std::move(expr) } {
}
virtual ~ExpressionStatement() override = default;
virtual std::string formatted() override;
@ -115,10 +142,12 @@ namespace AST {
std::unique_ptr<Statement> m_then;
std::optional<std::unique_ptr<Statement>> m_else;
public:
IfStatement(std::unique_ptr<Expression> condition,
IfStatement(token::Metadata meta,
std::unique_ptr<Expression> condition,
std::unique_ptr<Statement> then_statement,
std::optional<std::unique_ptr<Statement>> else_statement)
: m_condition{ std::move(condition) }
: Statement{ meta }
, m_condition{ std::move(condition) }
, m_then{ std::move(then_statement) }
, m_else{ std::move(else_statement) } {
}
@ -129,6 +158,7 @@ namespace AST {
class TopLevelStatement : public Node {
public:
TopLevelStatement(token::Metadata meta) : Node{ meta } {}
virtual void codegen(codegen::Builder& builder, codegen::Scope& scope) = 0;
};
@ -140,11 +170,13 @@ namespace AST {
std::vector<std::unique_ptr<Statement>> m_statements;
public:
Function(
token::Metadata meta,
std::unique_ptr<types::Type> return_ty,
std::vector<std::pair<std::string, std::unique_ptr<types::Type>>> params,
std::string name,
std::vector<std::unique_ptr<Statement>> statements)
: m_return_ty{ std::move(return_ty) }
: TopLevelStatement{ meta }
, m_return_ty{ std::move(return_ty) }
, m_params{ std::move(params) }
, m_name{ name }
, m_statements{ std::move(statements) } {

View File

@ -1,5 +1,6 @@
#include "types.h"
#include "parsing.h"
#include "tokens.h"
namespace parsing {
@ -28,13 +29,13 @@ namespace parsing {
if (token.type == token::Type::LiteralInt) {
stream.m_position = inner.m_position;
auto expr = new AST::IntLiteralExpression{ std::stoi(token.content) };
auto expr = new AST::IntLiteralExpression{ token.metadata, std::stoi(token.content) };
return new std::unique_ptr<AST::Expression>{ expr };
}
else if (token.type == token::Type::Ident) {
stream.m_position = inner.m_position;
auto expr = new AST::ValueReferenceExpression{ token.content };
auto expr = new AST::ValueReferenceExpression{ token.metadata, token.content };
return new std::unique_ptr<AST::Expression>{ expr };
}
else {
@ -49,6 +50,7 @@ namespace parsing {
Result<std::unique_ptr<AST::Expression>, std::string> parse_primary_expression(token::TokenStream& stream) {
token::TokenStream inner{ stream };
try {
auto before_meta = inner.metadata();
auto plain_expr = parse_plain_expression(inner);
while (inner.peek().content == "(") {
inner.next();
@ -64,7 +66,7 @@ namespace parsing {
inner.expect(token::Type::Symbol, ")");
auto fn_call = new AST::FunctionCallExpression{ plain_expr.unwrap(), std::move(args) };
auto fn_call = new AST::FunctionCallExpression{ before_meta + inner.metadata(), plain_expr.unwrap(), std::move(args) };
plain_expr = new std::unique_ptr<AST::Expression>{ fn_call };
}
@ -115,6 +117,8 @@ namespace parsing {
std::unique_ptr<AST::Expression> parse_rhs(
token::TokenStream& stream, std::unique_ptr<AST::Expression> lhs, int prev_precedence) {
auto before = stream.metadata();
auto binop_res = parse_binop(stream);
while (binop_res.ok()) {
auto binop = binop_res.unwrap();
@ -124,7 +128,7 @@ namespace parsing {
rhs = parse_rhs(stream, std::move(rhs), types::operator_precedence(binop));
}
auto binop_expr = new AST::BinaryOperationExpression{ std::move(lhs), binop, std::move(rhs) };
auto binop_expr = new AST::BinaryOperationExpression{ before + stream.metadata(), std::move(lhs), binop, std::move(rhs) };
lhs = std::unique_ptr<AST::Expression>{ binop_expr };
binop_res = parse_binop(stream);
@ -147,6 +151,9 @@ namespace parsing {
Result<std::unique_ptr<AST::InitializationStatement>, std::string> parse_init_statement(token::TokenStream& stream) {
token::TokenStream inner{ stream };
auto before_meta = inner.metadata();
try {
auto ty = parse_type(inner).unwrap();
auto name = inner.expect(token::Type::Ident);
@ -160,7 +167,7 @@ namespace parsing {
inner.expect(token::Type::Symbol, ";");
stream.m_position = inner.m_position;
auto init = new AST::InitializationStatement{ std::move(ty), name.content, std::move(expr) };
auto init = new AST::InitializationStatement{ before_meta + inner.metadata(), std::move(ty), name.content, std::move(expr) };
return new std::unique_ptr<AST::InitializationStatement>{ init };
}
catch (std::runtime_error& error) {
@ -170,6 +177,7 @@ namespace parsing {
Result<std::unique_ptr<AST::Statement>, std::string> parse_statement(token::TokenStream& stream) {
token::TokenStream inner{ stream };
auto before_meta = inner.metadata();
try {
if (inner.peek().type == token::Type::ReturnKeyword) {
inner.next();
@ -178,7 +186,7 @@ namespace parsing {
stream.m_position = inner.m_position;
auto ret = new AST::ReturnStatement{ std::move(expression) };
auto ret = new AST::ReturnStatement{ before_meta + stream.metadata(),std::move(expression) };
return new std::unique_ptr<AST::Statement>{ ret };
}
else if (inner.peek().type == token::Type::IfKeyword) {
@ -197,6 +205,7 @@ namespace parsing {
stream.m_position = inner.m_position;
auto statement = new AST::IfStatement{
before_meta + stream.metadata(),
std::move(expression),
std::move(then_statement),
std::move(else_statement)
@ -210,7 +219,7 @@ namespace parsing {
else if (auto expr = parse_expression(inner); expr.ok()) {
stream.m_position = inner.m_position;
stream.expect(token::Type::Symbol, ";");
auto expr_statement = new AST::ExpressionStatement{ expr.unwrap() };
auto expr_statement = new AST::ExpressionStatement{ before_meta + stream.metadata(), expr.unwrap() };
return new std::unique_ptr<AST::Statement>{ expr_statement };
}
else {
@ -226,6 +235,7 @@ namespace parsing {
Result<std::unique_ptr<AST::TopLevelStatement>, std::string> parse_top_level_statement(token::TokenStream& stream) {
token::TokenStream inner{ stream };
auto before_meta = inner.metadata();
try {
auto type = parse_type(inner).unwrap();
auto name_token = inner.expect(token::Type::Ident);
@ -257,7 +267,7 @@ namespace parsing {
stream.m_position = inner.m_position;
auto fun = new AST::Function{ std::move(type), std::move(params), name_token.content, std::move(statements) };
auto fun = new AST::Function{ before_meta + stream.metadata(), std::move(type), std::move(params), name_token.content, std::move(statements) };
return new std::unique_ptr<AST::TopLevelStatement>{ fun };
}
catch (std::runtime_error& error) {

View File

@ -57,6 +57,14 @@ namespace token {
return stream;
}
Position operator+(Position pos, Position other) {
return Position{ std::min(pos.line, other.line), std::min(pos.col, other.col) };
}
Metadata operator+(Metadata meta, Metadata other) {
return Metadata{ meta.position + other.position, meta.filename };
}
TokenStream::TokenStream(std::vector<Token>& tokens)
: m_tokens{ tokens }, m_position{ 0 } {
};
@ -95,6 +103,10 @@ namespace token {
throw std::runtime_error("Expected " + type_name(type) + "(" + std::string{ content } + "), got " + next.formatted());
}
Metadata TokenStream::metadata() {
return this->peek(0).metadata;
}
std::vector<token::Token> tokenize(std::string_view text, std::string filename) {
std::vector<token::Token> tokens{};

View File

@ -33,6 +33,8 @@ namespace token {
std::string filename;
};
Metadata operator+(Metadata meta, Metadata other);
struct Token {
Type type;
std::string content;
@ -52,6 +54,7 @@ namespace token {
Token next();
Token expect(Type type);
Token expect(Type type, std::string_view content);
Metadata metadata();
};
std::ostream& operator<<(std::ostream& stream, Token& token);