Major refactoring, expect bugs
This commit is contained in:
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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: {
|
||||
|
||||
@@ -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");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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)");
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
};
|
||||
}
|
||||
|
||||
@@ -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("");
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
#include "parser.h"
|
||||
#include "../error/error.h"
|
||||
#include "../utils/trim/trim.h"
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
|
||||
@@ -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("");
|
||||
}
|
||||
@@ -1,6 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
#include "../defs/defs.h"
|
||||
#include <vector>
|
||||
|
||||
Value varmod(std::vector<Value> args);
|
||||
Reference in New Issue
Block a user