Major refactoring, expect bugs

This commit is contained in:
2025-10-04 11:50:46 +10:00
parent d9cd88625e
commit 44e8c673a0
18 changed files with 397 additions and 298 deletions

View File

@@ -7,12 +7,12 @@
Value handleListOp(std::vector<Value> args) {
// listName idx = value
if (args.size() == 4 && args[2].valtype == ValueType::Real && args[2].real == "=") {
if (args.size() == 4 && args[2].valtype == ValueType::Identifier && args[2].string_val == "=") {
std::string var_name;
if (args[0].valtype == ValueType::Variable) {
var_name = args[0].varName.key;
} else if (args[0].valtype == ValueType::Real) {
var_name = args[0].real;
} else if (args[0].valtype == ValueType::Identifier) {
var_name = args[0].string_val;
} else {
error("Invalid target for indexed assignment");
return Value();
@@ -22,6 +22,11 @@ Value handleListOp(std::vector<Value> args) {
Value index_val = evaluate(args[1]);
Value new_val = evaluate(args[3]);
if (subject.valtype != ValueType::List) {
error("Indexed assignment can only be performed on a list");
return Value();
}
handleListSet(var_name, subject, index_val, new_val);
return Value();
}
@@ -35,31 +40,28 @@ Value handleListGet(const Value& subject, const std::vector<Value>& args) {
return Value();
}
Value accessor = args[0];
if (accessor.valtype != ValueType::Real) {
error("List accessor must be a real value");
if (accessor.valtype == ValueType::String && accessor.string_val == "size") {
return Value((long long)subject.list.size());
}
if (accessor.valtype != ValueType::Int) {
error("List accessor must be an integer or \"size\"");
return Value();
}
if (accessor.real == "size") {
return Value(std::to_string(subject.list.size()));
}
if (mathstuff::strisdigit(accessor.real)) {
int index = std::stoi(accessor.real);
int index = accessor.int_val;
if (index < 0 || (size_t)index >= subject.list.size()) {
error("List index out of bounds");
return Value();
}
return subject.list.at(index);
}
error("Invalid list accessor");
return Value();
}
void handleListSet(std::string var_name, Value& subject, const Value& index_val, const Value& new_val) {
if (index_val.valtype != ValueType::Real || !mathstuff::strisdigit(index_val.real)) {
if (index_val.valtype != ValueType::Int) {
error("Index must be an integer");
return;
}
int index = std::stoi(index_val.real);
long long index = index_val.int_val;
if (index < 0 || (size_t)index >= subject.list.size()) {
error("List index out of bounds");
@@ -84,12 +86,8 @@ std::vector<Value> parseListContent(const std::string& content) {
// End of an item
std::string trimmed = trim(current_item);
if (!trimmed.empty()) {
if (trimmed.front() == '"' && trimmed.back() == '"') {
items.push_back(Value(trimmed.substr(1, trimmed.length() - 2)));
} else {
items.push_back(Value(trimmed));
}
}
current_item.clear();
} else {
if (c == '[' || c == '(') nested_level++;
@@ -101,12 +99,8 @@ std::vector<Value> parseListContent(const std::string& content) {
// Last item
std::string trimmed = trim(current_item);
if (!trimmed.empty()) {
if (trimmed.front() == '"' && trimmed.back() == '"') {
items.push_back(Value(trimmed.substr(1, trimmed.length() - 2)));
} else {
items.push_back(Value(trimmed));
}
}
return items;
}

View File

@@ -5,12 +5,12 @@
#include "../../utils/evaluate/evaluate.h"
Value handleStringOp(std::vector<Value> args) {
if (args.size() == 4 && args[2].valtype == ValueType::Real && args[2].real == "=") {
if (args.size() == 4 && args[2].valtype == ValueType::Identifier && args[2].string_val == "=") {
std::string var_name;
if (args[0].valtype == ValueType::Variable) {
var_name = args[0].varName.key;
} else if (args[0].valtype == ValueType::Real) {
var_name = args[0].real;
} else if (args[0].valtype == ValueType::Identifier) {
var_name = args[0].string_val;
} else {
error("Invalid target for indexed assignment");
return Value();
@@ -20,10 +20,16 @@ Value handleStringOp(std::vector<Value> args) {
Value index_val = evaluate(args[1]);
Value new_val = evaluate(args[3]);
if (subject.valtype != ValueType::String) {
error("Indexed assignment can only be performed on a string");
return Value();
}
handleStringSet(var_name, subject, index_val, new_val);
return Value();
}
return Value();
}
Value handleStringGet(const Value& subject, const std::vector<Value>& args) {
@@ -32,40 +38,37 @@ Value handleStringGet(const Value& subject, const std::vector<Value>& args) {
return Value();
}
Value accessor = args[0];
if (accessor.valtype != ValueType::Real) {
error("String accessor must be a real value");
if (accessor.valtype != ValueType::Int) {
if (accessor.valtype == ValueType::String && accessor.string_val == "size") {
return Value((long long)subject.string_val.length());
}
error("String accessor must be an integer or \"size\"");
return Value();
}
if (accessor.real == "size") {
return Value(std::to_string(subject.real.length()));
}
if (mathstuff::strisdigit(accessor.real)) {
int index = std::stoi(accessor.real);
if (index < 0 || (size_t)index >= subject.real.length()) {
int index = accessor.int_val;
if (index < 0 || (size_t)index >= subject.string_val.length()) {
error("String index out of bounds");
return Value();
}
return Value(std::string(1, subject.real.at(index)));
}
error("Invalid string accessor");
return Value();
return Value(std::string(1, subject.string_val.at(index)));
}
void handleStringSet(std::string var_name, Value& subject, const Value& index_val, const Value& new_val) {
if (index_val.valtype != ValueType::Real || !mathstuff::strisdigit(index_val.real)) {
if (index_val.valtype != ValueType::Int) {
error("Index must be an integer");
return;
}
int index = std::stoi(index_val.real);
long long index = index_val.int_val;
if (new_val.valtype != ValueType::Real || new_val.real.length() != 1) {
if (new_val.valtype != ValueType::String || new_val.string_val.length() != 1) {
error("Can only assign a single character to a string index");
return;
}
if (index < 0 || (size_t)index >= subject.real.length()) {
if (index < 0 || (size_t)index >= subject.string_val.length()) {
error("String index out of bounds");
return;
}
subject.real[index] = new_val.real[0];
subject.string_val[index] = new_val.string_val[0];
data::modifyValue(var_name, subject);
}

View File

@@ -5,6 +5,7 @@
#include <memory>
#include <utility>
#include "../datatypes/lists/lists.h"
#include "../utils/trim/trim.h"
InstructionType strToInstructionType(std::string in) {
if (in == "println") return InstructionType::Println;
@@ -18,6 +19,7 @@ InstructionType strToInstructionType(std::string in) {
else if (in == "input") return InstructionType::Input;
else if (in == "return") return InstructionType::Return;
else if (in == "concat") return InstructionType::Concat;
else if (in == "split") return InstructionType::Split;
else return InstructionType::Variable;
}
@@ -43,12 +45,12 @@ Instruction::Instruction(std::vector<std::string> toks) {
Instruction::Instruction(std::vector<Value> toks) {
if (!toks.empty()) {
// Check type of value in first token, then compute token
if (toks[0].valtype == ValueType::Real) {
instruction = strToInstructionType(toks[0].real);
if (toks[0].valtype == ValueType::Identifier) {
instruction = strToInstructionType(toks[0].string_val);
} else if (toks[0].valtype == ValueType::Variable) {
instruction = InstructionType::Variable;
} else {
error("Instruction should be a real or variable value");
error("Instruction should be an identifier or variable value");
}
if (instruction == InstructionType::Variable) {
for (const auto& tok : toks) {
@@ -65,17 +67,57 @@ Instruction::Instruction(std::vector<Value> toks) {
}
}
Value::Value(std::string stringval) : valtype(ValueType::Real), real(stringval) {}
Value::Value(std::string stringval) {
// This constructor will attempt to parse the string into the most specific type possible.
if (stringval.length() >= 2 && stringval.front() == '"' && stringval.back() == '"') {
valtype = ValueType::String;
string_val = stringval.substr(1, stringval.length() - 2);
return;
}
if (stringval.empty()) {
valtype = ValueType::String;
string_val = "";
return;
}
// Try to parse as an integer
try {
size_t pos;
int_val = std::stoll(stringval, &pos);
if (pos == stringval.length()) {
valtype = ValueType::Int;
return;
}
} catch (const std::exception&) {}
// Try to parse as a double
try {
size_t pos;
double_val = std::stod(stringval, &pos);
if (pos == stringval.length()) {
valtype = ValueType::Double;
return;
}
} catch (const std::exception&) {}
// Default to an identifier
valtype = ValueType::Identifier;
string_val = stringval;
}
Value::Value(long long intval) : valtype(ValueType::Int), int_val(intval) {}
Value::Value(double doubleval) : valtype(ValueType::Double), double_val(doubleval) {}
Value::Value(Instruction instval) : valtype(ValueType::Processed), processed(std::make_unique<Instruction>(std::move(instval))) {}
Value::Value() : valtype(ValueType::Real) {}
Value::Value() : valtype(ValueType::String) {}
Value::Value(InstructionGroup instgroup) : valtype(ValueType::InstructionGroup), instructionGroup(instgroup) {};
Value::Value(std::vector<Value> listval) : valtype(ValueType::List), list(std::move(listval)) {}
Value::Value(const Value& other) : valtype(other.valtype), real(other.real), varName(other.varName), instructionGroup(other.instructionGroup), list(other.list) {
Value::Value(const Value& other) : valtype(other.valtype), string_val(other.string_val), int_val(other.int_val), double_val(other.double_val), instructionGroup(other.instructionGroup), list(other.list), varName(other.varName) {
if (other.processed) {
processed = std::make_unique<Instruction>(*other.processed);
}
@@ -89,7 +131,9 @@ Varname::Varname() : key("") {}
Value& Value::operator=(const Value& other) {
if (this != &other) {
valtype = other.valtype;
real = other.real;
string_val = other.string_val;
int_val = other.int_val;
double_val = other.double_val;
varName = other.varName;
instructionGroup = other.instructionGroup;
list = other.list;
@@ -105,8 +149,17 @@ Value& Value::operator=(const Value& other) {
std::string Value::toString() const {
std::string out = "Value(type: ";
switch (valtype) {
case ValueType::Real:
out += "Real, value: " + real + ")";
case ValueType::String:
out += "String, value: " + string_val + ")";
break;
case ValueType::Int:
out += "Int, value: " + std::to_string(int_val) + ")";
break;
case ValueType::Double:
out += "Double, value: " + std::to_string(double_val) + ")";
break;
case ValueType::Identifier:
out += "Identifier, value: " + string_val + ")";
break;
case ValueType::Processed:
out += "Processed, value: ";
@@ -213,6 +266,7 @@ std::vector<Value> split(std::string line) {
}
} else if (chr == '"') {
instring = !instring;
buf += chr;
} else {
buf += chr;
}

View File

@@ -6,11 +6,11 @@
enum class InstructionType {
None, Print, Println, Math, Let, Variable, Exit, If, While, Input, Compare, Function, Return, Concat
None, Print, Println, Math, Let, Variable, Exit, If, While, Input, Compare, Function, Return, Concat, Split
};
enum class ValueType {
Real, Processed, Variable, InstructionGroup, List, Map
Processed, Variable, InstructionGroup, List, Map, String, Int, Double, Identifier
};
struct Instruction;
@@ -29,15 +29,19 @@ struct Varname {
};
struct Value {
ValueType valtype = ValueType::Real;
ValueType valtype = ValueType::String;
std::unique_ptr<Instruction> processed;
std::string real = "";
std::string string_val = "";
long long int_val = 0;
double double_val = 0.0;
InstructionGroup instructionGroup;
std::vector<Value> list;
bool is_return = false;
std::string toString() const;
Varname varName = Varname();
Value(std::string stringval);
Value(long long intval);
Value(double doubleval);
Value(Instruction instval);
Value(InstructionGroup instgroup);
Value(std::vector<Value> listval);
@@ -60,5 +64,4 @@ struct Instruction {
std::vector<Value> split(std::string in);
InstructionType strToInstructionType(std::string in);
std::string trim(const std::string& str);
extern bool inReplMode;

View File

@@ -14,6 +14,7 @@
#include "../modules/compare/compare.h"
#include "../modules/input/input.h"
#include "../modules/function/function.h"
#include "../modules/split/split.h"
// Forward declaration for mutual recursion
Value evaluate(Value val);
@@ -34,54 +35,18 @@ Value execute(Instruction inst) {
}
if (inst.instruction == InstructionType::Variable) {
auto& args = inst.args;
if (args.empty()) {
return data::getValue(args[0].varName.key);
}
// Special reassignment
if (args[1].real != "=") {
switch (args[0].valtype) {
case ValueType::List:
handleListOp(args);
break;
case ValueType::Real:
handleStringOp(args);
break;
default:
error("Working on it!");
break;
}
}
// Simple reassignment: myVar = 20
if (args.size() == 3 && args[1].valtype == ValueType::Real && args[1].real == "=") {
if (args[0].valtype != ValueType::Real) {
error("The target of an assignment must be a variable name.");
return Value();
}
std::string var_name = args[0].real;
Value new_val = evaluate(args[2]);
data::modifyValue(var_name, new_val);
error("Empty variable instruction");
return Value();
}
// GET operations and function calls
Value subject = evaluate(args[0]);
std::vector<Value> op_args(args.begin() + 1, args.end());
if (!op_args.empty()) {
if (subject.valtype == ValueType::List) {
return handleListGet(subject, op_args);
} else if (subject.valtype == ValueType::Real) {
return handleStringGet(subject, op_args);
}
}
// Function call
if (args[0].valtype == ValueType::Real && data::functions.count(args[0].real)) {
const auto& func = data::functions.at(args[0].real);
// Function call: func arg1 arg2 ...
// This must be checked before variable evaluation, in case a variable has the same name as a function.
if (args[0].valtype == ValueType::Identifier && data::functions.count(args[0].string_val)) {
const auto& func = data::functions.at(args[0].string_val);
if (func.arg_names.size() != args.size() - 1) {
error("Function " + args[0].real + " expects " + std::to_string(func.arg_names.size()) + " arguments, but got " + std::to_string(args.size() - 1));
error("Function " + args[0].string_val + " expects " + std::to_string(func.arg_names.size()) + " arguments, but got " + std::to_string(args.size() - 1));
return Value();
}
data::pushScope();
@@ -101,8 +66,65 @@ Value execute(Instruction inst) {
return return_val;
}
// If we get here, it's just a variable by itself, so return its value.
return subject;
// Indexed assignment: $var index = value
if (args.size() == 4 && args[2].valtype == ValueType::Identifier && args[2].string_val == "=") {
std::string var_name;
if (args[0].valtype == ValueType::Variable) {
var_name = args[0].varName.key;
} else if (args[0].valtype == ValueType::Identifier) {
var_name = args[0].string_val;
} else {
error("The target of an indexed assignment must be a variable name.");
return Value();
}
Value subject = data::getValue(var_name);
if (subject.valtype == ValueType::List) {
return handleListOp(args);
} else if (subject.valtype == ValueType::String) { // strings are Real
return handleStringOp(args);
} else {
error("Indexed assignment is only for lists and strings.");
return Value();
}
}
// Simple assignment: $var = value
if (args.size() == 3 && args[1].valtype == ValueType::Identifier && args[1].string_val == "=") {
std::string var_name;
if (args[0].valtype == ValueType::Variable) {
var_name = args[0].varName.key;
} else if (args[0].valtype == ValueType::Identifier) {
var_name = args[0].string_val;
} else {
error("The target of an assignment must be a variable name.");
return Value();
}
Value new_val = evaluate(args[2]);
data::modifyValue(var_name, new_val);
return Value();
}
// Variable access or indexed get
// If args[0] is an Identifier and there are no args, it's a variable access.
if (args[0].valtype == ValueType::Identifier && args.empty()) {
return data::getValue(args[0].string_val);
}
Value subject = evaluate(args[0]);
std::vector<Value> op_args(args.begin() + 1, args.end());
if (op_args.empty()) {
return subject; // Just variable access
}
// Indexed get: subject index
if (subject.valtype == ValueType::List) {
return handleListGet(subject, op_args);
} else if (subject.valtype == ValueType::String) {
return handleStringGet(subject, op_args); }
error("Unknown variable or function call: " + args[0].toString());
return Value();
}
// For all other instructions, evaluate the arguments first
@@ -122,6 +144,8 @@ Value execute(Instruction inst) {
return modules::compare(inst.args);
case InstructionType::Input:
return modules::input(inst.args);
case InstructionType::Split:
return modules::split(inst.args);
case InstructionType::Exit:
return modules::exit(inst.args);
case InstructionType::Return: {

View File

@@ -8,38 +8,48 @@ Value modules::compare(std::vector<Value> values) {
return Value("0");
}
if (values[0].valtype != ValueType::Real || values[1].valtype != ValueType::Real || values[2].valtype != ValueType::Real) {
error("Compare arguments must be real values for now");
Value& lhs = values[0];
Value& rhs = values[2];
Value& op_val = values[1];
if (op_val.valtype != ValueType::Identifier) {
error("Comparison operator must be an identifier");
return Value("0");
}
std::string op = op_val.string_val;
std::string op = values[1].real;
bool is_lhs_numeric = lhs.valtype == ValueType::Int || lhs.valtype == ValueType::Double;
bool is_rhs_numeric = rhs.valtype == ValueType::Int || rhs.valtype == ValueType::Double;
if (mathstuff::strisdigit(values[0].real) && mathstuff::strisdigit(values[2].real)) {
int lhs = std::stoi(values[0].real);
int rhs = std::stoi(values[2].real);
if (is_lhs_numeric && is_rhs_numeric) {
double lhs_d = (lhs.valtype == ValueType::Int) ? lhs.int_val : lhs.double_val;
double rhs_d = (rhs.valtype == ValueType::Int) ? rhs.int_val : rhs.double_val;
bool result = false;
if (op == "==") result = (lhs == rhs);
else if (op == "!=") result = (lhs != rhs);
else if (op == ">") result = (lhs > rhs);
else if (op == "<") result = (lhs < rhs);
else if (op == ">=") result = (lhs >= rhs);
else if (op == "<=") result = (lhs <= rhs);
if (op == "==") result = (lhs_d == rhs_d);
else if (op == "!=") result = (lhs_d != rhs_d);
else if (op == ">") result = (lhs_d > rhs_d);
else if (op == "<") result = (lhs_d < rhs_d);
else if (op == ">=") result = (lhs_d >= rhs_d);
else if (op == "<=") result = (lhs_d <= rhs_d);
else {
error("Unknown comparison operator: " + op);
error("Unknown comparison operator for numbers: " + op);
}
return Value(result ? "1" : "0");
} else if (lhs.valtype == ValueType::String && rhs.valtype == ValueType::String) {
std::string lhs_s = lhs.string_val;
std::string rhs_s = rhs.string_val;
bool result = false;
if (op == "==") result = (lhs_s == rhs_s);
else if (op == "!=") result = (lhs_s != rhs_s);
else {
error("Unknown comparison operator for strings: " + op);
}
return Value(result ? "1" : "0");
} else {
std::string lhs = values[0].real;
std::string rhs = values[2].real;
bool result = false;
if (op == "==") result = (lhs == rhs);
else if (op == "!=") result = (lhs != rhs);
else {
error("Unknown comparison operator: " + op);
}
return Value(result ? "1" : "0");
// For now, only allow comparing numbers with numbers and strings with strings
error("Mismatched types in comparison");
return Value("0");
}
}

View File

@@ -6,11 +6,20 @@
Value modules::concat(std::vector<Value> args) {
std::string buf;
for (Value val : args) {
if (val.valtype == ValueType::Real) {
buf += val.real;
} else {
error("Can only concatenate real values");
switch (val.valtype) {
case ValueType::String:
buf += val.string_val;
break;
case ValueType::Int:
buf += std::to_string(val.int_val);
break;
case ValueType::Double:
buf += std::to_string(val.double_val);
break;
default:
error("Can only concatenate String, Int, and Double values");
break;
}
}
return buf;
return Value(buf);
}

View File

@@ -4,8 +4,8 @@
#include "../math/math.h"
Value modules::exit(std::vector<Value> args) {
if (args.size() > 0 && args[0].valtype == ValueType::Real && mathstuff::strisdigit(args[0].real)) {
std::exit(stoi(args[0].real));
if (args.size() > 0 && args[0].valtype == ValueType::Int) {
std::exit(args[0].int_val);
} else {
std::exit(0);
}

View File

@@ -19,20 +19,20 @@ Value modules::fndef(std::vector<Value> args) {
// First arg is the name
Value name_val = args[0];
if (name_val.valtype != ValueType::Real) {
error("Syntax error: function name must be a real value");
if (name_val.valtype != ValueType::Identifier) {
error("Syntax error: function name must be an identifier");
return Value();
}
std::string func_name = name_val.real;
std::string func_name = name_val.string_val;
// In-between args are the argument names
std::vector<std::string> arg_names;
for (size_t i = 1; i < args.size() - 1; ++i) {
if (args[i].valtype != ValueType::Real) {
error("Syntax error: function argument names must be real values");
if (args[i].valtype != ValueType::Identifier) {
error("Syntax error: function argument names must be identifiers");
return Value();
}
arg_names.push_back(args[i].real);
arg_names.push_back(args[i].string_val);
}
// Create and store the function

View File

@@ -19,10 +19,22 @@ Value modules::ifs(std::vector<Value> args) {
Value condition_result = execute(*args[0].processed);
bool is_true = false;
if (condition_result.valtype == ValueType::Real) {
if (condition_result.real != "0" && condition_result.real != "false" && !condition_result.real.empty()) {
is_true = true;
}
switch (condition_result.valtype) {
case ValueType::Int:
is_true = (condition_result.int_val != 0);
break;
case ValueType::Double:
is_true = (condition_result.double_val != 0.0);
break;
case ValueType::String:
is_true = (!condition_result.string_val.empty() && condition_result.string_val != "false");
break;
case ValueType::List:
is_true = (!condition_result.list.empty());
break;
default:
is_true = false;
break;
}
Value return_val;

View File

@@ -2,21 +2,23 @@
#include "../../data/data.h"
#include "../../defs/defs.h"
#include "../../error/error.h"
#include "../../utils/evaluate/evaluate.h"
#include <map>
#include <string>
Value modules::let(std::vector<Value> values) {
std::string varName;
if (values.size() > 0) {
if (values[0].valtype == ValueType::Real) {
varName = values[0].real;
if (values[0].valtype == ValueType::Identifier) {
varName = values[0].string_val;
} else {
error("FIXME unprocessed processed (in let module)");
error("Variable name in let must be an identifier");
return Value();
}
if (values.size() > 1) {
if (values[1].valtype == ValueType::Real && values[1].real == "=") {
if (values[1].valtype == ValueType::Identifier && values[1].string_val == "=") {
if (values.size() > 2) {
data::scopes.back()[varName] = values[2];
data::scopes.back()[varName] = evaluate(values[2]);
} else {
error("Expecting value after token '=' (in let module)");
}

View File

@@ -2,8 +2,9 @@
#include "../../defs/defs.h"
#include "../../error/error.h"
#include <vector>
#include <cmath>
mathstuff::Part::Part(int in) {
mathstuff::Part::Part(double in) {
num = in;
}
@@ -12,128 +13,107 @@ mathstuff::Part::Part(mathstuff::Operators in) {
op = in;
}
bool mathstuff::strisdigit(std::string in) {
for (char c : in) {
if (!isdigit(c)) return false;
}
return true;
}
Value modules::math(std::vector<Value> values) {
std::vector<mathstuff::Part> expression;
for (Value value : values) {
if (value.valtype == ValueType::Real) {
if (value.real == "+") {
if (value.valtype == ValueType::Int) {
expression.push_back(mathstuff::Part((double)value.int_val));
} else if (value.valtype == ValueType::Double) {
expression.push_back(mathstuff::Part(value.double_val));
} else if (value.valtype == ValueType::Identifier) {
if (value.string_val == "+") {
expression.push_back(mathstuff::Part(mathstuff::Operators::Add));
} else if (value.real == "-") {
} else if (value.string_val == "-") {
expression.push_back(mathstuff::Part(mathstuff::Operators::Subtract));
} else if (value.real == "*") {
} else if (value.string_val == "*") {
expression.push_back(mathstuff::Part(mathstuff::Operators::Multiply));
} else if (value.real == "/") {
} else if (value.string_val == "/") {
expression.push_back(mathstuff::Part(mathstuff::Operators::Divide));
} else if (value.real == "^") {
} else if (value.string_val == "^") {
expression.push_back(mathstuff::Part(mathstuff::Operators::Power));
} else if (value.real == "%") {
} else if (value.string_val == "%") {
expression.push_back(mathstuff::Part(mathstuff::Operators::Mod));
} else {
if (mathstuff::strisdigit(value.real)) {
expression.push_back(mathstuff::Part(std::stoi(value.real)));
} else {
error("Expected an integer or operator (in math module)");
}
error("Invalid string operator in math module: " + value.string_val);
}
} else {
error("FIXME unprocessed process (in math module)");
error("Invalid value type in math module");
}
}
// Power
size_t i = 0;
while (i < expression.size()) {
for (size_t i = 0; i < expression.size(); ) {
if (expression[i].isOperator && expression[i].op == mathstuff::Operators::Power) {
if (i >= expression.size() || expression[i + 1].isOperator) {
error("Expecting number after * (in math module)");
}
if (i == 0 || expression[i - 1].isOperator) {
error("Expecting number after * (in math module)");
}
expression[i] = mathstuff::Part(expression[i - 1].num * expression[i + 1].num);
expression.erase(std::next(expression.begin(), i + 1));
expression.erase(std::next(expression.begin(), i - 1));
if (i == 0 || i + 1 >= expression.size() || expression[i - 1].isOperator || expression[i + 1].isOperator) {
error("Syntax error in math expression around power operator");
return Value();
}
expression[i - 1].num = pow(expression[i - 1].num, expression[i + 1].num);
expression.erase(expression.begin() + i, expression.begin() + i + 2);
} else {
i++;
}
}
// Modulo
i = 0;
while (i < expression.size()) {
for (size_t i = 0; i < expression.size(); ) {
if (expression[i].isOperator && expression[i].op == mathstuff::Operators::Mod) {
if (i >= expression.size() || expression[i + 1].isOperator) {
error("Expecting number after % (in math module)");
}
if (i == 0 || expression[i - 1].isOperator) {
error("Expecting number after % (in math module)");
}
expression[i] = mathstuff::Part(expression[i - 1].num % expression[i + 1].num);
expression.erase(std::next(expression.begin(), i + 1));
expression.erase(std::next(expression.begin(), i - 1));
if (i == 0 || i + 1 >= expression.size() || expression[i - 1].isOperator || expression[i + 1].isOperator) {
error("Syntax error in math expression around modulo operator");
return Value();
}
expression[i - 1].num = fmod(expression[i - 1].num, expression[i + 1].num);
expression.erase(expression.begin() + i, expression.begin() + i + 2);
} else {
i++;
}
}
// Multiplication + Division
i = 0;
while (i < expression.size()) {
if (expression[i].isOperator && expression[i].op == mathstuff::Operators::Multiply) {
if (i >= expression.size() || expression[i + 1].isOperator) {
error("Expecting number after * (in math module)");
for (size_t i = 0; i < expression.size(); ) {
if (expression[i].isOperator && (expression[i].op == mathstuff::Operators::Multiply || expression[i].op == mathstuff::Operators::Divide)) {
if (i == 0 || i + 1 >= expression.size() || expression[i - 1].isOperator || expression[i + 1].isOperator) {
error("Syntax error in math expression around multiply/divide operator");
return Value();
}
if (i == 0 || expression[i - 1].isOperator) {
error("Expecting number after * (in math module)");
}
expression[i] = mathstuff::Part(expression[i - 1].num * expression[i + 1].num);
expression.erase(std::next(expression.begin(), i + 1));
expression.erase(std::next(expression.begin(), i - 1));
} else if (expression[i].isOperator && expression[i].op == mathstuff::Operators::Divide) {
if (i >= expression.size() || expression[i].isOperator) {
error("Expecting number after / (in math module)");
}
if (i == 0 || expression[i].isOperator) {
error("Expecting number after / (in math module)");
}
expression[i] = mathstuff::Part(expression[i - 1].num / expression[i + 1].num);
expression.erase(std::next(expression.begin(), i + 1));
expression.erase(std::next(expression.begin(), i - 1));
if (expression[i].op == mathstuff::Operators::Multiply) {
expression[i - 1].num *= expression[i + 1].num;
} else {
expression[i - 1].num /= expression[i + 1].num;
}
expression.erase(expression.begin() + i, expression.begin() + i + 2);
} else {
i++;
}
}
// Addition + Subtraction
i = 0;
while (i < expression.size()) {
if (expression[i].isOperator && expression[i].op == mathstuff::Operators::Add) {
if (i >= expression.size() || expression[i + 1].isOperator) {
error("Expecting number after + (in math module)");
for (size_t i = 0; i < expression.size(); ) {
if (expression[i].isOperator && (expression[i].op == mathstuff::Operators::Add || expression[i].op == mathstuff::Operators::Subtract)) {
if (i == 0 || i + 1 >= expression.size() || expression[i - 1].isOperator || expression[i + 1].isOperator) {
error("Syntax error in math expression around add/subtract operator");
return Value();
}
if (i == 0 || expression[i - 1].isOperator) {
error("Expecting number after + (in math module)");
}
expression[i] = mathstuff::Part(expression[i - 1].num + expression[i + 1].num);
expression.erase(std::next(expression.begin(), i + 1));
expression.erase(std::next(expression.begin(), i - 1));
} else if (expression[i].isOperator && expression[i].op == mathstuff::Operators::Subtract) {
if (i >= expression.size() || expression[i].isOperator) {
error("Expecting number after - (in math module)");
}
if (i == 0 || expression[i].isOperator) {
error("Expecting number after - (in math module)");
}
expression[i] = mathstuff::Part(expression[i - 1].num - expression[i + 1].num);
expression.erase(std::next(expression.begin(), i + 1));
expression.erase(std::next(expression.begin(), i - 1));
if (expression[i].op == mathstuff::Operators::Add) {
expression[i - 1].num += expression[i + 1].num;
} else {
expression[i - 1].num -= expression[i + 1].num;
}
expression.erase(expression.begin() + i, expression.begin() + i + 2);
} else {
i++;
}
}
return Value(std::to_string(expression[0].num));
if (expression.size() != 1 || expression[0].isOperator) {
error("Invalid math expression result");
return Value();
}
double result = expression[0].num;
if (result == floor(result)) {
return Value((long long)result);
} else {
return Value(result);
}
}

View File

@@ -8,13 +8,11 @@ namespace mathstuff {
Add, Subtract, Multiply, Divide, Mod, Power, None
};
bool strisdigit(std::string in);
struct Part {
Part(int in);
Part(double in);
Part(Operators in);
bool isOperator = false;
int num = 0;
double num = 0;
Operators op = Operators::None;
};
}

View File

@@ -7,25 +7,38 @@
Value modules::print(std::vector<Value> values) {
for (Value value : values) {
if (value.valtype == ValueType::Real) {
std::cout << value.real;
if (values.size() > 1) {
std::cout << " ";
}
} else if (value.valtype == ValueType::List) {
switch (value.valtype) {
case ValueType::String:
std::cout << value.string_val;
break;
case ValueType::Int:
std::cout << value.int_val;
break;
case ValueType::Double:
std::cout << value.double_val;
break;
case ValueType::List: {
std::cout << "[";
bool afterfirst = false;
for (Value val : value.list) {
if (afterfirst) {
std::cout << ", ";
} else {
}
else {
afterfirst = true;
}
print({val});
}
std::cout << "]";
} else {
error("FIXME unprocessed processed (in print module)");
break;
}
default:
error("FIXME: Unhandled type in print module");
break;
}
if (values.size() > 1) {
std::cout << " ";
}
}
return Value("");

View File

@@ -19,10 +19,22 @@ Value modules::whiles(std::vector<Value> args) {
Value condition_result = execute(*args[0].processed);
bool is_true = false;
if (condition_result.valtype == ValueType::Real) {
if (condition_result.real != "0" && condition_result.real != "false" && !condition_result.real.empty()) {
is_true = true;
}
switch (condition_result.valtype) {
case ValueType::Int:
is_true = (condition_result.int_val != 0);
break;
case ValueType::Double:
is_true = (condition_result.double_val != 0.0);
break;
case ValueType::String:
is_true = (!condition_result.string_val.empty() && condition_result.string_val != "false");
break;
case ValueType::List:
is_true = (!condition_result.list.empty());
break;
default:
is_true = false;
break;
}
Value return_val;
@@ -37,10 +49,22 @@ Value modules::whiles(std::vector<Value> args) {
condition_result = execute(*args[0].processed);
is_true = false;
if (condition_result.valtype == ValueType::Real) {
if (condition_result.real != "0" && condition_result.real != "false" && !condition_result.real.empty()) {
is_true = true;
}
switch (condition_result.valtype) {
case ValueType::Int:
is_true = (condition_result.int_val != 0);
break;
case ValueType::Double:
is_true = (condition_result.double_val != 0.0);
break;
case ValueType::String:
is_true = (!condition_result.string_val.empty() && condition_result.string_val != "false");
break;
case ValueType::List:
is_true = (!condition_result.list.empty());
break;
default:
is_true = false;
break;
}
}

View File

@@ -1,5 +1,6 @@
#include "parser.h"
#include "../error/error.h"
#include "../utils/trim/trim.h"
#include <string>
#include <vector>

View File

@@ -1,22 +0,0 @@
#include "vars.h"
#include "../data/data.h"
#include "../defs/defs.h"
#include "../error/error.h"
#include <vector>
#include <string>
Value varmod(std::vector<Value> args) {
if (args.size() < 3) {
error("Not enough args to reassign variable");
}
if (args[1].real != "=") {
error("Expecting '=' token");
}
if (args[0].valtype == ValueType::Real) {
data::modifyValue(args[0].real, args[2]);
} else {
error("Invalid variable name for assignment");
}
return Value("");
}

View File

@@ -1,6 +0,0 @@
#pragma once
#include "../defs/defs.h"
#include <vector>
Value varmod(std::vector<Value> args);