basic tests

This commit is contained in:
bronku 2025-12-01 11:39:43 +01:00
parent 2a04b62f45
commit 4ae6c97904
25 changed files with 158 additions and 25 deletions

View file

@ -17,11 +17,13 @@ build/lexer.cpp build/lexer.hpp: src/lexer.l build/parser.hpp src/scanner.hpp sr
build/%.o: build/%.cpp
$(CXX) -c $(ARGS) $< -o $@
build/%.o: src/%.cpp | build
$(CXX) -c $(ARGS) $< -o $@
build/main.o: src/main.cpp build src/codegen.hpp
$(CXX) -c $(ARGS) src/main.cpp -o build/main.o
src/ast.hpp: src/ast/base.hpp src/ast/expressions.hpp src/ast/literals.hpp src/ast/operators.hpp src/ast/statements.hpp src/ast/string_utils.hpp
src/codegen.hpp : src/ast.hpp
build:
mkdir -p build

125
src/codegen.hpp Normal file
View file

@ -0,0 +1,125 @@
#pragma once
#include "ast.hpp"
#include <sstream>
class RubyGenerator
{
std::ostringstream output;
int indent_level = 0;
void write_indent()
{
for (int i = 0; i < indent_level; i++)
{
output << " ";
}
}
void write(const std::string &s)
{
output << s;
}
public:
std::string generate(const Module &module)
{
output.str("");
indent_level = 0;
for (const auto &stmt : module.body)
{
generate_stmt(*stmt);
}
return output.str();
}
private:
void generate_stmt(const Stmt &stmt)
{
if (auto *expr_stmt = dynamic_cast<const ExprStmt *>(&stmt))
{
write_indent();
generate_expr(*expr_stmt->expr);
write("\n");
}
else if (auto *assign = dynamic_cast<const Assign *>(&stmt))
{
write_indent();
generate_expr(*assign->target);
write(" = ");
generate_expr(*assign->value);
write("\n");
}
else if (auto *if_stmt = dynamic_cast<const If *>(&stmt))
{
write_indent();
write("if ");
generate_expr(*if_stmt->condition);
write("\n");
indent_level++;
for (const auto &s : if_stmt->then_body)
{
generate_stmt(*s);
}
indent_level--;
if (!if_stmt->else_body.empty())
{
write("else\n");
indent_level++;
for (const auto &s : if_stmt->else_body)
{
generate_stmt(*s);
}
indent_level--;
}
write("end\n");
}
else if (auto *ret = dynamic_cast<const Return *>(&stmt))
{
write_indent();
write("return ");
if (ret->value)
{
generate_expr(*ret->value);
}
write("\n");
}
}
void generate_expr(const Expr &expr)
{
if (auto *num = dynamic_cast<const Number *>(&expr))
{
write(num->value);
}
else if (auto *id = dynamic_cast<const Identifier *>(&expr))
{
write(id->name);
}
else if (auto *str = dynamic_cast<const String *>(&expr))
{
write("\"" + str->value + "\"");
}
else if (auto *binop = dynamic_cast<const BinOp *>(&expr))
{
generate_expr(*binop->left);
write(" " + binop->op.symbol() + " ");
generate_expr(*binop->right);
}
else if (auto *call = dynamic_cast<const Call *>(&expr))
{
generate_expr(*call->func);
write("(");
for (size_t i = 0; i < call->args.size(); i++)
{
if (i > 0)
write(", ");
generate_expr(*call->args[i]);
}
write(")");
}
}
};

View file

@ -1,6 +1,7 @@
#include "parser.hpp"
#include "scanner.hpp"
#include "ast.hpp"
#include "codegen.hpp"
#include <iostream>
#include <fstream>
@ -71,5 +72,9 @@ int main(int argc, char *argv[])
if (ast_dump)
{
std::cout << ast_root->dump();
return 0;
}
RubyGenerator generator;
std::cout << generator.generate(*ast_root);
}

View file

@ -0,0 +1 @@
obj.method()