aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAlexis Lockwood2021-06-29 21:48:55 -0400
committerAlexis Lockwood2021-06-29 21:48:55 -0400
commite90bde096174bb401dfb68befd1a84ac8cb15b4e (patch)
tree57e23b3efca785a7549566401732ea842880564c
parentfda7d5db7b2589b0c789579b40d5bcf685f8702e (diff)
Loops shouldn't create a scope
(We don't have room to track the iterator variable efficiently otherwise)
-rw-r--r--README.md8
-rw-r--r--src/ls_internal.c12
-rw-r--r--src/ls_types.h5
3 files changed, 18 insertions, 7 deletions
diff --git a/README.md b/README.md
index f8732bd..e186c61 100644
--- a/README.md
+++ b/README.md
@@ -244,7 +244,7 @@ FILE device /path/to/file
| `END` | Stop execution and return to caller |
| `ERASE ident [, ident...]` | Deallocate any space held by `ident` and delete it. |
| `FN name(args...)` | Execute the function `name`, returning its value |
-| `FOR ident = a TO b [STEP c]` | Repeat until `NEXT` with `ident` running from `a` to `b` in steps of `c` |
+| `FOR ident = a TO b [STEP c]` | Repeat until `NEXT` with `ident` running from `a` to `b` in steps of `c`. |
| `GOSUB f[(args...)] [AS s]` | Call label `f` as a function, optionally passing and returning data |
| `GOTO label` | Go directly to `label` |
| `GOTO +n` or `GOTO -n` | Go directly forward or backward to numbered label `n` |
@@ -269,7 +269,7 @@ FILE device /path/to/file
| `UNPACK n... FROM s$ [USING fmt]` | Unpack values from binary format |
| `VAL(s$)` | Returns the numerical value of a string |
| `WEND` | Go back to the last `WHILE`. Must occur by itself, not inside an IF or similar. |
-| `WHILE cond` | Loop as long as `cond` is nonzero. Creates a scope. |
+| `WHILE cond` | Loop as long as `cond` is nonzero. |
(TODO: define file I/O variables. This will probably look nothing like
traditional BASICs)
@@ -283,6 +283,10 @@ erasing any unused variables.
If the iterator does not land directly on `b` because of the step size,
iteration stops when it passes `b`.
+
+FOR loops, like WHILE loops, do not create a full scope. The loop iterator
+can shadow other variables, but all other variables created inside the loop
+exist in its enclosing context.
`
### `GOSUB f[(args...)] [AS s]`
diff --git a/src/ls_internal.c b/src/ls_internal.c
index f407311..78bab75 100644
--- a/src/ls_internal.c
+++ b/src/ls_internal.c
@@ -232,14 +232,22 @@ ls_value_t * ls_find_var(ls_t * self, char const * name)
ls_value_t * ls_new_var(ls_t * self, char const * name)
{
+ ls_value_t * scope = self->_callstack;
+
+ while (scope && scope->ty != LS_TY_SCTX_CALL)
+ scope = scope->prev;
+
+ if (!scope)
+ ls_throw_err(self, LS_INTERNAL_ERROR);
+
ls_value_t * var = ls_alloc(self);
var->ty = LS_TY_INT_VAR;
memset(var->body.int_var.ident, 0, LS_IDENT_LEN);
strncpy(var->body.int_var.ident, name, LS_IDENT_LEN);
var->body.int_var.value = 0;
- var->next = self->_callstack->next;
- self->_callstack->next = var;
+ var->next = scope->next;
+ scope->next = var;
return var;
}
diff --git a/src/ls_types.h b/src/ls_types.h
index 9e8d899..26a6103 100644
--- a/src/ls_types.h
+++ b/src/ls_types.h
@@ -162,9 +162,8 @@ typedef struct {
ls_addr_t readptr;
} ls_ty_sctx_call_t;
-/// FOR loop stackframe. NEXT pointer should point into a linked list of
-/// variables, of which the first must be the loop iterator. Usually, this will
-/// be the only variable.
+/// FOR loop stackframe. NEXT pointer should point at the loop iterator
+/// variable.
typedef struct {
/// Terminating value
ls_int_t term;