summaryrefslogtreecommitdiff
path: root/src/core/interpret.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/core/interpret.c')
-rw-r--r--src/core/interpret.c122
1 files changed, 110 insertions, 12 deletions
diff --git a/src/core/interpret.c b/src/core/interpret.c
index 0911ef7..f61aa5c 100644
--- a/src/core/interpret.c
+++ b/src/core/interpret.c
@@ -74,6 +74,8 @@ int _program(Interpret *p_interpret);
int _statement(Interpret *p_interpret);
int _sum(Interpret *p_interpret);
int _term(Interpret *p_interpret);
+int _term_array_access(Interpret *p_interpret,
+ Token *p_token_array, Array *p_array);
int _var_assign(Interpret *p_interpret);
int _var_decl(Interpret *p_interpret);
int _var_list(Interpret *p_interpret);
@@ -99,6 +101,8 @@ interpret_new(List *p_list_token, Hash *p_hash_syms) {
p_interpret->tt_prev = TT_NONE;
p_interpret->p_token_prev = NULL;
p_interpret->p_token_temp = NULL;
+ p_interpret->p_token_array_lhs = NULL;
+ p_interpret->i_array_lhs_index = 0;
p_interpret->ct = CONTROL_NONE;
return (p_interpret);
@@ -860,6 +864,13 @@ _sum(Interpret *p_interpret) {
switch (p_interpret->tt) {
case TT_DDOT:
+ /* ':' is a shift-operator prefix only when followed by
+ * '<' or '>'; otherwise it is a slice separator so stop.
+ */
+ if (_NEXT_TT != TT_LT && _NEXT_TT != TT_GT) {
+ b_flag = false;
+ break;
+ }
p_token_tmp = p_interpret->p_token;
_NEXT
case TT_ADD:
@@ -941,6 +952,9 @@ int
_product2(Interpret *p_interpret) {
_CHECK TRACK
+ /* Clear any stale array LHS left from a preceding expression */
+ p_interpret->p_token_array_lhs = NULL;
+
if (_term(p_interpret)) {
_Bool b_flag = true;
@@ -949,11 +963,17 @@ _product2(Interpret *p_interpret) {
&& IS_NOT_OPERATOR(_NEXT_TT)) {
Token *p_token = p_interpret->p_token;
Token *p_token_temp = p_interpret->p_token_prev;
+ /* Save array LHS set by _term; RHS evaluation clears it */
+ Token *p_lhs = p_interpret->p_token_array_lhs;
+ int i_lhs_idx = p_interpret->i_array_lhs_index;
_NEXT
if (!_expression_(p_interpret))
_INTERPRET_ERROR("Expected expression", p_token);
+ /* Restore array LHS so function_process can assign it */
+ p_interpret->p_token_array_lhs = p_lhs;
+ p_interpret->i_array_lhs_index = i_lhs_idx;
p_interpret->p_token_temp = p_token_temp;
function_process(p_interpret, p_token, NULL,
p_interpret->p_stack, 2);
@@ -971,6 +991,86 @@ _product2(Interpret *p_interpret) {
return (0);
}
+/* Evaluate an array index or slice expression and push the result.
+ *
+ * On entry the current token is the array identifier. The function
+ * advances past `arr[...]` and pushes the result onto the stack.
+ *
+ * Supported forms (half-open range, end is exclusive):
+ * arr[i] single element at index i
+ * arr[i:j] sub-array of elements [i, j)
+ * arr[i:] elements from i to end
+ * arr[:j] elements from start up to j
+ * arr[:] full copy
+ *
+ * For single-element access, sets p_token_array_lhs / i_array_lhs_index
+ * so that _product2 can dispatch arr[i] = val to the right handler.
+ */
+int
+_term_array_access(Interpret *p_interpret,
+ Token *p_token_array, Array *p_array) {
+ _NEXT /* advance past identifier, now at '[' */
+ _NEXT /* advance past '[', now at index start */
+
+ /* Evaluate the low bound. _expression_ stops before ':' because
+ * _sum now only treats ':' as a shift prefix when the next token
+ * is '<' or '>'. Returns 0 and pushes nothing for arr[:j]. */
+ int i_low = 0;
+ if (_expression_(p_interpret))
+ i_low = convert_to_integer_get(
+ stack_pop(p_interpret->p_stack));
+
+ /* Skip the auto-semicolon the scanner inserts before ']' */
+ if (p_interpret->tt == TT_SEMICOLON)
+ _NEXT
+
+ if (p_interpret->tt == TT_DDOT) { /* slice: arr[i:j] etc. */
+ _NEXT /* advance past ':' */
+
+ /* Default: slice extends to the end of the array */
+ int i_high = array_get_used(p_array);
+
+ /* Evaluate explicit high bound if not immediately at ']' */
+ if (p_interpret->tt != TT_PARANT_AR
+ && p_interpret->tt != TT_SEMICOLON) {
+ if (!_expression_(p_interpret))
+ _INTERPRET_ERROR("Expected high-bound expression",
+ p_interpret->p_token);
+ i_high = convert_to_integer_get(
+ stack_pop(p_interpret->p_stack));
+ }
+
+ /* Skip auto-semicolon before ']' */
+ if (p_interpret->tt == TT_SEMICOLON)
+ _NEXT
+
+ /* Build sub-array [i_low, i_high) — shallow copy of pointers.
+ * Elements are shared with the original array; do not ref-up
+ * because the GC tracks all tokens at ref_count 0. */
+ int i_len = i_high - i_low;
+ Token *p_sub = token_new_array(i_len > 0 ? i_len : 1);
+ for (int i = i_low; i < i_high; ++i) {
+ Token *p_elem = array_get(p_array, i);
+ if (p_elem != NULL)
+ array_unshift(p_sub->p_array, p_elem);
+ }
+ stack_push(p_interpret->p_stack, p_sub);
+
+ } else { /* single index: arr[i] */
+ /* Record LHS info so _product2 can handle arr[i] = val */
+ p_interpret->p_token_array_lhs = p_token_array;
+ p_interpret->i_array_lhs_index = i_low;
+ stack_push(p_interpret->p_stack, array_get(p_array, i_low));
+ }
+
+ /* Consume ']' */
+ if (p_interpret->tt != TT_PARANT_AR)
+ _INTERPRET_ERROR("Expected ']'", p_interpret->p_token);
+ _NEXT /* advance past ']' */
+
+ return (1);
+}
+
int
_term(Interpret *p_interpret) {
_CHECK TRACK
@@ -993,24 +1093,22 @@ _term(Interpret *p_interpret) {
{
if (_NEXT_TT != TT_ASSIGN) {
if (_NEXT_TT == TT_PARANT_AL) {
- Token *p_token_var = p_interpret->p_token;
- char *c_name = token_get_val(p_token_var);
- Symbol *p_symbol = scope_get(p_interpret->p_scope, c_name);
+ /* Delegate to the array-access / slice helper */
+ char *c_name = token_get_val(p_interpret->p_token);
+ Symbol *p_symbol = scope_get(
+ p_interpret->p_scope, c_name);
if (p_symbol == NULL)
- _INTERPRET_ERROR("No such symbol", p_token_var);
+ _INTERPRET_ERROR("No such symbol",
+ p_interpret->p_token);
Token *p_token_array = symbol_get_val(p_symbol);
Array *p_array = TOKEN_GET_ARRAY(p_token_array);
if (p_array == NULL)
- _INTERPRET_ERROR("Expected an array", p_interpret->p_token);
-
- _NEXT2
- Token *p_token_val = array_get(p_array,
- convert_to_integer_get(p_interpret->p_token));
- stack_push(p_interpret->p_stack, p_token_val);
- _NEXT
+ _INTERPRET_ERROR("Expected an array",
+ p_interpret->p_token);
- return (1);
+ return (_term_array_access(p_interpret,
+ p_token_array, p_array));
} else if (function_is_buildin(p_interpret->p_token)) {
Token *p_token = p_interpret->p_token;