diff --git a/src/datatypes/lists/lists.cpp b/src/datatypes/lists/lists.cpp index cd61974..1a1fde3 100644 --- a/src/datatypes/lists/lists.cpp +++ b/src/datatypes/lists/lists.cpp @@ -7,12 +7,12 @@ Value handleListOp(std::vector 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 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& 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())); + + int index = accessor.int_val; + if (index < 0 || (size_t)index >= subject.list.size()) { + error("List index out of bounds"); + return Value(); } - if (mathstuff::strisdigit(accessor.real)) { - int index = std::stoi(accessor.real); - 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(); + return subject.list.at(index); } 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,11 +86,7 @@ std::vector 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)); - } + items.push_back(Value(trimmed)); } current_item.clear(); } else { @@ -101,11 +99,7 @@ std::vector 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)); - } + items.push_back(Value(trimmed)); } return items; diff --git a/src/datatypes/strings/strings.cpp b/src/datatypes/strings/strings.cpp index d175573..6d1db8c 100644 --- a/src/datatypes/strings/strings.cpp +++ b/src/datatypes/strings/strings.cpp @@ -5,12 +5,12 @@ #include "../../utils/evaluate/evaluate.h" Value handleStringOp(std::vector 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 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& args) { @@ -32,40 +38,37 @@ Value handleStringGet(const Value& subject, const std::vector& 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())); + + int index = accessor.int_val; + if (index < 0 || (size_t)index >= subject.string_val.length()) { + error("String index out of bounds"); + return Value(); } - if (mathstuff::strisdigit(accessor.real)) { - int index = std::stoi(accessor.real); - if (index < 0 || (size_t)index >= subject.real.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); } diff --git a/src/defs/defs.cpp b/src/defs/defs.cpp index 5bc4848..88f58f6 100644 --- a/src/defs/defs.cpp +++ b/src/defs/defs.cpp @@ -5,6 +5,7 @@ #include #include #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 toks) { Instruction::Instruction(std::vector 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 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(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 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(*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 split(std::string line) { } } else if (chr == '"') { instring = !instring; + buf += chr; } else { buf += chr; } diff --git a/src/defs/defs.h b/src/defs/defs.h index 693d8ea..90e3cff 100644 --- a/src/defs/defs.h +++ b/src/defs/defs.h @@ -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 processed; - std::string real = ""; + std::string string_val = ""; + long long int_val = 0; + double double_val = 0.0; InstructionGroup instructionGroup; std::vector 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 listval); @@ -60,5 +64,4 @@ struct Instruction { std::vector split(std::string in); InstructionType strToInstructionType(std::string in); -std::string trim(const std::string& str); extern bool inReplMode; diff --git a/src/executor/executor.cpp b/src/executor/executor.cpp index a3db619..1b43b3a 100644 --- a/src/executor/executor.cpp +++ b/src/executor/executor.cpp @@ -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 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 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: { diff --git a/src/modules/compare/compare.cpp b/src/modules/compare/compare.cpp index 66d399b..105ad54 100644 --- a/src/modules/compare/compare.cpp +++ b/src/modules/compare/compare.cpp @@ -8,38 +8,48 @@ Value modules::compare(std::vector 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"); } } diff --git a/src/modules/concat/concat.cpp b/src/modules/concat/concat.cpp index a7434b7..acb1d84 100644 --- a/src/modules/concat/concat.cpp +++ b/src/modules/concat/concat.cpp @@ -6,11 +6,20 @@ Value modules::concat(std::vector 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); } diff --git a/src/modules/exit/exit.cpp b/src/modules/exit/exit.cpp index a490dcb..1c39360 100644 --- a/src/modules/exit/exit.cpp +++ b/src/modules/exit/exit.cpp @@ -4,8 +4,8 @@ #include "../math/math.h" Value modules::exit(std::vector 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); } diff --git a/src/modules/function/function.cpp b/src/modules/function/function.cpp index 9c31e05..7d6576e 100644 --- a/src/modules/function/function.cpp +++ b/src/modules/function/function.cpp @@ -19,20 +19,20 @@ Value modules::fndef(std::vector 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 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 diff --git a/src/modules/if/if.cpp b/src/modules/if/if.cpp index fbed957..f2d0593 100644 --- a/src/modules/if/if.cpp +++ b/src/modules/if/if.cpp @@ -19,10 +19,22 @@ Value modules::ifs(std::vector 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; diff --git a/src/modules/let/let.cpp b/src/modules/let/let.cpp index 791ef31..0c3f1bc 100644 --- a/src/modules/let/let.cpp +++ b/src/modules/let/let.cpp @@ -2,21 +2,23 @@ #include "../../data/data.h" #include "../../defs/defs.h" #include "../../error/error.h" +#include "../../utils/evaluate/evaluate.h" #include #include Value modules::let(std::vector 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)"); } diff --git a/src/modules/math/math.cpp b/src/modules/math/math.cpp index 9994676..62a266e 100644 --- a/src/modules/math/math.cpp +++ b/src/modules/math/math.cpp @@ -2,8 +2,9 @@ #include "../../defs/defs.h" #include "../../error/error.h" #include +#include -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 values) { std::vector 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 || i + 1 >= expression.size() || expression[i - 1].isOperator || expression[i + 1].isOperator) { + error("Syntax error in math expression around power 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)); + expression[i - 1].num = pow(expression[i - 1].num, expression[i + 1].num); + expression.erase(expression.begin() + i, expression.begin() + i + 2); + } else { + i++; } - 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 || i + 1 >= expression.size() || expression[i - 1].isOperator || expression[i + 1].isOperator) { + error("Syntax error in math expression around modulo 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)); + expression[i - 1].num = fmod(expression[i - 1].num, expression[i + 1].num); + expression.erase(expression.begin() + i, expression.begin() + i + 2); + } else { + i++; } - 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)"); + 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[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)); + expression.erase(expression.begin() + i, expression.begin() + i + 2); + } else { + i++; } - 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)"); + 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[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)); + expression.erase(expression.begin() + i, expression.begin() + i + 2); + } else { + i++; } - 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); + } } diff --git a/src/modules/math/math.h b/src/modules/math/math.h index 712f4a6..a51e699 100644 --- a/src/modules/math/math.h +++ b/src/modules/math/math.h @@ -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; }; } diff --git a/src/modules/print/print.cpp b/src/modules/print/print.cpp index 5854db3..4f3ebd4 100644 --- a/src/modules/print/print.cpp +++ b/src/modules/print/print.cpp @@ -7,25 +7,38 @@ Value modules::print(std::vector 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) { - std::cout << "["; - bool afterfirst = false; - for (Value val : value.list) { - if (afterfirst) { - std::cout << ", "; - } else { - afterfirst = true; + 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 { + afterfirst = true; + } + print({val}); } - print({val}); + std::cout << "]"; + break; } - std::cout << "]"; - } else { - error("FIXME unprocessed processed (in print module)"); + default: + error("FIXME: Unhandled type in print module"); + break; + } + + if (values.size() > 1) { + std::cout << " "; } } return Value(""); diff --git a/src/modules/while/while.cpp b/src/modules/while/while.cpp index 22b451c..c89a08a 100644 --- a/src/modules/while/while.cpp +++ b/src/modules/while/while.cpp @@ -19,10 +19,22 @@ Value modules::whiles(std::vector 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 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; } } diff --git a/src/parser/parser.cpp b/src/parser/parser.cpp index 601f070..0bf3f17 100644 --- a/src/parser/parser.cpp +++ b/src/parser/parser.cpp @@ -1,5 +1,6 @@ #include "parser.h" #include "../error/error.h" +#include "../utils/trim/trim.h" #include #include diff --git a/src/vars/vars.cpp b/src/vars/vars.cpp deleted file mode 100644 index 25159bd..0000000 --- a/src/vars/vars.cpp +++ /dev/null @@ -1,22 +0,0 @@ -#include "vars.h" - -#include "../data/data.h" -#include "../defs/defs.h" -#include "../error/error.h" -#include -#include - -Value varmod(std::vector 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(""); -} diff --git a/src/vars/vars.h b/src/vars/vars.h deleted file mode 100644 index 2892ec7..0000000 --- a/src/vars/vars.h +++ /dev/null @@ -1,6 +0,0 @@ -#pragma once - -#include "../defs/defs.h" -#include - -Value varmod(std::vector args);