From cf85205ff031c531b379ed3b51b0f8841e109fef Mon Sep 17 00:00:00 2001 From: Maxwell Jeffress Date: Thu, 2 Oct 2025 14:44:48 +1000 Subject: [PATCH] Simple list implementation --- src/datatypes/lists.cpp | 53 +++++++++++++++++++++++++++++++++ src/datatypes/lists.h | 8 +++++ src/defs/defs.cpp | 32 ++++++++++++++++---- src/defs/defs.h | 7 +++-- src/executor/executor.cpp | 4 +++ src/modules/concat/concat.cpp | 16 ++++++++++ src/modules/concat/concat.h | 8 +++++ src/modules/print/print.cpp | 17 ++++++++++- src/modules/println/println.cpp | 10 ++----- src/modules/split/split.cpp | 8 +++++ src/modules/split/split.h | 8 +++++ src/parser/parser.cpp | 10 ------- 12 files changed, 155 insertions(+), 26 deletions(-) create mode 100644 src/datatypes/lists.cpp create mode 100644 src/datatypes/lists.h create mode 100644 src/modules/concat/concat.cpp create mode 100644 src/modules/concat/concat.h create mode 100644 src/modules/split/split.cpp create mode 100644 src/modules/split/split.h diff --git a/src/datatypes/lists.cpp b/src/datatypes/lists.cpp new file mode 100644 index 0000000..a8bbe26 --- /dev/null +++ b/src/datatypes/lists.cpp @@ -0,0 +1,53 @@ +#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 parse_list_content(const std::string& content) { + std::vector 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; +} diff --git a/src/datatypes/lists.h b/src/datatypes/lists.h new file mode 100644 index 0000000..d563eda --- /dev/null +++ b/src/datatypes/lists.h @@ -0,0 +1,8 @@ +#pragma once + +#include +#include +#include "../defs/defs.h" + +std::vector parse_list_content(const std::string& content); +std::string trim(const std::string& str); \ No newline at end of file diff --git a/src/defs/defs.cpp b/src/defs/defs.cpp index ba7f042..d431b0c 100644 --- a/src/defs/defs.cpp +++ b/src/defs/defs.cpp @@ -4,6 +4,7 @@ #include #include #include +#include "../datatypes/lists.h" InstructionType strToInstructionType(std::string in) { if (in == "println") return InstructionType::Println; @@ -16,6 +17,7 @@ InstructionType strToInstructionType(std::string in) { else if (in == "compare") return InstructionType::Compare; else if (in == "input") return InstructionType::Input; else if (in == "return") return InstructionType::Return; + else if (in == "concat") return InstructionType::Concat; else return InstructionType::Variable; } @@ -69,7 +71,9 @@ Value::Value() : valtype(ValueType::Real) {} Value::Value(InstructionGroup instgroup) : valtype(ValueType::InstructionGroup), instructionGroup(instgroup) {}; -Value::Value(const Value& other) : valtype(other.valtype), real(other.real), varName(other.varName), instructionGroup(other.instructionGroup) { +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) { if (other.processed) { processed = std::make_unique(*other.processed); } @@ -86,6 +90,7 @@ Value& Value::operator=(const Value& other) { real = other.real; varName = other.varName; instructionGroup = other.instructionGroup; + list = other.list; if (other.processed) { processed = std::make_unique(*other.processed); } else { @@ -113,6 +118,14 @@ std::string Value::toString() const { case ValueType::InstructionGroup: out += "InstructionGroup, contains " + std::to_string(instructionGroup.size()) + " instructions)"; break; + case ValueType::List: { + out += "List, items: ["; + for (const auto& item : list) { + out += item.toString() + ", "; + } + out += "])"; + break; + } default: out += "FIXME)"; break; @@ -161,6 +174,8 @@ std::vector split(std::string line) { std::string buf; bool instring = false; int brackets = 0; + char bracket_type = 0; + for (char chr : line) { if (chr == ' ' && !instring && brackets == 0 && !buf.empty()) { if (buf[0] == '$') { @@ -170,8 +185,8 @@ std::vector split(std::string line) { } buf = ""; } else if (chr == '(' || chr == '[') { - brackets += 1; - if (brackets == 1) { + if (brackets == 0) { + bracket_type = chr; if (!buf.empty()) { splitvals.push_back(Value(buf)); buf = ""; @@ -179,13 +194,20 @@ std::vector split(std::string line) { } else { buf += chr; } + brackets++; } else if (chr == ')' || chr == ']') { - brackets -= 1; + brackets--; if (brackets == 0) { if (!buf.empty()) { - splitvals.push_back(Value(Instruction(split(buf)))); + if (bracket_type == '(') { + splitvals.push_back(Value(Instruction(split(buf)))); + } else { + splitvals.push_back(Value(parse_list_content(buf))); + } buf = ""; } + } else { + buf += chr; } } else if (chr == '"') { instring = !instring; diff --git a/src/defs/defs.h b/src/defs/defs.h index 099ba71..693d8ea 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 + None, Print, Println, Math, Let, Variable, Exit, If, While, Input, Compare, Function, Return, Concat }; enum class ValueType { - Real, Processed, Variable, InstructionGroup + Real, Processed, Variable, InstructionGroup, List, Map }; struct Instruction; @@ -33,12 +33,14 @@ struct Value { std::unique_ptr processed; std::string real = ""; InstructionGroup instructionGroup; + std::vector list; bool is_return = false; std::string toString() const; Varname varName = Varname(); Value(std::string stringval); Value(Instruction instval); Value(InstructionGroup instgroup); + Value(std::vector listval); Value(Varname var); Value(); Value(const Value& other); @@ -58,4 +60,5 @@ 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 5f60e87..325b147 100644 --- a/src/executor/executor.cpp +++ b/src/executor/executor.cpp @@ -13,6 +13,7 @@ #include "../modules/compare/compare.h" #include "../modules/input/input.h" #include "../modules/function/function.h" +#include "../modules/concat/concat.h" Value execute(Instruction inst) { // Special cases that need to manage their own argument evaluation @@ -68,6 +69,9 @@ Value execute(Instruction inst) { 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; diff --git a/src/modules/concat/concat.cpp b/src/modules/concat/concat.cpp new file mode 100644 index 0000000..a7434b7 --- /dev/null +++ b/src/modules/concat/concat.cpp @@ -0,0 +1,16 @@ +#include "concat.h" +#include "../../defs/defs.h" +#include "../../error/error.h" +#include + +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"); + } + } + return buf; +} diff --git a/src/modules/concat/concat.h b/src/modules/concat/concat.h new file mode 100644 index 0000000..15ba3bc --- /dev/null +++ b/src/modules/concat/concat.h @@ -0,0 +1,8 @@ +#pragma once + +#include "../../defs/defs.h" +#include + +namespace modules { + Value concat(std::vector args); +} diff --git a/src/modules/print/print.cpp b/src/modules/print/print.cpp index 8aeed10..5854db3 100644 --- a/src/modules/print/print.cpp +++ b/src/modules/print/print.cpp @@ -8,7 +8,22 @@ Value modules::print(std::vector values) { for (Value value : values) { if (value.valtype == ValueType::Real) { - std::cout << value.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; + } + print({val}); + } + std::cout << "]"; } else { error("FIXME unprocessed processed (in print module)"); } diff --git a/src/modules/println/println.cpp b/src/modules/println/println.cpp index 2c454f1..13c2b8a 100644 --- a/src/modules/println/println.cpp +++ b/src/modules/println/println.cpp @@ -1,18 +1,12 @@ #include "println.h" #include "../../defs/defs.h" -#include "../../error/error.h" +#include "../print/print.h" #include #include #include Value modules::println(std::vector values) { - for (Value value : values) { - if (value.valtype == ValueType::Real) { - std::cout << value.real << " "; - } else { - error("FIXME unprocessed processed (in println module)"); - } - } + print(values); std::cout << "\n"; return Value(""); } diff --git a/src/modules/split/split.cpp b/src/modules/split/split.cpp new file mode 100644 index 0000000..1edac91 --- /dev/null +++ b/src/modules/split/split.cpp @@ -0,0 +1,8 @@ +#include "split.h" +#include "../../defs/defs.h" +#include +#include + +Value modules::split(std::vector args) { + return Value("Work in progress!"); +} diff --git a/src/modules/split/split.h b/src/modules/split/split.h new file mode 100644 index 0000000..8b73e52 --- /dev/null +++ b/src/modules/split/split.h @@ -0,0 +1,8 @@ +#pragma once + +#include "../../defs/defs.h" +#include + +namespace modules { + Value split(std::vector args); +} diff --git a/src/parser/parser.cpp b/src/parser/parser.cpp index 764b7ab..601f070 100644 --- a/src/parser/parser.cpp +++ b/src/parser/parser.cpp @@ -3,16 +3,6 @@ #include #include -// Helper to trim whitespace -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 parse(std::string program) { std::vector instructions; std::vector lines;