Accept GRAPHIC CLR and a negative DATA item
Two parse handlers refusing something the documentation promises. Landing together because they are the same defect twice -- a verb's own argument shape falling through to a general path that cannot see it -- in one file, found by one program, and verified in one pass. **`GRAPHIC CLR`** is given as `GRAPHIC mode | CLR` in both docs/06-graphics.md and docs/11-verb-reference.md, and was refused: `CLR` is a verb of its own, so the generic arglist path scanned it as a command token and the expression parser answered "Expected expression or literal". `akbasic_parse_graphic()` takes it as this verb's keyword argument and emits mode 5 -- which `akbasic_cmd_graphic()` already treats as "drop the saved shapes and go back to text", so both spellings are one statement and the exec handler is untouched. The documentation was right all along; nothing in it changes. **`DATA -5`** was refused by `akbasic_parse_data()`, and only there: `READ` scans the source text directly (src/data.c) and always returned the -5 intact. So the value was right and *reaching* the statement raised -- which, since section 4 settled that `DATA` at run time is a no-op, is what a program does with every `DATA` line it walks past. A table of coordinates or velocities is full of negative numbers, which is how a game found it. The fix accepts a unary minus over a numeric literal and nothing else: `DATA -A#` is still a mistake worth naming, and `akbasic_leaf_is_literal()` keeps meaning what it says because other callers rely on it. tests/read_data.c covers both mechanisms -- reading a negative item and reaching the line after it -- with a mixed-sign table and a negative float, since the two were never the same code path. TODO.md section 9 items 7 and 8, struck. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -99,6 +99,27 @@ int main(void)
|
||||
expect_command("LABEL LOOPTOP", AKBASIC_LEAF_COMMAND, "LABEL");
|
||||
expect_command("DIM A#(5)", AKBASIC_LEAF_COMMAND, "DIM");
|
||||
expect_command("DATA 1, 2, 3", AKBASIC_LEAF_COMMAND, "DATA");
|
||||
/*
|
||||
* A negated literal is one. `DATA -5` used to be refused here and only here:
|
||||
* READ scans the source text directly and returned the -5 intact, so the
|
||||
* value was right and reaching the *statement* raised "Expected literal" --
|
||||
* which is a table of coordinates or velocities failing on the line after
|
||||
* it. TODO.md section 9 item 8.
|
||||
*/
|
||||
expect_command("DATA -5", AKBASIC_LEAF_COMMAND, "DATA");
|
||||
expect_command("DATA -1, 2, -3.5", AKBASIC_LEAF_COMMAND, "DATA");
|
||||
/* Only over a literal, though: a negated variable is still a mistake. */
|
||||
expect_parse_error("DATA -A#");
|
||||
|
||||
/*
|
||||
* `GRAPHIC CLR` is documented in two chapters and used to be refused: CLR is
|
||||
* a verb of its own, so the generic arglist path scanned it as a command
|
||||
* token rather than as this verb's keyword argument. TODO.md section 9 item
|
||||
* 7. It becomes mode 5, which the exec handler already treats as exactly
|
||||
* this, so both spellings are one statement.
|
||||
*/
|
||||
expect_command("GRAPHIC CLR", AKBASIC_LEAF_COMMAND, "GRAPHIC");
|
||||
expect_command("GRAPHIC 1, 1", AKBASIC_LEAF_COMMAND, "GRAPHIC");
|
||||
expect_command("READ A#, B#", AKBASIC_LEAF_COMMAND, "READ");
|
||||
expect_command("POKE 100, 1", AKBASIC_LEAF_COMMAND, "POKE");
|
||||
expect_command("INPUT \"NAME? \" A$", AKBASIC_LEAF_COMMAND, "INPUT");
|
||||
|
||||
@@ -184,6 +184,37 @@ static void test_float_items(void)
|
||||
harness_stop();
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief A `DATA` line holding a negative number can be read *and* walked past.
|
||||
*
|
||||
* Two different mechanisms, and only one of them was ever wrong. `READ` scans
|
||||
* the source text directly, so it always returned the -5 intact; the statement's
|
||||
* own argument parse refused a leading minus, so reaching the line raised
|
||||
* "Expected literal". Section 4 settled that `DATA` at run time is a no-op --
|
||||
* reaching it means walking past it -- which is what made this reachable at all.
|
||||
*
|
||||
* TODO.md section 9 item 8. A table of coordinates or velocities is full of
|
||||
* negative numbers, which is how a game found it.
|
||||
*/
|
||||
static void test_negative_items(void)
|
||||
{
|
||||
TEST_REQUIRE_OK(run_program("10 READ A#\n"
|
||||
"20 PRINT \"READ GAVE \" + A#\n"
|
||||
"30 DATA -5\n"
|
||||
"40 PRINT \"PAST IT\"\n"));
|
||||
TEST_REQUIRE_STR(HARNESS_OUTPUT, "READ GAVE -5\nPAST IT\n");
|
||||
harness_stop();
|
||||
|
||||
/* Mixed signs across a real table, and a negative float. */
|
||||
TEST_REQUIRE_OK(run_program("10 DATA -1, 2, -3\n"
|
||||
"20 DATA -0.5\n"
|
||||
"30 READ A#, B#, C#\n"
|
||||
"40 READ D%\n"
|
||||
"50 PRINT \"\" + A# + \" \" + B# + \" \" + C# + \" \" + D%\n"));
|
||||
TEST_REQUIRE_STR(HARNESS_OUTPUT, "-1 2 -3 -0.500000\n");
|
||||
harness_stop();
|
||||
}
|
||||
|
||||
int main(void)
|
||||
{
|
||||
test_read_in_order();
|
||||
@@ -197,5 +228,6 @@ int main(void)
|
||||
test_quoted_items();
|
||||
test_colon_ends_data();
|
||||
test_float_items();
|
||||
test_negative_items();
|
||||
return akbasic_test_failures;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user