← index
cplusplus2x.Examples/C++20/scanner/ETL/ast.hpp
Source: cplusplus2x.Examples/C++20/scanner/ETL/ast.hpp
#ifndef AST_HPP
#define AST_HPP

#include <memory>
#include <string>
#include <vector>

namespace ast {

    enum class VarType {
        NUMBER,
        STRING,
        POINTER
    };
    inline std::vector<std::string> VarString{"NUMBER", "STRING", "POINTER"};

    struct ASTNode {
        virtual ~ASTNode() = default;
        virtual std::string text() const = 0; // Pure virtual method to be implemented by subclasses
    };

    struct Expression : ASTNode {};

    struct Statement : ASTNode {
        ~Statement() override = default;
    };

    struct Literal : Expression {
        std::string value;
        types::TokenType type;

        Literal(const std::string &v) : value(v) {}
        Literal(const std::string &v, const types::TokenType &t) : value(v), type{t} {
            if (type == types::TokenType::TT_STR) {
                value = "\"" + value + "\"";
            }
        }

        std::string text() const override {
            return value;
        }
    };

    struct Identifier : Expression {
        std::string name;
        VarType vtype;
        Identifier(const std::string &n) : name(n), vtype{} {}

        std::string text() const override {
            return name;
        }
    };

    struct BinaryOp : Expression {
        types::OperatorType op;
        std::unique_ptr<Expression> left;
        std::unique_ptr<Expression> right;
        bool allocated;

        BinaryOp(types::OperatorType o, std::unique_ptr<Expression> l, std::unique_ptr<Expression> r, bool a = false)
            : op(o), left(std::move(l)), right(std::move(r)), allocated(a) {}

        std::string text() const override {
            return "(" + left->text() + " " + types::opName[static_cast<unsigned int>(op)] + " " + right->text() + ")";
        }
    };

    struct UnaryOp : Expression {
        types::OperatorType op;
        std::unique_ptr<Expression> operand;

        UnaryOp(types::OperatorType o, std::unique_ptr<Expression> e)
            : op(o), operand(std::move(e)) {}

        std::string text() const override {
            return types::opName[static_cast<unsigned int>(op)] + operand->text();
        }
    };

    struct Call : Statement, Expression {
        std::string functionName;
        std::vector<std::unique_ptr<Expression>> arguments;
        VarType vtype;
        Call(const std::string &name, std::vector<std::unique_ptr<Expression>> args)
            : functionName(name), arguments(std::move(args)), vtype{} {}

        std::string text() const override {
            std::string result = functionName + "(";
            for (size_t i = 0; i < arguments.size(); ++i) {
                result += arguments[i]->text();
                if (i < arguments.size() - 1) {
                    result += ", ";
                }
            }
            result += ")";
            return result;
        }
    };

    struct Assignment : Statement {
        std::unique_ptr<Expression> left;
        std::unique_ptr<Expression> right;
        VarType vtype;
        bool there = false;

        Assignment(std::unique_ptr<Expression> l, std::unique_ptr<Expression> r, VarType vtype = VarType::NUMBER, bool there = false)
            : left(std::move(l)), right(std::move(r)), vtype(vtype), there(there) {}

        std::string text() const override {
            return left->text() + " = " + right->text() + ";";
        }
    };

    struct Return : Statement {
        std::unique_ptr<Expression> return_value;
        bool allocated;

        Return(std::unique_ptr<Expression> rt, bool a = false) : return_value(std::move(rt)), allocated(false) {}

        std::string text() const override {
            return "return " + return_value->text() + ";";
        }
    };

    struct IfStatement : Statement {
        std::unique_ptr<Expression> condition;
        std::vector<std::unique_ptr<ASTNode>> if_body;
        std::vector<std::unique_ptr<ASTNode>> else_body;

        IfStatement(std::unique_ptr<Expression> cond,
                    std::vector<std::unique_ptr<ASTNode>> if_b,
                    std::vector<std::unique_ptr<ASTNode>> else_b = {})
            : condition(std::move(cond)), if_body(std::move(if_b)), else_body(std::move(else_b)) {}

        std::string text() const override {
            std::string result = "if (" + condition->text() + ") {\n";

            for (const auto &stmt : if_body) {
                result += "  " + stmt->text() + "\n";
            }
            result += "}";

            if (!else_body.empty()) {
                result += " else {\n";
                for (const auto &stmt : else_body) {
                    result += "  " + stmt->text() + "\n";
                }
                result += "}";
            }
            return result;
        }
    };

    struct Break : Statement {
        std::string text() const override {
            return "break;";
        }
    };

    struct Continue : Statement {
        std::string text() const override {
            return "continue;";
        }
    };

    struct WhileStatement : Statement {
        std::unique_ptr<Expression> condition;
        std::vector<std::unique_ptr<ASTNode>> body;

        WhileStatement(std::unique_ptr<Expression> cond,
                       std::vector<std::unique_ptr<ASTNode>> b)
            : condition(std::move(cond)), body(std::move(b)) {}

        std::string text() const override {
            std::ostringstream oss;
            oss << "while (" << condition->text() << ") {\n";

            for (const auto &statement : body) {
                oss << "    " << statement->text() << "\n";
            }
            oss << "}";
            return oss.str();
        }
    };

    struct ForStatement : Statement {
        std::unique_ptr<Expression> condition;
        std::unique_ptr<Assignment> init_statement, post;
        std::vector<std::unique_ptr<ASTNode>> body;

        ForStatement(std::unique_ptr<Assignment> init_x, std::unique_ptr<Expression> cond, std::unique_ptr<Assignment> p,
                     std::vector<std::unique_ptr<ASTNode>> b)
            : init_statement(std::move(init_x)), condition(std::move(cond)), post(std::move(p)), body(std::move(b)) {}

        std::string text() const override {
            std::ostringstream oss;
            oss << "for (" << init_statement->text() << ";" << condition->text() << ";" << post->text() << ") {\n";

            for (const auto &statement : body) {
                oss << "    " << statement->text() << "\n";
            }
            oss << "}";
            return oss.str();
        }
    };

    struct Function : ASTNode {
        std::string name;
        std::vector<std::unique_ptr<ASTNode>> body;
        std::vector<std::pair<std::string, VarType>> parameters;
        ast::VarType return_type;
        Function(const std::string &n, const std::vector<std::pair<std::string, VarType>> &p, VarType vt) : name(n), parameters(std::move(p)), return_type{vt} {}
        Function(const std::string &n) : name{n} {}
        std::string text() const override {
            std::string result = "function " + name + "() {\n";
            for (const auto &stmt : body) {
                result += "  " + stmt->text() + "\n";
            }
            result += "}";
            return result;
        }
    };

    struct DefineFunction : ASTNode {
        std::string name;
        std::vector<std::unique_ptr<ASTNode>> body;
        std::vector<std::pair<std::string, VarType>> parameters;
        ast::VarType return_type;
        DefineFunction(const std::string &n, const std::vector<std::pair<std::string, VarType>> &p, VarType vt) : name(n), parameters(std::move(p)), return_type{vt} {}
        DefineFunction(const std::string &n) : name{n} {}
        std::string text() const override {
            std::string result = "define " + name + "(";
            for (auto &i : parameters) {
                result += i.first + " ";
            }
            result += ")";
            return result;
        }
    };

    struct Program : ASTNode {
        std::vector<std::unique_ptr<ASTNode>> body;

        Program() = default;

        std::string text() const override {
            std::string result;
            for (const auto &stmt : body) {
                result += stmt->text() + "\n";
            }
            return result;
        }
    };

} // namespace ast

#endif