From 6d782d65b74e49180ee1cc9da997116e54d8d781 Mon Sep 17 00:00:00 2001 From: Maxwell Jeffress Date: Mon, 1 Dec 2025 12:28:15 +1100 Subject: [PATCH] Add string operations --- README.md | 10 +++++----- src/interpreter.c | 48 +++++++++++++++++++++++++++++++++++++++++++++++ src/interpreter.h | 2 +- tests/string.grnd | 11 +++++++++++ 4 files changed, 65 insertions(+), 6 deletions(-) create mode 100644 tests/string.grnd diff --git a/README.md b/README.md index 6b40625..c4526b6 100644 --- a/README.md +++ b/README.md @@ -25,13 +25,13 @@ Progress marker: - [x] Labels - [x] Console I/O - [x] Control flow - - [ ] Data + - [x] Data - [x] Variable creation - [x] Variable access - - [ ] Lists - - [ ] Creation - - [ ] Access - - [ ] String operations + - [x] Lists + - [x] Creation + - [x] Access + - [x] String operations - [x] Maths - [x] Comparisions - [ ] Type conversions diff --git a/src/interpreter.c b/src/interpreter.c index b53e446..1bba766 100644 --- a/src/interpreter.c +++ b/src/interpreter.c @@ -696,6 +696,54 @@ void interpretGroundInstruction(GroundInstruction inst, GroundScope* scope) { } break; } + + /* + * STRING OPERATIONS + * Allows easier manipulation of strings. + * Instructions: + * getstrcharat, getstrsize + */ + case GETSTRCHARAT: { + if (in->args.length < 3) { + runtimeError(TOO_FEW_ARGS, "Expecting 3 args", in, currentInstruction); + } + if (in->args.length > 3) { + runtimeError(TOO_MANY_ARGS, "Expecting 3 args", in, currentInstruction); + } + if (in->args.args[0].type != VALUE && in->args.args[0].value.value.type != STRING) { + runtimeError(ARG_TYPE_MISMATCH, "Expecting a String for arg 1", in, currentInstruction); + } + if (in->args.args[1].type != VALUE && in->args.args[1].value.value.type != INT) { + runtimeError(ARG_TYPE_MISMATCH, "Expecting an Int for arg 2", in, currentInstruction); + } + if (in->args.args[2].type != DIRREF) { + runtimeError(ARG_TYPE_MISMATCH, "Expecting a DirectRef for arg 3", in, currentInstruction); + } + char* str = in->args.args[0].value.value.data.stringVal; + int64_t idx = in->args.args[1].value.value.data.intVal; + if (idx < strlen(str)) { + addVariable(scope->variables, in->args.args[2].value.refName, createCharGroundValue(str[idx])); + } else { + runtimeError(STRING_ERROR, "Out of bounds index", in, currentInstruction); + } + break; + } + case GETSTRSIZE: { + if (in->args.length < 2) { + runtimeError(TOO_FEW_ARGS, "Expecting 2 args", in, currentInstruction); + } + if (in->args.length > 2) { + runtimeError(TOO_MANY_ARGS, "Expecting 2 args", in, currentInstruction); + } + if (in->args.args[0].type != VALUE && in->args.args[0].value.value.type != STRING) { + runtimeError(ARG_TYPE_MISMATCH, "Expecting a String for arg 1", in, currentInstruction); + } + if (in->args.args[1].type != DIRREF) { + runtimeError(ARG_TYPE_MISMATCH, "Expecting a DirectRef for arg 2", in, currentInstruction); + } + addVariable(scope->variables, in->args.args[1].value.refName, createIntGroundValue(strlen(in->args.args[0].value.value.data.stringVal))); + break; + } /* * COMPARISONS diff --git a/src/interpreter.h b/src/interpreter.h index c0bb0ad..3c35069 100644 --- a/src/interpreter.h +++ b/src/interpreter.h @@ -7,7 +7,7 @@ #include "include/uthash.h" typedef enum GroundRuntimeError { - ARG_TYPE_MISMATCH, TOO_FEW_ARGS, TOO_MANY_ARGS, UNKNOWN_LABEL, UNKNOWN_VARIABLE, LIST_ERROR, FIXME + ARG_TYPE_MISMATCH, TOO_FEW_ARGS, TOO_MANY_ARGS, UNKNOWN_LABEL, UNKNOWN_VARIABLE, LIST_ERROR, STRING_ERROR, FIXME } GroundRuntimeError; typedef struct GroundLabel { diff --git a/tests/string.grnd b/tests/string.grnd new file mode 100644 index 0000000..8e0b4e2 --- /dev/null +++ b/tests/string.grnd @@ -0,0 +1,11 @@ +input &str +getstrsize $str &size +set &idx 0 +@loop +getstrcharat $str $idx &char +println $char +add 1 $idx &idx +equal $idx $size &cond +if $cond %loopend +jump %loop +@loopend