Skip to content

Commit 704c019

Browse files
cursoragentomiq
andcommitted
Runtime hints for ON GOTO/GOSUB, RETURN, IF blocks, FUNCTION
- ON: GOTO/GOSUB keyword; line list digits only; GOSUB stack in ON path - GOSUB/RETURN: stack overflow and RETURN without GOSUB - skip_if_block_to_target: END IF expected; IF nesting; ELSE/END IF pairing - skip_function_block / END FUNCTION: matching FUNCTION - invoke_udf: FUNCTION nesting too deep - Fix CURSOR fallback to runtime_error_hint; complete FOR Expected TO hint - CHANGELOG: document control-flow and UDF hints Co-authored-by: Chris Garrett <chris@chrisg.com>
1 parent 59934e4 commit 704c019

2 files changed

Lines changed: 19 additions & 12 deletions

File tree

CHANGELOG.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22

33
### Unreleased
44

5-
- **Runtime hints**: **`goto` / `gosub` / `on` / `if … then`**, **`DIM` / `FOR` / `NEXT`**, **array subscripts**, **`LET`/`=`**, **`INPUT`**, **`READ`/`DATA`**, **`RESTORE`**, **`GET`**, **`LOAD`/`MEMSET`/`MEMCPY`**, **`OPEN`/`CLOSE`** and **`PRINT#`/`INPUT#`/`GET#`**, **`TEXTAT`/`LOCATE`**, **`SORT`**, **`SPLIT`/`JOIN`**, **`CURSOR`**, **`COLOR`/`BACKGROUND`**, **`SCREEN`/`PSET`/`PRESET`/`LINE`/`SCREENCODES`**, **`LOADSPRITE`/`DRAWSPRITE`/`SPRITEVISIBLE`/`UNLOADSPRITE`**, **`WHILE`/`WEND`**, **`DO`/`LOOP`/`EXIT`** — short **`Hint:`** lines for common mistakes. **Native** `runtime_error_hint` prints **`Hint:`** on stderr (parity with WASM). **`tutorial-embed.js`**: **Ctrl+Enter** / **Cmd+Enter** runs; **`scrollToError`** (default **on**). **`web/tutorial.html`** playground mentions keyboard run.
5+
- **Runtime hints**: **`goto` / `gosub` / `return`**, **`on` `goto`/`gosub`**, **`if`/`else`/`end if`**, **`function`/`end function`**, **`DIM` / `FOR` / `NEXT`**, **array subscripts**, **`LET`/`=`**, **`INPUT`**, **`READ`/`DATA`**, **`RESTORE`**, **`GET`**, **`LOAD`/`MEMSET`/`MEMCPY`**, **`OPEN`/`CLOSE`** and **`PRINT#`/`INPUT#`/`GET#`**, **`TEXTAT`/`LOCATE`**, **`SORT`**, **`SPLIT`/`JOIN`**, **`CURSOR`**, **`COLOR`/`BACKGROUND`**, **`SCREEN`/`PSET`/`PRESET`/`LINE`/`SCREENCODES`**, **`LOADSPRITE`/`DRAWSPRITE`/`SPRITEVISIBLE`/`UNLOADSPRITE`**, **`WHILE`/`WEND`**, **`DO`/`LOOP`/`EXIT`** — short **`Hint:`** lines for common mistakes. **Native** `runtime_error_hint` prints **`Hint:`** on stderr (parity with WASM). **`tutorial-embed.js`**: **Ctrl+Enter** / **Cmd+Enter** runs; **`scrollToError`** (default **on**). **`web/tutorial.html`** playground mentions keyboard run.
66

77
- **Sprites**: **`SPRITECOLLIDE(a, b)`** — returns **1** if two loaded, visible sprites’ axis-aligned bounding boxes overlap (basic-gfx + canvas WASM; **0** otherwise). Terminal **`./basic`** errors if used (requires **basic-gfx** or canvas WASM). **Runtime errors**: optional **`Hint:`** line for **unknown function** (shows name) and **`ensure_num` / `ensure_str`** type mismatches. **`tutorial-embed.js`**: optional **`runOnEdit`** / **`runOnEditMs`** for debounced auto-run after editing; **`web/tutorial.html`** enables this on the final playground embed only (**550** ms).
88

basic.c

Lines changed: 18 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -6583,7 +6583,8 @@ static void statement_on(char **p)
65836583
is_gosub = 1;
65846584
*p += 5;
65856585
} else {
6586-
runtime_error("ON must be followed by GOTO or GOSUB");
6586+
runtime_error_hint("ON must be followed by GOTO or GOSUB",
6587+
"Use ON X GOTO 100,200,300 or ON X GOSUB 100,200,300");
65876588
return;
65886589
}
65896590

@@ -6595,7 +6596,8 @@ static void statement_on(char **p)
65956596

65966597
skip_spaces(p);
65976598
if (!isdigit((unsigned char)**p)) {
6598-
runtime_error("Expected line number in ON");
6599+
runtime_error_hint("Expected line number in ON",
6600+
"After GOTO/GOSUB list comma-separated line numbers only.");
65996601
return;
66006602
}
66016603
target = atoi(*p);
@@ -6615,7 +6617,8 @@ static void statement_on(char **p)
66156617
}
66166618
if (is_gosub) {
66176619
if (gosub_top >= MAX_GOSUB) {
6618-
runtime_error("GOSUB stack overflow");
6620+
runtime_error_hint("GOSUB stack overflow",
6621+
"Too many nested GOSUBs; RETURN before deeper GOSUB.");
66196622
return;
66206623
}
66216624
gosub_stack[gosub_top].line_index = current_line;
@@ -7568,7 +7571,8 @@ static void statement_gosub(char **p)
75687571
int len;
75697572

75707573
if (gosub_top >= MAX_GOSUB) {
7571-
runtime_error("GOSUB stack overflow");
7574+
runtime_error_hint("GOSUB stack overflow",
7575+
"Too many nested GOSUBs without RETURN; reduce nesting.");
75727576
return;
75737577
}
75747578
skip_spaces(p);
@@ -7790,7 +7794,7 @@ static void statement_if(char **p)
77907794
/* Block mode: THEN at EOL or followed only by ':' then EOL */
77917795
if (!*after_then || (*after_then == ':' && !after_then[1])) {
77927796
if (if_depth >= MAX_IF_DEPTH) {
7793-
runtime_error("IF nesting too deep");
7797+
runtime_error_hint("IF nesting too deep", "Too many nested block IFs; simplify or split lines.");
77947798
return;
77957799
}
77967800
if_stack[if_depth].took_then = cond_true ? 1 : 0;
@@ -7841,7 +7845,7 @@ static void statement_else(char **p)
78417845
static void statement_end_if(char **p)
78427846
{
78437847
if (if_depth <= 0) {
7844-
runtime_error("END IF without matching IF");
7848+
runtime_error_hint("END IF without matching IF", "Each END IF closes a block IF above it.");
78457849
return;
78467850
}
78477851
skip_spaces(p);
@@ -8091,24 +8095,26 @@ static void statement_for(char **p)
80918095
return;
80928096
}
80938097
if (is_array) {
8094-
runtime_error("FOR variable must be scalar");
8098+
runtime_error_hint("FOR variable must be scalar",
8099+
"Use a simple variable (e.g. I), not an array element.");
80958100
return;
80968101
}
80978102
if (is_string) {
8098-
runtime_error("FOR variable must be numeric");
8103+
runtime_error_hint("FOR variable must be numeric",
8104+
"FOR only works with numeric variables (not names ending in $).");
80998105
return;
81008106
}
81018107
skip_spaces(p);
81028108
if (**p != '=') {
8103-
runtime_error("Expected '=' in FOR");
8109+
runtime_error_hint("Expected '=' in FOR", "Use FOR I = 1 TO 10 ( = after the variable).");
81048110
return;
81058111
}
81068112
(*p)++;
81078113
startv = eval_expr(p);
81088114
ensure_num(&startv);
81098115
skip_spaces(p);
81108116
if (!starts_with_kw(*p, "TO")) {
8111-
runtime_error("Expected TO in FOR");
8117+
runtime_error_hint("Expected TO in FOR", "Use FOR var = start TO end [STEP n].");
81128118
return;
81138119
}
81148120
*p += 2;
@@ -8223,7 +8229,8 @@ static void statement_next(char **p)
82238229
}
82248230
}
82258231
if (i < 0) {
8226-
runtime_error("NEXT without FOR");
8232+
runtime_error_hint("NEXT without FOR",
8233+
"Every NEXT needs a matching FOR above; NEXT I pairs with FOR I = …");
82278234
return;
82288235
}
82298236
for_top = i + 1;

0 commit comments

Comments
 (0)