diff --git a/.github/workflows/valgrind.yml b/.github/workflows/valgrind.yml index 8178015..3685433 100644 --- a/.github/workflows/valgrind.yml +++ b/.github/workflows/valgrind.yml @@ -20,10 +20,5 @@ jobs: run: make all - name: Run tests under Valgrind - run: | - valgrind --leak-check=full \ - --show-leak-kinds=all \ - --track-origins=yes \ - --error-exitcode=1 \ - ./build/cleaf test.clf + run: make valgrind-test diff --git a/Makefile b/Makefile index de0f208..49558cf 100644 --- a/Makefile +++ b/Makefile @@ -62,8 +62,33 @@ asan-test: CFLAGS="-fsanitize=address,undefined -g -O1" make test valgrind-test: - valgrind --error-exitcode=1 --leak-check=full --show-leak-kinds=all ./build/cleaf test.clf - + @echo "Testing memory safety with valgrind..." + @echo "=== Testing normal execution ===" + valgrind --error-exitcode=1 --leak-check=full --show-leak-kinds=all ./build/cleaf test/valgrind_case/full.clf + @echo "=== Testing lexer errors ===" + valgrind --error-exitcode=1 --leak-check=full --show-leak-kinds=all ./build/cleaf test/valgrind_case/lexer_error.clf + @echo "=== Testing parser errors ===" + valgrind --error-exitcode=1 --leak-check=full --show-leak-kinds=all ./build/cleaf test/valgrind_case/parser_missing_semicolon.clf + valgrind --error-exitcode=1 --leak-check=full --show-leak-kinds=all ./build/cleaf test/valgrind_case/parser_unmatched_brace.clf + valgrind --error-exitcode=1 --leak-check=full --show-leak-kinds=all ./build/cleaf test/valgrind_case/parser_missing_paren.clf + valgrind --error-exitcode=1 --leak-check=full --show-leak-kinds=all ./build/cleaf test/valgrind_case/parser_incomplete_function.clf + valgrind --error-exitcode=1 --leak-check=full --show-leak-kinds=all ./build/cleaf test/valgrind_case/parser_missing_function_name.clf + valgrind --error-exitcode=1 --leak-check=full --show-leak-kinds=all ./build/cleaf test/valgrind_case/parser_missing_var_name.clf + valgrind --error-exitcode=1 --leak-check=full --show-leak-kinds=all ./build/cleaf test/valgrind_case/parser_for_missing_increment.clf + @echo "=== Testing semantic errors ===" + valgrind --error-exitcode=1 --leak-check=full --show-leak-kinds=all ./build/cleaf test/valgrind_case/semantic_function_reserved.clf + valgrind --error-exitcode=1 --leak-check=full --show-leak-kinds=all ./build/cleaf test/valgrind_case/semantic_undefined_vars.clf + valgrind --error-exitcode=1 --leak-check=full --show-leak-kinds=all ./build/cleaf test/valgrind_case/semantic_type_mismatch.clf + valgrind --error-exitcode=1 --leak-check=full --show-leak-kinds=all ./build/cleaf test/valgrind_case/semantic_var_redefinition.clf + valgrind --error-exitcode=1 --leak-check=full --show-leak-kinds=all ./build/cleaf test/valgrind_case/semantic_undefined_function.clf + valgrind --error-exitcode=1 --leak-check=full --show-leak-kinds=all ./build/cleaf test/valgrind_case/semantic_function_duplicate.clf + valgrind --error-exitcode=1 --leak-check=full --show-leak-kinds=all ./build/cleaf test/valgrind_case/semantic_function_args_error.clf + valgrind --error-exitcode=1 --leak-check=full --show-leak-kinds=all ./build/cleaf test/valgrind_case/semantic_return_type_error.clf + valgrind --error-exitcode=1 --leak-check=full --show-leak-kinds=all ./build/cleaf test/valgrind_case/semantic_unary_type_error.clf + valgrind --error-exitcode=1 --leak-check=full --show-leak-kinds=all ./build/cleaf test/valgrind_case/semantic_control_flow_errors.clf + @echo "=== Testing combined errors ===" + valgrind --error-exitcode=1 --leak-check=full --show-leak-kinds=all ./build/cleaf test/valgrind_case/combined_multiple_errors.clf + @echo "=== All valgrind tests passed ===" clean: rm -rf $(BUILD) diff --git a/src/frontend/ast.c b/src/frontend/ast.c index ad31792..2ecd067 100644 --- a/src/frontend/ast.c +++ b/src/frontend/ast.c @@ -368,135 +368,96 @@ expression_t* ast_parse_expr_assign(parser_t* p) return e; } -expression_t* ast_parse_expr_binary(parser_t* p) +expression_t* ast_parse_expr_binary(parser_t* p, int min_bp) { - expression_t* e = (expression_t*) malloc(sizeof(expression_t)); - if (!e) { - error_report_general(ERROR_SEVERITY_ERROR, "out of memory"); + token_t* tok; + expression_t* expr = parse_primary(p); + if (!expr) { + // TODO: add some sort of error_report_stack_trace later on return NULL; } - memset(e, 0, sizeof(expression_t)); - e->type = EXPRESSION_BINARY; - e->source_pos = peek(p)->source_pos; + while ((tok = peek(p))->type != ';' && + (tok = peek(p))->type != ')') { + int lbp, rbp; + switch (tok->type) { + case '+': case '-': + lbp = 10; rbp = 11; + break; + case '*': case '/': + lbp = 20; rbp = 21; + break; + case '>': + case '<': + case LEXER_token_gteq: + case LEXER_token_lseq: + lbp = 5; rbp = 6; + break; + case LEXER_token_eq: + case LEXER_token_neq: + lbp = 4; + rbp = 5; + break; + } - expression_t* left = (expression_t*) malloc(sizeof(expression_t)); - if (!left) { - error_report_general(ERROR_SEVERITY_ERROR, "out of memory"); - free_expression(e); - return NULL; - } - memset(left, 0, sizeof(expression_t)); - - token_t* left_tok = advance(p); - left->source_pos = left_tok->source_pos; - switch (left_tok->type) { - case LEXER_token_intlit: - left->type = EXPRESSION_INT_LIT; - left->int_lit.value = left_tok->int_value; - break; - case LEXER_token_dqstring: - left->type = EXPRESSION_STRING_LIT; - if (!left_tok->string_value) { - if (p->error_ctx) { - error_report_at_token(p->error_ctx, left_tok, ERROR_SEVERITY_ERROR, - "string literal has no value"); - } - free_expression(e); - free_expression(left); - return NULL; - } - left->string_lit.value = strdup(left_tok->string_value); - if (!left->string_lit.value) { - error_report_general(ERROR_SEVERITY_ERROR, "out of memory"); - free_expression(e); - free_expression(left); - return NULL; - } - break; - case LEXER_token_id: - left->type = EXPRESSION_VAR; - if (!left_tok->string_value) { - if (p->error_ctx) { - error_report_at_token(p->error_ctx, left_tok, ERROR_SEVERITY_ERROR, - "identifier has no value"); - } - free_expression(e); - free_expression(left); - return NULL; - } - left->var.name = strdup(left_tok->string_value); - if (!left->var.name) { - error_report_general(ERROR_SEVERITY_ERROR, "out of memory"); - free_expression(e); - free_expression(left); - return NULL; - } - break; - default: - // unexpected - if (p->error_ctx) { - error_report_at_token(p->error_ctx, left_tok, ERROR_SEVERITY_ERROR, - "unexpected token in binary expression"); - } - free_expression(e); - free_expression(left); + if (lbp < min_bp) break; + + expression_t* e = (expression_t*) calloc(1, sizeof(expression_t)); + if (!e) { + error_report_general(ERROR_SEVERITY_ERROR, "out of memory"); + free_expression(expr); return NULL; - } + } - e->binary.left = left; - - token_t* op_tok = advance(p); - switch (op_tok->type) { - case '+': - e->binary.op = BINARY_PLUS; - break; - case '-': - e->binary.op = BINARY_MINUS; - break; - case '*': - e->binary.op = BINARY_MUL; - break; - case '/': - e->binary.op = BINARY_DIV; - break; - case '>': - e->binary.op = BINARY_GT; - break; - case LEXER_token_gteq: - e->binary.op = BINARY_GTE; - break; - case '<': - e->binary.op = BINARY_LT; - break; - case LEXER_token_lseq: - e->binary.op = BINARY_LTE; - break; - case LEXER_token_eq: - e->binary.op = BINARY_EQ; - break; - case LEXER_token_neq: - e->binary.op = BINARY_NEQ; - break; - default: - error_report_at_token(p->error_ctx, op_tok, ERROR_SEVERITY_ERROR, - "unexpected binary operation token"); - } - - e->binary.right = parse_expression(p); - if (!e->binary.right) { - if (p->error_ctx) { - error_report_at_token(p->error_ctx, op_tok, ERROR_SEVERITY_ERROR, - "expected expression after binary operator"); + advance(p); + + e->type = EXPRESSION_BINARY; + e->source_pos = tok->source_pos; + + switch (tok->type) { + case '*': + e->binary.op = BINARY_MUL; + break; + case '/': + e->binary.op = BINARY_DIV; + break; + case '+': + e->binary.op = BINARY_PLUS; + break; + case '-': + e->binary.op = BINARY_MINUS; + break; + case '>': + e->binary.op = BINARY_GT; + break; + case '<': + e->binary.op = BINARY_LT; + break; + case LEXER_token_gteq: + e->binary.op = BINARY_GTE; + break; + case LEXER_token_lseq: + e->binary.op = BINARY_LTE; + break; + case LEXER_token_eq: + e->binary.op = BINARY_EQ; + break; + case LEXER_token_neq: + e->binary.op = BINARY_NEQ; + break; } - free_expression(e); - return NULL; - } - return e; + expression_t* right = ast_parse_expr_binary(p, rbp); + + e->binary.left = expr; + e->binary.right = right; + expr = e; + } + + return expr; } -expression_t* ast_parse_expr_call(parser_t* p) +expression_t* ast_parse_expr_call(parser_t* p) { expression_t* e = (expression_t*) malloc(sizeof(expression_t)); if (!e) { @@ -651,6 +612,24 @@ expression_t* ast_parse_expr_unary(parser_t* p) return e; } +expression_t* parse_primary(parser_t* p) +{ + if (check(p, LEXER_token_id) && check_next(p, '(', 1)) { + return ast_parse_expr_call(p); + } + + if (check(p, LEXER_token_id)) + return ast_parse_expr_var(p); + + if (check(p, LEXER_token_dqstring)) + return ast_parse_expr_string_lit(p); + + if (check(p, LEXER_token_intlit)) + return ast_parse_expr_int_lit(p); + + return NULL; +} + expression_t* parse_expression(parser_t* p) { if (check_next(p, '=', 1)) @@ -670,11 +649,11 @@ expression_t* parse_expression(parser_t* p) check_next(p, '/', 1) || check_next(p, '<', 1) || check_next(p, '>', 1) || - check_next(p, LEXER_token_eq, 1) || - check_next(p, LEXER_token_neq, 1) || check_next(p, LEXER_token_gteq, 1) || - check_next(p, LEXER_token_lseq, 1)) - return ast_parse_expr_binary(p); + check_next(p, LEXER_token_lseq, 1) || + check_next(p, LEXER_token_eq, 1) || + check_next(p, LEXER_token_neq, 1)) + return ast_parse_expr_binary(p, 0); if (check(p, LEXER_token_id) && check_next(p, '(', 1)) { return ast_parse_expr_call(p); @@ -1416,7 +1395,8 @@ statement_t* parse_statement(parser_t* p) return ast_parse_decl_stmt(p); } - // for now, we can maybe assume that this is the always wanted fallback - // TODO: keep an eye on this - return ast_parse_expr_stmt(p); + if ((size_t) p->pos < p->count) + return ast_parse_expr_stmt(p); + + return NULL; } diff --git a/src/frontend/ast.h b/src/frontend/ast.h index e3b9ee7..fbc4795 100644 --- a/src/frontend/ast.h +++ b/src/frontend/ast.h @@ -43,6 +43,7 @@ declaration_t* ast_parse_function(parser_t* p); declaration_t* ast_parse_var_decl(parser_t* p); declaration_t* ast_parse_untype_var_decl(parser_t* p); declaration_t* parse_declaration(parser_t* p); + statement_t* ast_parse_return_stmt(parser_t* p); statement_t* ast_parse_decl_stmt(parser_t* p); statement_t* ast_parse_expr_stmt(parser_t* p); @@ -50,12 +51,16 @@ statement_t* ast_parse_if_stmt(parser_t* p); statement_t* ast_parse_while_stmt(parser_t* p); statement_t* ast_parse_for_stmt(parser_t* p); statement_t* parse_statement(parser_t* p); + expression_t* parse_expression(parser_t* p); +expression_t* parse_primary(parser_t* p); expression_t* ast_parse_expr_int_lit(parser_t* p); expression_t* ast_parse_expr_string_lit(parser_t* p); expression_t* ast_parse_expr_var(parser_t* p); expression_t* ast_parse_expr_assign(parser_t* p); -expression_t* ast_parse_expr_binary(parser_t* p); +expression_t* ast_parse_expr_binary(parser_t* p, + int bp); +expression_t* ast_parse_expr_comparison_binary(parser_t* p); expression_t* ast_parse_expr_call(parser_t* p); expression_t* ast_parse_expr_unary(parser_t* p); diff --git a/src/frontend/semantic.c b/src/frontend/semantic.c index 1d9a020..c3b336a 100644 --- a/src/frontend/semantic.c +++ b/src/frontend/semantic.c @@ -39,6 +39,8 @@ void semantic_analyze(semantic_analyzer_t* analyzer) analyzer->function_symbols, (*it)->func.name); + if (!fs) continue; + for (size_t i = 0; i < fs->params_count; ++i) hashmap_put(function_scope->symbols, fs->params_name[i], @@ -54,6 +56,22 @@ void semantic_analyze(semantic_analyzer_t* analyzer) semantic_error_display(analyzer); } +int semantic_check_name_not_reserved(const char* name) +{ + int left = 0, right = reserved_keyword_count - 1; + + while (left <= right) { + int mid = (left + right) / 2; + int cmp = strcmp(name, reserved_keywords[mid]); + + if (cmp == 0) return 1; + if (cmp < 0) right = mid - 1; + else left = mid + 1; + } + + return 0; +} + int analyze_declaration(semantic_analyzer_t* analyzer, declaration_t* decl, scope_t* scope) @@ -63,6 +81,11 @@ int analyze_declaration(semantic_analyzer_t* analyzer, decl->var_decl.ident.source_pos - 1, "already defined variable redifinition"); return 0; + } else if (semantic_check_name_not_reserved(decl->var_decl.ident.name)) { + semantic_error_register(analyzer, + decl->var_decl.ident.source_pos - 1, + "can't named a variable using a reserved keyword"); + return 0; } else { return 1; } @@ -358,9 +381,16 @@ void semantic_load_function_definition(semantic_analyzer_t* analyzer) if ((*it)->type!= DECLARATION_FUNC) continue; + if (semantic_check_name_not_reserved((*it)->func.name)) { + semantic_error_register(analyzer, + (*it)->source_pos + 1, + "can't named a function using a reserved keyword"); + continue; + } + if (hashmap_get(func_sym, (*it)->func.name)) { const char* pos = (*it)->source_pos + 1; - semantic_error_register(analyzer, pos, "already defined function redifinition"); + semantic_error_register(analyzer, pos, "already defined function redefinition"); continue; } diff --git a/src/frontend/semantic.h b/src/frontend/semantic.h index afc6787..bb8b4c2 100644 --- a/src/frontend/semantic.h +++ b/src/frontend/semantic.h @@ -12,6 +12,26 @@ #include #include +// WARNING: keep this sorted (this is a bit poor but whatever) +static const char* reserved_keywords[] = { + "break", + "continue", + "else", + "false", + "fn", + "for", + "if", + "int", + "return", + "string", + "true", + "var", + "while", +}; + +static const size_t reserved_keyword_count = + sizeof(reserved_keywords) / sizeof(reserved_keywords[0]); + typedef struct { const char* message; @@ -72,5 +92,6 @@ void semantic_error_register(semantic_analyzer_t* analyzer, const char* pos, const char* msg); void semantic_error_display(semantic_analyzer_t* analyzer); +int semantic_check_name_not_reserved(const char* name); #endif // SEMANTIC_H diff --git a/test/semantic_case/function_declaration_reserved_keywords.clf b/test/semantic_case/function_declaration_reserved_keywords.clf new file mode 100644 index 0000000..a901d9f --- /dev/null +++ b/test/semantic_case/function_declaration_reserved_keywords.clf @@ -0,0 +1,11 @@ +fn var() {} + +fn int() {} + +fn if() {} + +fn return() {} + +fn false() {} + +fn fn() {} diff --git a/test/semantic_case/var_decl_reserved_keywords.clf b/test/semantic_case/var_decl_reserved_keywords.clf new file mode 100644 index 0000000..00a74ac --- /dev/null +++ b/test/semantic_case/var_decl_reserved_keywords.clf @@ -0,0 +1,10 @@ +fn main(): int { + var var; + var if; + var int; + var false; + var return; + var fn; + + return 0; +} diff --git a/test/semantic_test.c b/test/semantic_test.c index 02995b7..47f0c18 100644 --- a/test/semantic_test.c +++ b/test/semantic_test.c @@ -325,3 +325,13 @@ ct_test(semantic_case, function_call_use_return_error, "test/semantic_case/funct ct_assert_eq(analyzer.error_count, 2, "Should have 2 errors on different test case with function call return type"); free_analyzer(&analyzer); } + +ct_test(semantic_case, function_declaration_reserved_keywords, "test/semantic_case/function_declaration_reserved_keywords.clf") { + ct_assert_eq(analyzer.error_count, 6, "Should have 6 errors for different test case on function declaration with reserve keywords"); + free_analyzer(&analyzer); +} + +ct_test(semantic_case, var_decl_reserved_keywords, "test/semantic_case/var_decl_reserved_keywords.clf") { + ct_assert_eq(analyzer.error_count, 6, "Should have 6 errors for different test case on var decl with reserved keywords"); + free_analyzer(&analyzer); +} diff --git a/test/valgrind_case/README.md b/test/valgrind_case/README.md new file mode 100644 index 0000000..c9800c6 --- /dev/null +++ b/test/valgrind_case/README.md @@ -0,0 +1,8 @@ +# Valgrind test case + +The goal of this dir is to create cleaf program that valgrind will test to verify that there is no memory leaks. + +Here is the strategy: + +- maintain some base cleaf program that runs completely to check memory safety in a normal environment +- test every early compiler termination by adding cleaf files that should not compile to check that not running the compiler entirely don't cause memory leak diff --git a/test/valgrind_case/combined_multiple_errors.clf b/test/valgrind_case/combined_multiple_errors.clf new file mode 100644 index 0000000..719b667 --- /dev/null +++ b/test/valgrind_case/combined_multiple_errors.clf @@ -0,0 +1,25 @@ +fn test(int a, int a): string { + var b = undefined_var + 5; + int c = "string" + 10; + var c = 20; + return 42; +} + +fn test(): int { + return "duplicate function"; +} + +fn main() { + int x = missing_func(1, 2); + var y = test(5 + string z = x + "text"; + + for (var i = 0; undef_var < 10; ++i) { + int i = 0; + var result = i + "string"; + } + + if (another_missing { + x = y; + +} diff --git a/test/valgrind_case/full.clf b/test/valgrind_case/full.clf new file mode 100644 index 0000000..f8889b0 --- /dev/null +++ b/test/valgrind_case/full.clf @@ -0,0 +1,36 @@ +fn main(): int { + var a = bar(0); + int b = bar(0); + + string c = foo(); + + var d = a + b; + + for (var i = 0; i < a + 10; ++i) { + if (b == 0) { + d++; + } + } + + while (d > 0) { + d = d - b + 1; + } + + if (d == 0) { + d = 4; + } else { + d = 0; + } + + return 0; +} + + +fn foo(): string { + var b = "test"; + return b; +} + +fn bar(int a): int { + return a; +} diff --git a/test/valgrind_case/lexer_error.clf b/test/valgrind_case/lexer_error.clf new file mode 100644 index 0000000..184791d --- /dev/null +++ b/test/valgrind_case/lexer_error.clf @@ -0,0 +1,3 @@ +fn main() { + var a = @invalid; +} diff --git a/test/valgrind_case/parser_for_missing_increment.clf b/test/valgrind_case/parser_for_missing_increment.clf new file mode 100644 index 0000000..4b771aa --- /dev/null +++ b/test/valgrind_case/parser_for_missing_increment.clf @@ -0,0 +1,5 @@ +fn main() { + for (var i = 0; i < 10) { + i++; + } +} diff --git a/test/valgrind_case/parser_incomplete_function.clf b/test/valgrind_case/parser_incomplete_function.clf new file mode 100644 index 0000000..c12a976 --- /dev/null +++ b/test/valgrind_case/parser_incomplete_function.clf @@ -0,0 +1 @@ +fn main( diff --git a/test/valgrind_case/parser_missing_function_name.clf b/test/valgrind_case/parser_missing_function_name.clf new file mode 100644 index 0000000..75a916e --- /dev/null +++ b/test/valgrind_case/parser_missing_function_name.clf @@ -0,0 +1,3 @@ +fn { + return 0; +} diff --git a/test/valgrind_case/parser_missing_paren.clf b/test/valgrind_case/parser_missing_paren.clf new file mode 100644 index 0000000..4454218 --- /dev/null +++ b/test/valgrind_case/parser_missing_paren.clf @@ -0,0 +1,3 @@ +fn main() { + var a = (5 + 3; +} diff --git a/test/valgrind_case/parser_missing_semicolon.clf b/test/valgrind_case/parser_missing_semicolon.clf new file mode 100644 index 0000000..2ff69c5 --- /dev/null +++ b/test/valgrind_case/parser_missing_semicolon.clf @@ -0,0 +1,4 @@ +fn main() { + var a = 5 + var b = 10; +} diff --git a/test/valgrind_case/parser_missing_var_name.clf b/test/valgrind_case/parser_missing_var_name.clf new file mode 100644 index 0000000..d486f58 --- /dev/null +++ b/test/valgrind_case/parser_missing_var_name.clf @@ -0,0 +1,3 @@ +fn main() { + var = 5; +} diff --git a/test/valgrind_case/parser_unmatched_brace.clf b/test/valgrind_case/parser_unmatched_brace.clf new file mode 100644 index 0000000..c9015f5 --- /dev/null +++ b/test/valgrind_case/parser_unmatched_brace.clf @@ -0,0 +1,6 @@ +fn main() { + var a = 5; + if (a > 0) { + a = 10; + +} diff --git a/test/valgrind_case/semantic_control_flow_errors.clf b/test/valgrind_case/semantic_control_flow_errors.clf new file mode 100644 index 0000000..f874508 --- /dev/null +++ b/test/valgrind_case/semantic_control_flow_errors.clf @@ -0,0 +1,14 @@ +fn main() { + int a = 5; + for (var i = 0; undefined_cond < 10; ++i) { + a++; + } + + while (missing_var > 0) { + a--; + } + + if (another_undef) { + a = 0; + } +} diff --git a/test/valgrind_case/semantic_function_args_error.clf b/test/valgrind_case/semantic_function_args_error.clf new file mode 100644 index 0000000..e19c103 --- /dev/null +++ b/test/valgrind_case/semantic_function_args_error.clf @@ -0,0 +1,9 @@ +fn add(int a, int b): int { + return a + b; +} + +fn main() { + var x = add(5); + var y = add(1, 2, 3); + var z = add("test", 5); +} diff --git a/test/valgrind_case/semantic_function_duplicate.clf b/test/valgrind_case/semantic_function_duplicate.clf new file mode 100644 index 0000000..21fa962 --- /dev/null +++ b/test/valgrind_case/semantic_function_duplicate.clf @@ -0,0 +1,11 @@ +fn foo() { + return 0; +} + +fn foo() { + return 1; +} + +fn main() { + return 0; +} diff --git a/test/valgrind_case/semantic_function_reserved.clf b/test/valgrind_case/semantic_function_reserved.clf new file mode 100644 index 0000000..74b1563 --- /dev/null +++ b/test/valgrind_case/semantic_function_reserved.clf @@ -0,0 +1,3 @@ +fn var(): { + return 0; +} diff --git a/test/valgrind_case/semantic_return_type_error.clf b/test/valgrind_case/semantic_return_type_error.clf new file mode 100644 index 0000000..52de8ad --- /dev/null +++ b/test/valgrind_case/semantic_return_type_error.clf @@ -0,0 +1,7 @@ +fn test(): string { + return 42; +} + +fn main(): int { + return "not an int"; +} diff --git a/test/valgrind_case/semantic_type_mismatch.clf b/test/valgrind_case/semantic_type_mismatch.clf new file mode 100644 index 0000000..3248969 --- /dev/null +++ b/test/valgrind_case/semantic_type_mismatch.clf @@ -0,0 +1,6 @@ +fn main() { + int a = 5; + string b = "test"; + var c = a + b; + var d = b - 10; +} diff --git a/test/valgrind_case/semantic_unary_type_error.clf b/test/valgrind_case/semantic_unary_type_error.clf new file mode 100644 index 0000000..f39cd7f --- /dev/null +++ b/test/valgrind_case/semantic_unary_type_error.clf @@ -0,0 +1,6 @@ +fn main() { + var a = -"string"; + int b = !"test"; + string c = "hello"; + var d = ++c; +} diff --git a/test/valgrind_case/semantic_undefined_function.clf b/test/valgrind_case/semantic_undefined_function.clf new file mode 100644 index 0000000..e6f7c91 --- /dev/null +++ b/test/valgrind_case/semantic_undefined_function.clf @@ -0,0 +1,4 @@ +fn main() { + var result = undefined_function(); + another_missing(5, 10); +} diff --git a/test/valgrind_case/semantic_undefined_vars.clf b/test/valgrind_case/semantic_undefined_vars.clf new file mode 100644 index 0000000..070f8d3 --- /dev/null +++ b/test/valgrind_case/semantic_undefined_vars.clf @@ -0,0 +1,4 @@ +fn main() { + int a = undefined_var + 5; + var b = another_undef; +} diff --git a/test/valgrind_case/semantic_var_redefinition.clf b/test/valgrind_case/semantic_var_redefinition.clf new file mode 100644 index 0000000..5558358 --- /dev/null +++ b/test/valgrind_case/semantic_var_redefinition.clf @@ -0,0 +1,6 @@ +fn main() { + int a = 5; + int a = 10; + var b = 3; + string b = "test"; +}