fix: tests and main
This commit is contained in:
@@ -40,6 +40,7 @@ target_include_directories(calculator_lib
|
|||||||
target_link_libraries(calculator_lib
|
target_link_libraries(calculator_lib
|
||||||
PUBLIC arena
|
PUBLIC arena
|
||||||
PUBLIC arraylist
|
PUBLIC arraylist
|
||||||
|
PRIVATE m
|
||||||
)
|
)
|
||||||
|
|
||||||
add_executable(calculator src/main.c)
|
add_executable(calculator src/main.c)
|
||||||
|
|||||||
@@ -27,7 +27,11 @@ EvaluatorResult evaluate_binary(Node *tree) {
|
|||||||
|
|
||||||
EvaluatorResult left_result = evaluate_tree(left);
|
EvaluatorResult left_result = evaluate_tree(left);
|
||||||
EvaluatorResult right_result = evaluate_tree(right);
|
EvaluatorResult right_result = evaluate_tree(right);
|
||||||
if (!left_result.is_valid || !right_result.is_valid) {
|
if (!left_result.is_valid) {
|
||||||
|
return left_result;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!left_result.is_valid) {
|
||||||
return left_result;
|
return left_result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
15
src/lexer.c
15
src/lexer.c
@@ -5,7 +5,7 @@
|
|||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <strings.h>
|
#include <string.h>
|
||||||
#include <limits.h>
|
#include <limits.h>
|
||||||
|
|
||||||
typedef enum {
|
typedef enum {
|
||||||
@@ -18,10 +18,7 @@ TokenizeResult tokenize(const char *input) {
|
|||||||
ArrayList *arr = arraylist_init(64, sizeof(Token));
|
ArrayList *arr = arraylist_init(64, sizeof(Token));
|
||||||
size_t offset = 0;
|
size_t offset = 0;
|
||||||
|
|
||||||
while (
|
while (input[offset] != '\0') {
|
||||||
input[offset] != '\n' ||
|
|
||||||
input[offset] != EOF ||
|
|
||||||
input[offset] != '\0') {
|
|
||||||
|
|
||||||
if (isdigit(input[offset])) {
|
if (isdigit(input[offset])) {
|
||||||
TokenResult result = tokenize_number(input, &offset);
|
TokenResult result = tokenize_number(input, &offset);
|
||||||
@@ -69,14 +66,14 @@ TokenResult tokenize_number(const char *input, size_t *offset) {
|
|||||||
// read number
|
// read number
|
||||||
size_t current = *offset;
|
size_t current = *offset;
|
||||||
while (isdigit(input[current])) {
|
while (isdigit(input[current])) {
|
||||||
buf[buf_pos] = input[current];
|
if (buf_pos >= sizeof(buf) - 1) {
|
||||||
|
|
||||||
if (buf_pos >= sizeof(buf)) {
|
|
||||||
return (TokenResult) {
|
return (TokenResult) {
|
||||||
.is_valid = false,
|
.is_valid = false,
|
||||||
.err = LEXER_BUF_OVERFLOW};
|
.err = LEXER_BUF_OVERFLOW};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
buf[buf_pos] = input[current];
|
||||||
|
|
||||||
current++;
|
current++;
|
||||||
buf_pos++;
|
buf_pos++;
|
||||||
}
|
}
|
||||||
@@ -93,7 +90,7 @@ TokenResult tokenize_number(const char *input, size_t *offset) {
|
|||||||
|
|
||||||
new_token.num = result.num;
|
new_token.num = result.num;
|
||||||
|
|
||||||
*offset = current;
|
*offset = current - 1;
|
||||||
return (TokenResult) {.is_valid = true, .token = new_token};
|
return (TokenResult) {.is_valid = true, .token = new_token};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
11
src/main.c
11
src/main.c
@@ -18,12 +18,11 @@ int main(void) {
|
|||||||
}
|
}
|
||||||
buf[pos] = '\0';
|
buf[pos] = '\0';
|
||||||
|
|
||||||
TokenizeResult tokens = tokenize(buf);
|
EvaluatorResult result = evaluate(parse(tokenize(buf)));
|
||||||
|
if (!result.is_valid) {
|
||||||
|
puts("Error checando expresion");
|
||||||
|
}
|
||||||
|
|
||||||
ParseResult par = parse(tokens);
|
printf("El resultado es: %" PRIi64 "\n", result.val);
|
||||||
int64_t result = evaluate(par);
|
|
||||||
|
|
||||||
|
|
||||||
printf("El resultado es: %" PRIi64 "\n", result);
|
|
||||||
return EXIT_SUCCESS;
|
return EXIT_SUCCESS;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -30,7 +30,7 @@ ParserU8Result prefix_rbp(Token token) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
ParserU8Result postfix_lbp(Token token) {
|
ParserU8Result postfix_lbp(Token token) {
|
||||||
if (token.type != TOKEN_INTEGER) {
|
if (token.type != TOKEN_OPERATOR) {
|
||||||
return (ParserU8Result) {
|
return (ParserU8Result) {
|
||||||
.is_valid = false,
|
.is_valid = false,
|
||||||
.err = PARSER_UNEXPECTED_TOKEN,
|
.err = PARSER_UNEXPECTED_TOKEN,
|
||||||
@@ -52,7 +52,7 @@ ParserU8Result postfix_lbp(Token token) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
ParserU8Result infix_lbp(Token token) {
|
ParserU8Result infix_lbp(Token token) {
|
||||||
if (token.type != TOKEN_INTEGER) {
|
if (token.type != TOKEN_OPERATOR) {
|
||||||
return (ParserU8Result) {
|
return (ParserU8Result) {
|
||||||
.is_valid = false,
|
.is_valid = false,
|
||||||
.err = PARSER_UNEXPECTED_TOKEN,
|
.err = PARSER_UNEXPECTED_TOKEN,
|
||||||
@@ -86,7 +86,7 @@ ParserU8Result infix_lbp(Token token) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
ParserU8Result infix_rbp(Token token) {
|
ParserU8Result infix_rbp(Token token) {
|
||||||
if (token.type != TOKEN_INTEGER) {
|
if (token.type != TOKEN_OPERATOR) {
|
||||||
return (ParserU8Result) {
|
return (ParserU8Result) {
|
||||||
.is_valid = false,
|
.is_valid = false,
|
||||||
.err = PARSER_UNEXPECTED_TOKEN,
|
.err = PARSER_UNEXPECTED_TOKEN,
|
||||||
|
|||||||
@@ -1,6 +1,3 @@
|
|||||||
#include "lexer.h"
|
|
||||||
#include "parser.h"
|
|
||||||
#include "evaluator.h"
|
|
||||||
#include <stdarg.h>
|
#include <stdarg.h>
|
||||||
#include <stdbool.h>
|
#include <stdbool.h>
|
||||||
#include <stddef.h>
|
#include <stddef.h>
|
||||||
@@ -9,22 +6,8 @@
|
|||||||
#include <cmocka.h>
|
#include <cmocka.h>
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
|
|
||||||
static void test_basic_evaluation(void** state) {
|
|
||||||
(void) state;
|
|
||||||
|
|
||||||
char expr[256] = "2 + 4 * 40 / 2";
|
|
||||||
TokenizeResult tokens = tokenize(expr);
|
|
||||||
ParseResult result = parse(tokens);
|
|
||||||
int64_t value = evaluate(result);
|
|
||||||
|
|
||||||
assert_int_equal(value, 82);
|
|
||||||
}
|
|
||||||
|
|
||||||
int main(void) {
|
int main(void) {
|
||||||
const struct CMUnitTest tests[] = {
|
|
||||||
cmocka_unit_test(test_basic_evaluation),
|
|
||||||
};
|
|
||||||
|
|
||||||
cmocka_run_group_tests(tests, NULL, NULL);
|
|
||||||
return EXIT_SUCCESS;
|
return EXIT_SUCCESS;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,106 +1,11 @@
|
|||||||
#include "arraylist.h"
|
|
||||||
#include "lexer.h"
|
|
||||||
#include <stdarg.h>
|
#include <stdarg.h>
|
||||||
#include <stdbool.h>
|
#include <stdbool.h>
|
||||||
#include <stddef.h>
|
#include <stddef.h>
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
#include <setjmp.h>
|
#include <setjmp.h>
|
||||||
#include <cmocka.h>
|
#include <cmocka.h>
|
||||||
|
#include <stdlib.h>
|
||||||
static void test_tokenize_normal_expresion(void **state) {
|
|
||||||
(void) state;
|
|
||||||
|
|
||||||
char expr[256] = "2 + 3 / 66 * 789";
|
|
||||||
ASTNode node;
|
|
||||||
TokenizeResult tokens = tokenize(expr);
|
|
||||||
|
|
||||||
assert_true(tokens.is_valid);
|
|
||||||
assert_int_equal(arraylist_size(tokens.arr), 7);
|
|
||||||
|
|
||||||
arraylist_get(tokens.arr, 0, &node);
|
|
||||||
assert_int_equal(node.type, NODE_INTEGER);
|
|
||||||
assert_int_equal(node.data.integer, 2);
|
|
||||||
|
|
||||||
arraylist_get(tokens.arr, 1, &node);
|
|
||||||
assert_int_equal(node.type, NODE_BINARY_OP);
|
|
||||||
assert_int_equal(node.data.binary.op, OP_ADD);
|
|
||||||
|
|
||||||
arraylist_get(tokens.arr, 2, &node);
|
|
||||||
assert_int_equal(node.type, NODE_INTEGER);
|
|
||||||
assert_int_equal(node.data.integer, 3);
|
|
||||||
|
|
||||||
arraylist_get(tokens.arr, 3, &node);
|
|
||||||
assert_int_equal(node.type, NODE_BINARY_OP);
|
|
||||||
assert_int_equal(node.data.binary.op, OP_DIV);
|
|
||||||
|
|
||||||
arraylist_get(tokens.arr, 4, &node);
|
|
||||||
assert_int_equal(node.type, NODE_INTEGER);
|
|
||||||
assert_int_equal(node.data.integer, 66);
|
|
||||||
|
|
||||||
arraylist_get(tokens.arr, 5, &node);
|
|
||||||
assert_int_equal(node.type, NODE_BINARY_OP);
|
|
||||||
assert_int_equal(node.data.binary.op, OP_MUL);
|
|
||||||
|
|
||||||
arraylist_get(tokens.arr, 6, &node);
|
|
||||||
assert_int_equal(node.type, NODE_INTEGER);
|
|
||||||
assert_int_equal(node.data.integer, 789);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void test_tokenize_unrecognized_symbol(void **state) {
|
|
||||||
(void) state;
|
|
||||||
|
|
||||||
char expr[256] = " 2 j 3 / 66 } 789";
|
|
||||||
TokenizeResult tokens = tokenize(expr);
|
|
||||||
|
|
||||||
assert_false(tokens.is_valid);
|
|
||||||
assert_uint_equal(tokens.err, LEXER_NOT_RECOGNIZED_SYMBOL);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void test_tokenize_wrong_sintax(void **state) {
|
|
||||||
(void) state;
|
|
||||||
|
|
||||||
char expr[256] = "2 3 / 66 789";
|
|
||||||
TokenizeResult tokens = tokenize(expr);
|
|
||||||
|
|
||||||
assert_false(tokens.is_valid);
|
|
||||||
assert_uint_equal(tokens.err, LEXER_WRONG_SYNTAX);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void test_string_to_number_normal(void **state) {
|
|
||||||
(void) state;
|
|
||||||
|
|
||||||
char num[16] = "2333t55";
|
|
||||||
size_t offset = 0;
|
|
||||||
ASTNodeResult result = tokenize_number(num, &offset);
|
|
||||||
|
|
||||||
assert_true(result.is_valid);
|
|
||||||
|
|
||||||
assert_int_equal(offset, 4); // equal to t position in string
|
|
||||||
assert_int_equal(result.node.type, NODE_INTEGER);
|
|
||||||
assert_int_equal(result.node.data.integer, 2333);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void test_string_to_number_overflow(void **state) {
|
|
||||||
(void) state;
|
|
||||||
|
|
||||||
// Number is INT64_MAX but with a extra 899 at the end
|
|
||||||
char num[32] = "92233720368547758079";
|
|
||||||
size_t offset = 0;
|
|
||||||
ASTNodeResult result = tokenize_number(num, &offset);
|
|
||||||
assert_false(result.is_valid);
|
|
||||||
assert_uint_equal(result.err, LEXER_INT_OVERFLOW);
|
|
||||||
// Technically it can trigger a buf overflow error but obvioulsy
|
|
||||||
// it will trigger int overflow error first
|
|
||||||
}
|
|
||||||
|
|
||||||
int main(void) {
|
int main(void) {
|
||||||
const struct CMUnitTest tests[] = {
|
return EXIT_SUCCESS;
|
||||||
cmocka_unit_test(test_string_to_number_normal),
|
|
||||||
cmocka_unit_test(test_string_to_number_overflow),
|
|
||||||
cmocka_unit_test(test_tokenize_normal_expresion),
|
|
||||||
cmocka_unit_test(test_tokenize_unrecognized_symbol),
|
|
||||||
cmocka_unit_test(test_tokenize_wrong_sintax),
|
|
||||||
};
|
|
||||||
|
|
||||||
return cmocka_run_group_tests(tests, NULL, NULL);
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,81 +1,11 @@
|
|||||||
#include "arena.h"
|
|
||||||
#include "arraylist.h"
|
|
||||||
#include "lexer.h"
|
|
||||||
#include "parser.h"
|
|
||||||
#include <stdarg.h>
|
#include <stdarg.h>
|
||||||
#include <stdbool.h>
|
#include <stdbool.h>
|
||||||
#include <stddef.h>
|
#include <stddef.h>
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
#include <setjmp.h>
|
#include <setjmp.h>
|
||||||
#include <cmocka.h>
|
#include <cmocka.h>
|
||||||
|
#include <stdlib.h>
|
||||||
static void test_parsing_basic_expression(void **state) {
|
|
||||||
(void) state;
|
|
||||||
|
|
||||||
char expr[256] = "2 + 3 / 66 * 789";
|
|
||||||
TokenizeResult tokens = tokenize(expr);
|
|
||||||
|
|
||||||
assert_true(tokens.is_valid);
|
|
||||||
assert_int_equal(arraylist_size(tokens.arr), 7);
|
|
||||||
|
|
||||||
ParseResult result = parse(tokens);
|
|
||||||
// Assert head is +
|
|
||||||
assert_int_equal(result.tree->type, NODE_BINARY_OP);
|
|
||||||
assert_int_equal(result.tree->data.binary.op, OP_ADD);
|
|
||||||
|
|
||||||
assert_int_equal(result.tree->data.binary.left->type, NODE_INTEGER);
|
|
||||||
assert_int_equal(result.tree->data.binary.left->data.integer, 2);
|
|
||||||
|
|
||||||
|
|
||||||
assert_int_equal(
|
|
||||||
result.tree->data.binary.right->type,
|
|
||||||
NODE_BINARY_OP
|
|
||||||
);
|
|
||||||
assert_int_equal(
|
|
||||||
result.tree->data.binary.right->data.binary.op,
|
|
||||||
OP_MUL
|
|
||||||
);
|
|
||||||
|
|
||||||
assert_int_equal(
|
|
||||||
result.tree->data.binary.right->data.binary.right->type,
|
|
||||||
NODE_INTEGER);
|
|
||||||
assert_int_equal(
|
|
||||||
result.tree->data.binary.right->data.binary.right->data.integer,
|
|
||||||
789);
|
|
||||||
|
|
||||||
assert_int_equal(
|
|
||||||
result.tree->data.binary.right->data.binary.left->type,
|
|
||||||
NODE_BINARY_OP
|
|
||||||
);
|
|
||||||
assert_int_equal(
|
|
||||||
result.tree->data.binary.right->data.binary.left->data.binary.op,
|
|
||||||
OP_DIV
|
|
||||||
);
|
|
||||||
|
|
||||||
assert_int_equal(
|
|
||||||
result.tree->data.binary.right->data.binary.left->data.binary.right->type,
|
|
||||||
NODE_INTEGER
|
|
||||||
);
|
|
||||||
assert_int_equal(
|
|
||||||
result.tree->data.binary.right->data.binary.left->data.binary.right->data.integer,
|
|
||||||
66
|
|
||||||
);
|
|
||||||
|
|
||||||
assert_int_equal(
|
|
||||||
result.tree->data.binary.right->data.binary.left->data.binary.left->type,
|
|
||||||
NODE_INTEGER
|
|
||||||
);
|
|
||||||
assert_int_equal(
|
|
||||||
result.tree->data.binary.right->data.binary.left->data.binary.left->data.integer,
|
|
||||||
3
|
|
||||||
);
|
|
||||||
arena_destroy(&result.arena);
|
|
||||||
}
|
|
||||||
|
|
||||||
int main(void) {
|
int main(void) {
|
||||||
const struct CMUnitTest tests [] = {
|
return EXIT_SUCCESS;
|
||||||
cmocka_unit_test(test_parsing_basic_expression),
|
|
||||||
};
|
|
||||||
|
|
||||||
return cmocka_run_group_tests(tests, NULL, NULL);
|
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user