112 lines
3.9 KiB
C
112 lines
3.9 KiB
C
|
|
/**
|
||
|
|
* @file parser_commands.c
|
||
|
|
* @brief Tests the verbs that carry their own parse path.
|
||
|
|
*/
|
||
|
|
|
||
|
|
#include "harness.h"
|
||
|
|
|
||
|
|
static void expect_command(const char *line, akbasic_LeafType wanttype, const char *wantname)
|
||
|
|
{
|
||
|
|
akbasic_ASTLeaf *leaf = NULL;
|
||
|
|
akerr_ErrorContext *e = NULL;
|
||
|
|
|
||
|
|
e = harness_parse(line, &leaf);
|
||
|
|
if ( e != NULL ) {
|
||
|
|
fprintf(stderr, "FAIL: \"%s\" did not parse: %s\n", line, e->message);
|
||
|
|
akbasic_test_failures += 1;
|
||
|
|
test_discard_error(e);
|
||
|
|
return;
|
||
|
|
}
|
||
|
|
TEST_REQUIRE(leaf != NULL, "\"%s\" produced no leaf", line);
|
||
|
|
if ( leaf == NULL ) {
|
||
|
|
return;
|
||
|
|
}
|
||
|
|
TEST_REQUIRE_INT(leaf->leaftype, wanttype);
|
||
|
|
if ( wantname != NULL ) {
|
||
|
|
TEST_REQUIRE_STR(leaf->identifier, wantname);
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
static void expect_parse_error(const char *line)
|
||
|
|
{
|
||
|
|
akbasic_ASTLeaf *leaf = NULL;
|
||
|
|
akerr_ErrorContext *e = NULL;
|
||
|
|
|
||
|
|
e = harness_parse(line, &leaf);
|
||
|
|
TEST_REQUIRE(e != NULL, "\"%s\" should not have parsed", line);
|
||
|
|
if ( e != NULL ) {
|
||
|
|
test_discard_error(e);
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
int main(void)
|
||
|
|
{
|
||
|
|
akbasic_ASTLeaf *leaf = NULL;
|
||
|
|
|
||
|
|
TEST_REQUIRE_OK(harness_start(NULL));
|
||
|
|
|
||
|
|
/* Plain verbs with an expression rval. */
|
||
|
|
expect_command("PRINT 1", AKBASIC_LEAF_COMMAND, "PRINT");
|
||
|
|
expect_command("GOTO 100", AKBASIC_LEAF_COMMAND, "GOTO");
|
||
|
|
expect_command("GOSUB 100", AKBASIC_LEAF_COMMAND, "GOSUB");
|
||
|
|
|
||
|
|
/* A verb with no rval at all must not fail. */
|
||
|
|
expect_command("RETURN", AKBASIC_LEAF_COMMAND, "RETURN");
|
||
|
|
expect_command("STOP", AKBASIC_LEAF_COMMAND, "STOP");
|
||
|
|
|
||
|
|
/* Immediate commands get their own leaf type. */
|
||
|
|
expect_command("QUIT", AKBASIC_LEAF_COMMAND_IMMEDIATE, "QUIT");
|
||
|
|
expect_command("LIST", AKBASIC_LEAF_COMMAND_IMMEDIATE, "LIST");
|
||
|
|
expect_command("RUN", AKBASIC_LEAF_COMMAND_IMMEDIATE, "RUN");
|
||
|
|
|
||
|
|
/* Verbs with their own parse path. */
|
||
|
|
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");
|
||
|
|
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");
|
||
|
|
|
||
|
|
/* LET parses as a bare assignment. */
|
||
|
|
expect_command("LET A# = 1", AKBASIC_LEAF_BINARY, NULL);
|
||
|
|
|
||
|
|
/* IF produces a BRANCH, not a COMMAND. */
|
||
|
|
expect_command("IF 1 == 1 THEN PRINT 1", AKBASIC_LEAF_BRANCH, NULL);
|
||
|
|
TEST_REQUIRE_OK(harness_parse("IF 1 == 1 THEN PRINT 1 ELSE PRINT 2", &leaf));
|
||
|
|
TEST_REQUIRE(leaf != NULL && leaf->left != NULL && leaf->right != NULL,
|
||
|
|
"IF ... THEN ... ELSE must fill both branches");
|
||
|
|
|
||
|
|
/* FOR installs a loop environment and returns the assignment. */
|
||
|
|
{
|
||
|
|
akbasic_Environment *before = HARNESS_RUNTIME.environment;
|
||
|
|
TEST_REQUIRE_OK(harness_parse("FOR I# = 1 TO 5", &leaf));
|
||
|
|
TEST_REQUIRE(HARNESS_RUNTIME.environment != before,
|
||
|
|
"FOR must install a new environment");
|
||
|
|
TEST_REQUIRE(HARNESS_RUNTIME.environment->forToLeaf != NULL,
|
||
|
|
"FOR must record its TO expression");
|
||
|
|
TEST_REQUIRE(HARNESS_RUNTIME.environment->forStepLeaf != NULL,
|
||
|
|
"FOR must default its STEP to 1");
|
||
|
|
TEST_REQUIRE_OK(akbasic_runtime_prev_environment(&HARNESS_RUNTIME));
|
||
|
|
}
|
||
|
|
{
|
||
|
|
akbasic_Environment *before = HARNESS_RUNTIME.environment;
|
||
|
|
TEST_REQUIRE_OK(harness_parse("FOR I# = 1 TO 10 STEP 2", &leaf));
|
||
|
|
TEST_REQUIRE(HARNESS_RUNTIME.environment != before, "FOR STEP must install an environment");
|
||
|
|
TEST_REQUIRE_OK(akbasic_runtime_prev_environment(&HARNESS_RUNTIME));
|
||
|
|
}
|
||
|
|
|
||
|
|
/* Malformed FOR is rejected at parse time. */
|
||
|
|
expect_parse_error("FOR I# = 1");
|
||
|
|
expect_parse_error("FOR I# = 1 TO 5 STEP");
|
||
|
|
expect_parse_error("FOR 1 TO 5");
|
||
|
|
|
||
|
|
/* Other malformed forms. */
|
||
|
|
expect_parse_error("IF 1 == 1 PRINT 1");
|
||
|
|
expect_parse_error("LABEL 5");
|
||
|
|
expect_parse_error("READ 1");
|
||
|
|
expect_parse_error("DATA A#");
|
||
|
|
|
||
|
|
harness_stop();
|
||
|
|
return akbasic_test_failures;
|
||
|
|
}
|