/** * @file parser_expressions.c * @brief Tests the expression grammar via the leaf renderer. */ #include "harness.h" /* Parse a line and assert the shape of the tree it produced. */ static void expect_tree(const char *line, const char *want) { akbasic_ASTLeaf *leaf = NULL; char rendered[AKBASIC_MAX_STRING_LENGTH]; 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; } e = akbasic_leaf_to_string(leaf, rendered, sizeof(rendered)); if ( e != NULL ) { test_discard_error(e); akbasic_test_failures += 1; return; } TEST_REQUIRE(strcmp(rendered, want) == 0, "\"%s\": expected %s, got %s", line, want, rendered); } 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)); /* * An assignment renders with an empty operator: the reference's * operatorToStr() has a case for EQUAL but none for ASSIGNMENT, so it prints * "( A# ...)". Reproduced, so these expectations look odd on purpose. */ /* Multiplication binds tighter than addition. */ expect_tree("PRINT 1 + 2 * 3", "(PRINT)"); expect_tree("A# = 1 + 2 * 3", "( A# (+ 1 (* 2 3)))"); expect_tree("A# = 1 * 2 + 3", "( A# (+ (* 1 2) 3))"); expect_tree("A# = 8 / 2 / 2", "( A# (/ (/ 8 2) 2))"); /* Grouping overrides precedence. */ expect_tree("A# = (1 + 2) * 3", "( A# (* (group (+ 1 2)) 3))"); /* Unary minus and NOT. */ expect_tree("A# = -5", "( A# (- 5))"); expect_tree("A# = NOT 1", "( A# (NOT 1))"); /* Comparisons sit below the arithmetic. */ expect_tree("A# = 1 + 1 == 2", "( A# (= (+ 1 1) 2))"); expect_tree("A# = 1 <> 2", "( A# (<> 1 2))"); /* AND and OR sit below comparison. */ expect_tree("A# = 1 == 1 AND 2 == 2", "( A# (AND (= 1 1) (= 2 2)))"); /* Exponent. */ expect_tree("A# = 2 ^ 3", "( A# (^ 2 3))"); /* * Addition loops over its operator; subtraction returns after one. So * `1 + 2 + 3` folds left, while `1 - 2 - 3` parses only `1 - 2` and leaves * `- 3` in the token stream for the statement loop to pick up as a second * statement. That silently computes the wrong answer -- TODO.md section 12 * item 12 -- and is pinned here so the fix is a deliberate change to this * assertion and not an accident. */ expect_tree("A# = 1 + 2 + 3", "( A# (+ (+ 1 2) 3))"); expect_tree("A# = 1 - 2 - 3", "( A# (- 1 2))"); /* An array reference parses as an identifier carrying a subscript list. */ TEST_REQUIRE_OK(harness_parse("A#(2) = 1", &leaf)); TEST_REQUIRE(leaf != NULL && leaf->left != NULL, "assignment must have an lvalue"); if ( leaf != NULL && leaf->left != NULL ) { TEST_REQUIRE_INT(leaf->left->leaftype, AKBASIC_LEAF_IDENTIFIER_INT); TEST_REQUIRE(akbasic_leaf_first_subscript(leaf->left) != NULL, "A#(2) must carry an array subscript"); } /* Failure paths. */ expect_parse_error("A# = "); expect_parse_error("A# = (1 + 2"); expect_parse_error("A# = *"); harness_stop(); return akbasic_test_failures; }