Basic math support
This commit is contained in:
@@ -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];
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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();
|
||||
|
||||
Reference in New Issue
Block a user