Basic math support

This commit is contained in:
2025-10-30 10:55:21 +00:00
parent 7c633c334c
commit 817cf5a1a9
6 changed files with 264 additions and 8 deletions

View File

@@ -82,6 +82,116 @@ void Executor::printValue(const ASTValue& arg) {
}
}
ASTValue Executor::evaluateOperator(const std::shared_ptr<ASTOperator>& op) {
std::vector<ASTValue> stack;
auto args = op->getArguments();
for (const auto& arg : args) {
if (std::holds_alternative<ASTNode>(arg)) {
ASTNode node = std::get<ASTNode>(arg);
if (std::holds_alternative<std::shared_ptr<ASTValue>>(node)) {
stack.push_back(*std::get<std::shared_ptr<ASTValue>>(node));
} else if (std::holds_alternative<std::shared_ptr<ASTIdentifier>>(node)) {
std::string varName = std::get<std::shared_ptr<ASTIdentifier>>(node)->name;
if (variables.count(varName)) {
Object obj = variables[varName];
if (!obj.isCustomObject && std::holds_alternative<ASTValue>(obj.value)) {
stack.push_back(std::get<ASTValue>(obj.value));
} else {
std::cout << "Variable " << varName << " is not a value in expression" << std::endl;
exit(1);
}
} else {
std::cout << "Undefined variable " << varName << " in expression" << std::endl;
exit(1);
}
}
} else { // It's an OperatorType
OperatorType opType = std::get<OperatorType>(arg);
if (stack.size() < 2) {
std::cout << "Syntax error in expression: not enough operands for operator" << std::endl;
exit(1);
}
ASTValue right = stack.back();
stack.pop_back();
ASTValue left = stack.back();
stack.pop_back();
if ((left.type == ValueType::Int || left.type == ValueType::Float) &&
(right.type == ValueType::Int || right.type == ValueType::Float)) {
double l = left.type == ValueType::Int ? (double)left.getInt().value() : left.getFloat().value();
double r = right.type == ValueType::Int ? (double)right.getInt().value() : right.getFloat().value();
bool resultIsFloat = left.type == ValueType::Float || right.type == ValueType::Float;
switch (opType) {
case OperatorType::Add:
resultIsFloat ? stack.emplace_back(l + r) : stack.emplace_back((long long)(l + r));
break;
case OperatorType::Subtract:
resultIsFloat ? stack.emplace_back(l - r) : stack.emplace_back((long long)(l - r));
break;
case OperatorType::Multiply:
resultIsFloat ? stack.emplace_back(l * r) : stack.emplace_back((long long)(l * r));
break;
case OperatorType::Divide:
if (r == 0) { std::cout << "Division by zero" << std::endl; exit(1); }
stack.emplace_back(l / r);
break;
case OperatorType::Equal:
stack.emplace_back(l == r);
break;
case OperatorType::Inequal:
stack.emplace_back(l != r);
break;
case OperatorType::Greater:
stack.emplace_back(l > r);
break;
case OperatorType::GreaterEqual:
stack.emplace_back(l >= r);
break;
case OperatorType::Less:
stack.emplace_back(l < r);
break;
case OperatorType::LessEqual:
stack.emplace_back(l <= r);
break;
default:
std::cout << "Unsupported operator for numeric types" << std::endl;
exit(1);
}
} else if (left.type == ValueType::String && opType == OperatorType::Add) {
std::string r_str;
if (right.type == ValueType::String) r_str = right.getString().value();
else if (right.type == ValueType::Int) r_str = std::to_string(right.getInt().value());
else if (right.type == ValueType::Float) r_str = std::to_string(right.getFloat().value());
else if (right.type == ValueType::Bool) r_str = right.getBool().value() ? "true" : "false";
else { std::cout << "Unsupported type for string concatenation" << std::endl; exit(1); }
stack.emplace_back(left.getString().value() + r_str);
} else if (left.type == ValueType::Bool && right.type == ValueType::Bool) {
bool l = left.getBool().value();
bool r = right.getBool().value();
switch (opType) {
case OperatorType::Equal: stack.emplace_back(l == r); break;
case OperatorType::Inequal: stack.emplace_back(l != r); break;
default: std::cout << "Unsupported operator for booleans" << std::endl; exit(1);
}
}
else {
std::cout << "Unsupported operand types in expression" << std::endl;
exit(1);
}
}
}
if (stack.size() != 1) {
std::cout << "Invalid expression" << std::endl;
exit(1);
}
return stack.back();
}
std::optional<ASTNode> Executor::consume() {
if (iterator < code.nodes.size()) {
return code.nodes[iterator++];
@@ -141,6 +251,10 @@ Executor::Executor(ASTCodeBlock in, bool isInitCall, std::map<std::string, Objec
if (node.has_value()) {
// for if we see an identifier
if (std::holds_alternative<std::shared_ptr<ASTIdentifier>>(node.value())) {
if (std::holds_alternative<std::shared_ptr<ASTOperator>>(node.value())) {
evaluateOperator(std::get<std::shared_ptr<ASTOperator>>(node.value()));
continue;
}
std::optional<ASTNode> next = consume();
if (next.has_value()) {
// function assignment
@@ -159,6 +273,9 @@ Executor::Executor(ASTCodeBlock in, bool isInitCall, std::map<std::string, Objec
variables.emplace(std::get<std::shared_ptr<ASTIdentifier>>(node.value())->name, *std::get<std::shared_ptr<ASTValue>>(valueNode.value()));
} else if (std::holds_alternative<std::shared_ptr<ASTFunction>>(valueNode.value())) {
variables.emplace(std::get<std::shared_ptr<ASTIdentifier>>(node.value())->name, *std::get<std::shared_ptr<ASTFunction>>(valueNode.value()));
} else if (std::holds_alternative<std::shared_ptr<ASTOperator>>(valueNode.value())) {
ASTValue result = evaluateOperator(std::get<std::shared_ptr<ASTOperator>>(valueNode.value()));
variables.emplace(std::get<std::shared_ptr<ASTIdentifier>>(node.value())->name, result);
} else {
std::cout << "Expected value or function after = sign" << std::endl;
exit(1);
@@ -188,6 +305,9 @@ Executor::Executor(ASTCodeBlock in, bool isInitCall, std::map<std::string, Objec
if (variables.find(std::get<std::shared_ptr<ASTIdentifier>>(callArgNode)->name) != variables.end()) {
callArgs.push_back(variables[std::get<std::shared_ptr<ASTIdentifier>>(callArgNode)->name]);
}
} else if (std::holds_alternative<std::shared_ptr<ASTOperator>>(callArgNode)) {
ASTValue result = evaluateOperator(std::get<std::shared_ptr<ASTOperator>>(callArgNode));
callArgs.emplace_back(result);
}
}
@@ -288,7 +408,12 @@ Executor::Executor(ASTCodeBlock in, bool isInitCall, std::map<std::string, Objec
}
if (arg.getBool().value()) {
if (std::holds_alternative<std::shared_ptr<ASTCodeBlock>>(block.value())) {
Executor(*std::get<std::shared_ptr<ASTCodeBlock>>(block.value()), false, variables);
Executor newExecutor(*std::get<std::shared_ptr<ASTCodeBlock>>(block.value()), false, variables);
for (const auto& [key, value] : newExecutor.getVariables()) {
if (variables.find(key) != variables.end()) {
variables[key] = newExecutor.getVariables()[key];
}
}
}
}
} else if (fnName == "while") {
@@ -315,7 +440,12 @@ Executor::Executor(ASTCodeBlock in, bool isInitCall, std::map<std::string, Objec
if (arg.getBool().value()) {
while (arg.getBool().value()) {
if (std::holds_alternative<std::shared_ptr<ASTCodeBlock>>(block.value())) {
Executor(*std::get<std::shared_ptr<ASTCodeBlock>>(block.value()), false, variables);
Executor newExecutor(*std::get<std::shared_ptr<ASTCodeBlock>>(block.value()), false, variables);
for (const auto& [key, value] : newExecutor.getVariables()) {
if (variables.find(key) != variables.end()) {
variables[key] = newExecutor.getVariables()[key];
}
}
}
}
}

View File

@@ -36,6 +36,7 @@ class Executor {
std::optional<ASTNode> consume();
std::optional<ASTNode> peek(int ahead = 1);
void printValue(const ASTValue& arg);
ASTValue evaluateOperator(const std::shared_ptr<ASTOperator>& op);
public:
explicit Executor(ASTCodeBlock in, bool isInitCall = false, std::map<std::string, Object> scopeVals = {}, std::vector<Object> args = {});
std::map<std::string, Object> getVariables();