From e5cd69c26b7d087b9c7a4e7d2fa23cce92c06637 Mon Sep 17 00:00:00 2001 From: Camden Dixie O'Brien Date: Thu, 24 Oct 2024 21:20:57 +0100 Subject: [PATCH] Allow whitespace in expressions --- lib/reader.c | 39 +++++++++++++++++++++++++--- tests/reader_tests.c | 60 ++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 96 insertions(+), 3 deletions(-) diff --git a/lib/reader.c b/lib/reader.c index 1f73116..f86592e 100644 --- a/lib/reader.c +++ b/lib/reader.c @@ -6,6 +6,15 @@ static int parse_expression( memory_pool_t *pool, const char *input, int len, expression_t **out); +static int parse_whitespace(const char *input, int len) +{ + for (int i = 0; i < len; ++i) { + if (!isspace(input[i])) + return i; + } + return len; +} + static int parse_number( memory_pool_t *pool, const char *input, int len, expression_t **out) { @@ -29,10 +38,19 @@ static int parse_factor( memory_pool_t *pool, const char *input, int len, expression_t **out) { if (len > 1 && input[0] == '(') { - const int result = parse_expression(pool, input + 1, len - 1, out); + int result, used = 1; + + result = parse_whitespace(input + used, len - used); + used += result; + + result = parse_expression(pool, input + used, len - used, out); if (0 == result) return 0; - const int used = result + 1; + used += result; + + result = parse_whitespace(input + used, len - used); + used += result; + return len >= used && input[used] == ')' ? used + 1 : 0; } else { return parse_number(pool, input, len, out); @@ -53,6 +71,9 @@ static int parse_term( while (len > used) { const expression_t *term0 = expr; + result = parse_whitespace(input + used, len - used); + used += result; + operator_t operator; if ('*' == input[used]) operator= OPERATOR_MULTIPLY; @@ -62,6 +83,9 @@ static int parse_term( break; ++used; + result = parse_whitespace(input + used, len - used); + used += result; + expression_t *term1; result = parse_factor(pool, input + used, len - used, &term1); if (0 >= result) @@ -84,8 +108,11 @@ static int parse_expression( { int result, used = 0; + result = parse_whitespace(input + used, len - used); + used += result; + expression_t *expr; - result = parse_term(pool, input, len, &expr); + result = parse_term(pool, input + used, len - used, &expr); if (0 >= result) return 0; used += result; @@ -93,6 +120,9 @@ static int parse_expression( while (len > used) { const expression_t *term0 = expr; + result = parse_whitespace(input + used, len - used); + used += result; + operator_t operator; if ('+' == input[used]) operator= OPERATOR_ADD; @@ -102,6 +132,9 @@ static int parse_expression( break; ++used; + result = parse_whitespace(input + used, len - used); + used += result; + expression_t *term1; result = parse_term(pool, input + used, len - used, &term1); if (0 >= result) diff --git a/tests/reader_tests.c b/tests/reader_tests.c index 8a4b238..1df4e42 100644 --- a/tests/reader_tests.c +++ b/tests/reader_tests.c @@ -180,6 +180,60 @@ static void valid_expression_followed_by_garbage_yeilds_null(void) ASSERT_NULL(result); } +static void sum_with_single_spaces_around_plus_is_parsed_successfully(void) +{ + init_memory_pool(&pool); + const expression_t *result = read_expression(&pool, "1 + 2", 5); + ASSERT_NOT_NULL(result); + ASSERT_FALSE(result->is_number); + ASSERT_EQUAL(OPERATOR_ADD, result->application.operator); +} + +static void sum_with_multiple_spaces_around_plus_is_parsed_successfully(void) +{ + init_memory_pool(&pool); + const expression_t *result = read_expression(&pool, "1 + 2", 7); + ASSERT_NOT_NULL(result); + ASSERT_FALSE(result->is_number); + ASSERT_EQUAL(OPERATOR_ADD, result->application.operator); +} + +static void product_with_spaces_around_times_is_parsed_successfully(void) +{ + init_memory_pool(&pool); + const expression_t *result = read_expression(&pool, "1 * 2", 6); + ASSERT_NOT_NULL(result); + ASSERT_FALSE(result->is_number); + ASSERT_EQUAL(OPERATOR_MULTIPLY, result->application.operator); +} + +static void spaces_inside_parens_are_ignored(void) +{ + init_memory_pool(&pool); + const expression_t *result = read_expression(&pool, "( 14 )", 6); + ASSERT_NOT_NULL(result); + ASSERT_TRUE(result->is_number); + ASSERT_EQUAL(14, result->number); +} + +static void leading_spaces_are_ignored(void) +{ + init_memory_pool(&pool); + const expression_t *result = read_expression(&pool, " 14", 5); + ASSERT_NOT_NULL(result); + ASSERT_TRUE(result->is_number); + ASSERT_EQUAL(14, result->number); +} + +static void trailing_spaces_are_ignored(void) +{ + init_memory_pool(&pool); + const expression_t *result = read_expression(&pool, "14 ", 5); + ASSERT_NOT_NULL(result); + ASSERT_TRUE(result->is_number); + ASSERT_EQUAL(14, result->number); +} + int main(void) { TESTING_BEGIN(); @@ -196,5 +250,11 @@ int main(void) RUN_TEST(paren_1_plus_2_times_3_close_paren_parses_as_left_nested); RUN_TEST(garbage_input_yeilds_null); RUN_TEST(valid_expression_followed_by_garbage_yeilds_null); + RUN_TEST(sum_with_single_spaces_around_plus_is_parsed_successfully); + RUN_TEST(sum_with_multiple_spaces_around_plus_is_parsed_successfully); + RUN_TEST(product_with_spaces_around_times_is_parsed_successfully); + RUN_TEST(spaces_inside_parens_are_ignored); + RUN_TEST(leading_spaces_are_ignored); + RUN_TEST(trailing_spaces_are_ignored); TESTING_END(); }