A simple scripting language in C++
Ferenc Szontágh
2025-04-18 a76181288ae27b85521838ee87352727c3cba2f8
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
#ifndef PARSEREXPRESSION_BUILDER_HPP
#define PARSEREXPRESSION_BUILDER_HPP
 
#include <memory>
#include <stdexcept>
 
#include "Interpreter/BinaryExpressionNode.hpp"
#include "Interpreter/ExpressionNode.hpp"
#include "Interpreter/IdentifierExpressionNode.hpp"
#include "Interpreter/LiteralExpressionNode.hpp"
#include "Interpreter/UnaryExpressionNode.hpp"  // <-- új include
#include "Interpreter/CallExpressionNode.hpp"
#include "Parser/ParsedExpression.hpp"
 
namespace Parser {
static std::unique_ptr<Interpreter::ExpressionNode> buildExpressionFromParsed(
    const ParsedExpressionPtr & expr) {
    using Kind = ParsedExpression::Kind;
 
    switch (expr->kind) {
        case Kind::Literal:
            return std::make_unique<Interpreter::LiteralExpressionNode>(expr->value);
 
        case Kind::Variable:
            return std::make_unique<Interpreter::IdentifierExpressionNode>(expr->name);
 
        case Kind::Binary:
            {
                auto lhs = buildExpressionFromParsed(expr->lhs);
                auto rhs = buildExpressionFromParsed(expr->rhs);
                return std::make_unique<Interpreter::BinaryExpressionNode>(std::move(lhs), expr->op, std::move(rhs));
            }
 
        case Kind::Unary:
            {
                auto operand = buildExpressionFromParsed(expr->rhs);  // rhs az operandus
                return std::make_unique<Interpreter::UnaryExpressionNode>(expr->op, std::move(operand));
            }
        case Kind::Call:
            {
                // Build argument expressions
                std::vector<std::unique_ptr<Interpreter::ExpressionNode>> callArgs;
                callArgs.reserve(expr->args.size());
                for (const auto &arg : expr->args) {
                    callArgs.push_back(buildExpressionFromParsed(arg));
                }
                return std::make_unique<Interpreter::CallExpressionNode>(expr->name, std::move(callArgs));
            }
    }
 
    throw std::runtime_error("Unknown ParsedExpression kind");
}
 
void typecheckParsedExpression(const ParsedExpressionPtr & expr) {
    using Kind = ParsedExpression::Kind;
 
    switch (expr->kind) {
        case Kind::Literal:
            {
                // Literál típusának ellenőrzése - a literál típusát a value.getType() adja vissza
                // auto type = expr->value.getType();
                // Nem szükséges semmilyen más típusellenőrzés a literálokhoz, mivel azok fix típusúak.
                break;
            }
 
        case Kind::Variable:
            {
                const std::string ns     = Symbols::SymbolContainer::instance()->currentScopeName() + ".variables";
                auto              symbol = Symbols::SymbolContainer::instance()->get(ns, expr->name);
                if (!symbol) {
                    throw std::runtime_error("Variable not found in symbol table: " + expr->name);
                }
 
                // Ha a szimbólum nem egy változó, akkor hibát dobunk
                if (symbol->getKind() == Symbols::Kind::Function) {
                    throw std::runtime_error("Cannot use function as variable: " + expr->name);
                }
                break;
            }
 
        case Kind::Binary:
            {
                // Bináris kifejezés operandusainak típusellenőrzése
                typecheckParsedExpression(expr->lhs);
                typecheckParsedExpression(expr->rhs);
 
                auto lhsType = expr->lhs->getType();
                auto rhsType = expr->rhs->getType();
 
                if (lhsType != rhsType) {
                    throw std::runtime_error(
                        "Type mismatch in binary expression: " + Symbols::Variables::TypeToString(lhsType) + " and " +
                        Symbols::Variables::TypeToString(rhsType));
                }
 
                // Bináris operátoroknál is elvégezhetjük a típusellenőrzést:
                // Ha numerikus operátor, akkor az operandusoknak numerikusnak kell lenniük
                if (expr->op == "+" || expr->op == "-" || expr->op == "*" || expr->op == "/") {
                    if (lhsType != Symbols::Variables::Type::INTEGER && lhsType != Symbols::Variables::Type::FLOAT) {
                        throw std::runtime_error("Operands must be numeric for operator: " + expr->op);
                    }
                }
                // Ha logikai operátorok, akkor boolean típus szükséges
                else if (expr->op == "&&" || expr->op == "||") {
                    if (lhsType != Symbols::Variables::Type::BOOLEAN) {
                        throw std::runtime_error("Operands must be boolean for operator: " + expr->op);
                    }
                }
                break;
            }
 
        case Kind::Unary:
            {
                // Unáris kifejezés operandusának típusellenőrzése
                typecheckParsedExpression(expr->rhs);  // 'rhs' tárolja az operandust az unáris kifejezésnél
 
                auto operandType = expr->rhs->getType();
 
                if (expr->op == "!") {
                    if (operandType != Symbols::Variables::Type::BOOLEAN) {
                        throw std::runtime_error("Operand must be boolean for unary operator '!'");
                    }
                }
                break;
            }
 
        default:
            throw std::runtime_error("Unknown expression kind");
    }
}
 
}  // namespace Parser
 
#endif  // PARSEREXPRESSION_BUILDER_HPP