Refactoring datatypes start (unstable)
This commit is contained in:
@@ -1,53 +0,0 @@
|
||||
#include "lists.h"
|
||||
|
||||
// Helper to trim whitespace from the start and end of a string
|
||||
std::string trim(const std::string& str) {
|
||||
size_t first = str.find_first_not_of(" \t\n\r");
|
||||
if (std::string::npos == first) {
|
||||
return str;
|
||||
}
|
||||
size_t last = str.find_last_not_of(" \t\n\r");
|
||||
return str.substr(first, (last - first + 1));
|
||||
}
|
||||
|
||||
std::vector<Value> parse_list_content(const std::string& content) {
|
||||
std::vector<Value> items;
|
||||
std::string current_item;
|
||||
bool in_string = false;
|
||||
int nested_level = 0;
|
||||
|
||||
for (char c : content) {
|
||||
if (c == '"') {
|
||||
in_string = !in_string;
|
||||
}
|
||||
|
||||
if (c == ',' && !in_string && nested_level == 0) {
|
||||
// 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++;
|
||||
if (c == ']' || c == ')') nested_level--;
|
||||
current_item += c;
|
||||
}
|
||||
}
|
||||
|
||||
// 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;
|
||||
}
|
||||
@@ -1,8 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
#include <vector>
|
||||
#include <string>
|
||||
#include "../defs/defs.h"
|
||||
|
||||
std::vector<Value> parse_list_content(const std::string& content);
|
||||
std::string trim(const std::string& str);
|
||||
112
src/datatypes/lists/lists.cpp
Normal file
112
src/datatypes/lists/lists.cpp
Normal file
@@ -0,0 +1,112 @@
|
||||
#include "lists.h"
|
||||
#include "../../error/error.h"
|
||||
#include "../../modules/math/math.h"
|
||||
#include "../../data/data.h"
|
||||
#include "../../utils/trim/trim.h"
|
||||
#include "../../utils/evaluate/evaluate.h"
|
||||
|
||||
Value handleListOp(std::vector<Value> args) {
|
||||
// listName idx = value
|
||||
if (args.size() == 4 && args[2].valtype == ValueType::Real && args[2].real == "=") {
|
||||
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 {
|
||||
error("Invalid target for indexed assignment");
|
||||
return Value();
|
||||
}
|
||||
|
||||
Value subject = data::getValue(var_name);
|
||||
Value index_val = evaluate(args[1]);
|
||||
Value new_val = evaluate(args[3]);
|
||||
|
||||
handleListSet(var_name, subject, index_val, new_val);
|
||||
return Value();
|
||||
}
|
||||
|
||||
return Value();
|
||||
}
|
||||
|
||||
Value handleListGet(const Value& subject, const std::vector<Value>& args) {
|
||||
if (args.size() != 1) {
|
||||
error("Invalid number of arguments for list access");
|
||||
return Value();
|
||||
}
|
||||
Value accessor = args[0];
|
||||
if (accessor.valtype != ValueType::Real) {
|
||||
error("List accessor must be a real value");
|
||||
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);
|
||||
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)) {
|
||||
error("Index must be an integer");
|
||||
return;
|
||||
}
|
||||
int index = std::stoi(index_val.real);
|
||||
|
||||
if (index < 0 || (size_t)index >= subject.list.size()) {
|
||||
error("List index out of bounds");
|
||||
return;
|
||||
}
|
||||
subject.list[index] = new_val;
|
||||
data::modifyValue(var_name, subject);
|
||||
}
|
||||
|
||||
std::vector<Value> parseListContent(const std::string& content) {
|
||||
std::vector<Value> items;
|
||||
std::string current_item;
|
||||
bool in_string = false;
|
||||
int nested_level = 0;
|
||||
|
||||
for (char c : content) {
|
||||
if (c == '"') {
|
||||
in_string = !in_string;
|
||||
}
|
||||
|
||||
if (c == ',' && !in_string && nested_level == 0) {
|
||||
// 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++;
|
||||
if (c == ']' || c == ')') nested_level--;
|
||||
current_item += c;
|
||||
}
|
||||
}
|
||||
|
||||
// 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;
|
||||
}
|
||||
10
src/datatypes/lists/lists.h
Normal file
10
src/datatypes/lists/lists.h
Normal file
@@ -0,0 +1,10 @@
|
||||
#pragma once
|
||||
|
||||
#include <vector>
|
||||
#include <string>
|
||||
#include "../../defs/defs.h"
|
||||
|
||||
Value handleListOp(std::vector<Value> args);
|
||||
std::vector<Value> parseListContent(const std::string& content);
|
||||
Value handleListGet(const Value& subject, const std::vector<Value>& args);
|
||||
void handleListSet(std::string var_name, Value& subject, const Value& index_val, const Value& new_val);
|
||||
71
src/datatypes/strings/strings.cpp
Normal file
71
src/datatypes/strings/strings.cpp
Normal file
@@ -0,0 +1,71 @@
|
||||
#include "strings.h"
|
||||
#include "../../error/error.h"
|
||||
#include "../../modules/math/math.h"
|
||||
#include "../../data/data.h"
|
||||
#include "../../utils/evaluate/evaluate.h"
|
||||
|
||||
Value handleStringOp(std::vector<Value> args) {
|
||||
if (args.size() == 4 && args[2].valtype == ValueType::Real && args[2].real == "=") {
|
||||
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 {
|
||||
error("Invalid target for indexed assignment");
|
||||
return Value();
|
||||
}
|
||||
|
||||
Value subject = data::getValue(var_name);
|
||||
Value index_val = evaluate(args[1]);
|
||||
Value new_val = evaluate(args[3]);
|
||||
|
||||
handleStringSet(var_name, subject, index_val, new_val);
|
||||
return Value();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
Value handleStringGet(const Value& subject, const std::vector<Value>& args) {
|
||||
if (args.size() != 1) {
|
||||
error("Invalid number of arguments for string access");
|
||||
return Value();
|
||||
}
|
||||
Value accessor = args[0];
|
||||
if (accessor.valtype != ValueType::Real) {
|
||||
error("String accessor must be a real value");
|
||||
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()) {
|
||||
error("String index out of bounds");
|
||||
return Value();
|
||||
}
|
||||
return Value(std::string(1, subject.real.at(index)));
|
||||
}
|
||||
error("Invalid string accessor");
|
||||
return Value();
|
||||
}
|
||||
|
||||
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)) {
|
||||
error("Index must be an integer");
|
||||
return;
|
||||
}
|
||||
int index = std::stoi(index_val.real);
|
||||
|
||||
if (new_val.valtype != ValueType::Real || new_val.real.length() != 1) {
|
||||
error("Can only assign a single character to a string index");
|
||||
return;
|
||||
}
|
||||
if (index < 0 || (size_t)index >= subject.real.length()) {
|
||||
error("String index out of bounds");
|
||||
return;
|
||||
}
|
||||
subject.real[index] = new_val.real[0];
|
||||
data::modifyValue(var_name, subject);
|
||||
}
|
||||
8
src/datatypes/strings/strings.h
Normal file
8
src/datatypes/strings/strings.h
Normal file
@@ -0,0 +1,8 @@
|
||||
#pragma once
|
||||
|
||||
#include "../../defs/defs.h"
|
||||
#include <vector>
|
||||
|
||||
Value handleStringOp(std::vector<Value> args);
|
||||
Value handleStringGet(const Value& subject, const std::vector<Value>& args);
|
||||
void handleStringSet(std::string var_name, Value& subject, const Value& index_val, const Value& new_val);
|
||||
@@ -4,7 +4,7 @@
|
||||
#include <string>
|
||||
#include <memory>
|
||||
#include <utility>
|
||||
#include "../datatypes/lists.h"
|
||||
#include "../datatypes/lists/lists.h"
|
||||
|
||||
InstructionType strToInstructionType(std::string in) {
|
||||
if (in == "println") return InstructionType::Println;
|
||||
@@ -45,8 +45,10 @@ Instruction::Instruction(std::vector<Value> toks) {
|
||||
// Check type of value in first token, then compute token
|
||||
if (toks[0].valtype == ValueType::Real) {
|
||||
instruction = strToInstructionType(toks[0].real);
|
||||
} else if (toks[0].valtype == ValueType::Variable) {
|
||||
instruction = InstructionType::Variable;
|
||||
} else {
|
||||
error("Instruction should be a real");
|
||||
error("Instruction should be a real or variable value");
|
||||
}
|
||||
if (instruction == InstructionType::Variable) {
|
||||
for (const auto& tok : toks) {
|
||||
@@ -202,7 +204,7 @@ std::vector<Value> split(std::string line) {
|
||||
if (bracket_type == '(') {
|
||||
splitvals.push_back(Value(Instruction(split(buf))));
|
||||
} else {
|
||||
splitvals.push_back(Value(parse_list_content(buf)));
|
||||
splitvals.push_back(Value(parseListContent(buf)));
|
||||
}
|
||||
buf = "";
|
||||
}
|
||||
|
||||
@@ -2,7 +2,8 @@
|
||||
#include "../defs/defs.h"
|
||||
#include "../data/data.h"
|
||||
#include "../error/error.h"
|
||||
#include "../vars/vars.h"
|
||||
#include "../datatypes/lists/lists.h"
|
||||
#include "../datatypes/strings/strings.h"
|
||||
#include "../modules/println/println.h"
|
||||
#include "../modules/print/print.h"
|
||||
#include "../modules/math/math.h"
|
||||
@@ -13,10 +14,12 @@
|
||||
#include "../modules/compare/compare.h"
|
||||
#include "../modules/input/input.h"
|
||||
#include "../modules/function/function.h"
|
||||
#include "../modules/concat/concat.h"
|
||||
|
||||
// Forward declaration for mutual recursion
|
||||
Value evaluate(Value val);
|
||||
|
||||
Value execute(Instruction inst) {
|
||||
// Special cases that need to manage their own argument evaluation
|
||||
// Special cases that don't evaluate their arguments first
|
||||
if (inst.instruction == InstructionType::Let) {
|
||||
return modules::let(inst.args);
|
||||
}
|
||||
@@ -29,89 +32,98 @@ Value execute(Instruction inst) {
|
||||
if (inst.instruction == InstructionType::Function) {
|
||||
return modules::fndef(inst.args);
|
||||
}
|
||||
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);
|
||||
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);
|
||||
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));
|
||||
return Value();
|
||||
}
|
||||
data::pushScope();
|
||||
for (size_t i = 0; i < func.arg_names.size(); ++i) {
|
||||
Value arg_val = evaluate(args[i+1]);
|
||||
data::scopes.back()[func.arg_names[i]] = arg_val;
|
||||
}
|
||||
Value return_val;
|
||||
for (const auto& body_inst : func.body) {
|
||||
return_val = execute(body_inst);
|
||||
if (return_val.is_return) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
data::popScope();
|
||||
return_val.is_return = false;
|
||||
return return_val;
|
||||
}
|
||||
|
||||
// If we get here, it's just a variable by itself, so return its value.
|
||||
return subject;
|
||||
}
|
||||
|
||||
// For all other instructions, evaluate the arguments first
|
||||
size_t i = 0;
|
||||
while (i < inst.args.size()) {
|
||||
bool evaluated = false;
|
||||
if (inst.args[i].valtype == ValueType::Processed) {
|
||||
if (inst.args[i].processed) {
|
||||
inst.args[i] = execute(*inst.args[i].processed);
|
||||
evaluated = true;
|
||||
}
|
||||
} else if (inst.args[i].valtype == ValueType::Variable) {
|
||||
inst.args[i] = data::getValue(inst.args[i].varName.key);
|
||||
evaluated = true;
|
||||
}
|
||||
|
||||
if (!evaluated) {
|
||||
i++;
|
||||
}
|
||||
for(auto& arg : inst.args) {
|
||||
arg = evaluate(arg);
|
||||
}
|
||||
|
||||
// Then, execute the instruction with the evaluated arguments
|
||||
switch (inst.instruction) {
|
||||
case InstructionType::Print:
|
||||
return modules::print(inst.args);
|
||||
break;
|
||||
case InstructionType::Println:
|
||||
return modules::println(inst.args);
|
||||
break;
|
||||
case InstructionType::Math:
|
||||
return modules::math(inst.args);
|
||||
break;
|
||||
case InstructionType::Compare:
|
||||
return modules::compare(inst.args);
|
||||
break;
|
||||
case InstructionType::Input:
|
||||
return modules::input(inst.args);
|
||||
break;
|
||||
case InstructionType::Exit:
|
||||
return modules::exit(inst.args);
|
||||
break;
|
||||
case InstructionType::Concat:
|
||||
return modules::concat(inst.args);
|
||||
break;
|
||||
case InstructionType::Variable: {
|
||||
if (!inst.args.empty()) {
|
||||
const std::string& name = inst.args[0].real;
|
||||
if (data::functions.count(name)) {
|
||||
const auto& func = data::functions.at(name);
|
||||
|
||||
if (func.arg_names.size() != inst.args.size() - 1) {
|
||||
error("Function " + name + " expects " + std::to_string(func.arg_names.size()) + " arguments, but got " + std::to_string(inst.args.size() - 1));
|
||||
return Value();
|
||||
}
|
||||
|
||||
data::pushScope();
|
||||
|
||||
for (size_t i = 0; i < func.arg_names.size(); ++i) {
|
||||
Value arg_val = inst.args[i+1];
|
||||
data::scopes.back()[func.arg_names[i]] = arg_val;
|
||||
}
|
||||
|
||||
Value return_val;
|
||||
for (const auto& body_inst : func.body) {
|
||||
return_val = execute(body_inst);
|
||||
if (return_val.is_return) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
data::popScope();
|
||||
|
||||
return_val.is_return = false;
|
||||
return return_val;
|
||||
}
|
||||
}
|
||||
if (inst.args.size() > 2 && inst.args[1].valtype == ValueType::Real && inst.args[1].real == "=") {
|
||||
return varmod(inst.args);
|
||||
} else {
|
||||
error("Unknown instruction or variable");
|
||||
return Value("");
|
||||
}
|
||||
break;
|
||||
}
|
||||
case InstructionType::Return: {
|
||||
if (inst.args.empty()) {
|
||||
Value val;
|
||||
@@ -123,7 +135,6 @@ Value execute(Instruction inst) {
|
||||
return return_val;
|
||||
}
|
||||
default:
|
||||
// Note: 'If' and 'Let' are already handled.
|
||||
error("Unknown instruction");
|
||||
return Value("");
|
||||
}
|
||||
|
||||
15
src/utils/evaluate/evaluate.cpp
Normal file
15
src/utils/evaluate/evaluate.cpp
Normal file
@@ -0,0 +1,15 @@
|
||||
#include "evaluate.h"
|
||||
#include "../../defs/defs.h"
|
||||
#include "../../executor/executor.h"
|
||||
#include "../../data/data.h"
|
||||
|
||||
Value evaluate(Value val) {
|
||||
if (val.valtype == ValueType::Processed) {
|
||||
if (val.processed) {
|
||||
return execute(*val.processed);
|
||||
}
|
||||
} else if (val.valtype == ValueType::Variable) {
|
||||
return data::getValue(val.varName.key);
|
||||
}
|
||||
return val;
|
||||
}
|
||||
5
src/utils/evaluate/evaluate.h
Normal file
5
src/utils/evaluate/evaluate.h
Normal file
@@ -0,0 +1,5 @@
|
||||
#pragma once
|
||||
|
||||
#include "../../defs/defs.h"
|
||||
|
||||
Value evaluate(Value val);
|
||||
12
src/utils/trim/trim.cpp
Normal file
12
src/utils/trim/trim.cpp
Normal file
@@ -0,0 +1,12 @@
|
||||
#include "trim.h"
|
||||
|
||||
// Helper to trim whitespace from the start and end of a string
|
||||
std::string trim(const std::string& str) {
|
||||
size_t first = str.find_first_not_of(" \t\n\r");
|
||||
if (std::string::npos == first) {
|
||||
return str;
|
||||
}
|
||||
size_t last = str.find_last_not_of(" \t\n\r");
|
||||
return str.substr(first, (last - first + 1));
|
||||
}
|
||||
|
||||
5
src/utils/trim/trim.h
Normal file
5
src/utils/trim/trim.h
Normal file
@@ -0,0 +1,5 @@
|
||||
#pragma once
|
||||
|
||||
#include <string>
|
||||
|
||||
std::string trim(const std::string& str);
|
||||
Reference in New Issue
Block a user