diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..8b1e9cb --- /dev/null +++ b/.gitignore @@ -0,0 +1,7 @@ +*.md +.gitignore +*.swp +merge.py +/test_* +*.o +run_examples diff --git a/tests/test_7_8.c b/tests/test_7_8.c new file mode 100644 index 0000000..3741876 --- /dev/null +++ b/tests/test_7_8.c @@ -0,0 +1,84 @@ +#include "../lexer/lexer.h" +#include "../parser/parser.h" +#include "../semantic/semantic.h" +#include "../ir/ir.h" +#include "../ir/ir_gen.h" +#include "../runtime/runtime.h" +#include +#include +#include +#include + +static char* read_file(const char *filename) { + FILE *file = fopen(filename, "r"); + if (!file) return NULL; + fseek(file, 0, SEEK_END); + long size = ftell(file); + fseek(file, 0, SEEK_SET); + char *content = malloc(size + 1); + size_t read_bytes = fread(content, 1, size, file); (void)read_bytes; + content[size] = '\0'; + fclose(file); + return content; +} + +static bool run_example(const char *filename, const char *class_name) { + printf("\n========================================\n"); + printf("Running: %s\n", filename); + printf("========================================\n"); + + char *source = read_file(filename); + if (!source) return false; + + RavaLexer_t *lexer = rava_lexer_create(source); + RavaParser_t *parser = rava_parser_create(lexer); + RavaASTNode_t *ast = rava_parser_parse(parser); + + if (parser->had_error) { + free(source); + return false; + } + + RavaSemanticAnalyzer_t *analyzer = rava_semantic_analyzer_create(); + if (!rava_semantic_analyze(analyzer, ast)) { + free(source); + return false; + } + + RavaIRGenerator_t *ir_gen = rava_ir_generator_create(analyzer); + RavaProgram_t *program = rava_ir_generate(ir_gen, ast); + + if (!program) { + free(source); + return false; + } + + RavaVM_t *vm = rava_vm_create(program); + printf("\nOutput:\n"); + + if (!rava_vm_execute(vm, class_name, "main")) { + printf("\nRuntime error: %s\n", vm->error_message); + rava_vm_destroy(vm); + free(source); + return false; + } + + printf("\n✅ Execution completed successfully!\n"); + + rava_vm_destroy(vm); + rava_program_destroy(program); + rava_ir_generator_destroy(ir_gen); + rava_semantic_analyzer_destroy(analyzer); + rava_ast_node_destroy(ast); + rava_parser_destroy(parser); + rava_lexer_destroy(lexer); + free(source); + + return true; +} + +int main() { + run_example("examples/07_CollatzConjecture.java", "CollatzConjecture"); + run_example("examples/08_PascalTriangle.java", "PascalTriangle"); + return 0; +} diff --git a/tests/test_all_10.c b/tests/test_all_10.c new file mode 100644 index 0000000..3990526 --- /dev/null +++ b/tests/test_all_10.c @@ -0,0 +1,110 @@ +#include "../lexer/lexer.h" +#include "../parser/parser.h" +#include "../semantic/semantic.h" +#include "../ir/ir.h" +#include "../ir/ir_gen.h" +#include "../runtime/runtime.h" +#include +#include +#include +#include + +static char* read_file(const char *filename) { + FILE *file = fopen(filename, "r"); + if (!file) return NULL; + fseek(file, 0, SEEK_END); + long size = ftell(file); + fseek(file, 0, SEEK_SET); + char *content = malloc(size + 1); + size_t read_bytes = fread(content, 1, size, file); (void)read_bytes; + content[size] = '\0'; + fclose(file); + return content; +} + +static bool run_example(const char *filename, const char *class_name) { + printf("\n========================================\n"); + printf("Running: %s\n", filename); + printf("========================================\n"); + fflush(stdout); + + char *source = read_file(filename); + if (!source) return false; + + RavaLexer_t *lexer = rava_lexer_create(source); + RavaParser_t *parser = rava_parser_create(lexer); + RavaASTNode_t *ast = rava_parser_parse(parser); + + if (parser->had_error) { + free(source); + return false; + } + + RavaSemanticAnalyzer_t *analyzer = rava_semantic_analyzer_create(); + if (!rava_semantic_analyze(analyzer, ast)) { + free(source); + return false; + } + + RavaIRGenerator_t *ir_gen = rava_ir_generator_create(analyzer); + RavaProgram_t *program = rava_ir_generate(ir_gen, ast); + + if (!program) { + free(source); + return false; + } + + RavaVM_t *vm = rava_vm_create(program); + printf("\nOutput:\n"); + fflush(stdout); + + if (!rava_vm_execute(vm, class_name, "main")) { + printf("\nRuntime error: %s\n", vm->error_message); + rava_vm_destroy(vm); + free(source); + return false; + } + + printf("\n✅ Execution completed successfully!\n"); + fflush(stdout); + + rava_vm_destroy(vm); + rava_program_destroy(program); + rava_ir_generator_destroy(ir_gen); + rava_semantic_analyzer_destroy(analyzer); + rava_ast_node_destroy(ast); + rava_parser_destroy(parser); + rava_lexer_destroy(lexer); + free(source); + + return true; +} + +int main() { + const char *examples[][2] = { + {"examples/01_Fibonacci.java", "Fibonacci"}, + {"examples/02_PrimeNumbers.java", "PrimeNumbers"}, + {"examples/03_FactorialVariations.java", "FactorialVariations"}, + {"examples/04_GCD_LCM.java", "GCD_LCM"}, + {"examples/05_PowerFunction.java", "PowerFunction"}, + {"examples/06_BubbleSort.java", "BubbleSort"}, + {"examples/07_CollatzConjecture.java", "CollatzConjecture"}, + {"examples/08_PascalTriangle.java", "PascalTriangle"}, + {"examples/09_TowerOfHanoi.java", "TowerOfHanoi"}, + {"examples/10_AckermannFunction.java", "AckermannFunction"}, + }; + + int passed = 0; + for (size_t i = 0; i < 10; i++) { + printf("\n[%zu/10]\n", i+1); + fflush(stdout); + if (run_example(examples[i][0], examples[i][1])) { + passed++; + } + } + + printf("\n========================================\n"); + printf("SUMMARY: %d/10 passed\n", passed); + printf("========================================\n"); + return (passed == 10) ? 0 : 1; +} diff --git a/tests/test_array_init.c b/tests/test_array_init.c new file mode 100644 index 0000000..d1c6dd2 --- /dev/null +++ b/tests/test_array_init.c @@ -0,0 +1,125 @@ +#include "../lexer/lexer.h" +#include "../parser/parser.h" +#include "../semantic/semantic.h" +#include "../ir/ir.h" +#include "../ir/ir_gen.h" +#include "../runtime/runtime.h" +#include +#include +#include + +static int test_count = 0; +static int pass_count = 0; + +static void run_test_int(const char* name, const char* source, int expected) { + test_count++; + + RavaLexer_t* lexer = rava_lexer_create(source); + RavaParser_t* parser = rava_parser_create(lexer); + RavaASTNode_t* ast = rava_parser_parse(parser); + + if (!ast || parser->had_error) { + printf("FAIL: %s - Parse error: %s\n", name, parser->error_message ? parser->error_message : "unknown"); + rava_parser_destroy(parser); + rava_lexer_destroy(lexer); + return; + } + + RavaSemanticAnalyzer_t* analyzer = rava_semantic_analyzer_create(); + rava_semantic_analyze(analyzer, ast); + + RavaIRGenerator_t* ir_gen = rava_ir_generator_create(analyzer); + RavaProgram_t* program = rava_ir_generate(ir_gen, ast); + + RavaVM_t* vm = rava_vm_create(program); + + if (!rava_vm_execute(vm, "Test", "main")) { + printf("FAIL: %s - Runtime error: %s\n", name, vm->error_message ? vm->error_message : "unknown"); + rava_vm_destroy(vm); + rava_program_destroy(program); + rava_ir_generator_destroy(ir_gen); + rava_semantic_analyzer_destroy(analyzer); + rava_ast_node_destroy(ast); + rava_parser_destroy(parser); + rava_lexer_destroy(lexer); + return; + } + + RavaValue_t result = rava_vm_get_result(vm); + int32_t result_int = rava_value_as_int(result); + + if (result_int == expected) { + printf("PASS: %s (result=%d)\n", name, result_int); + pass_count++; + } else { + printf("FAIL: %s (expected=%d, got=%d)\n", name, expected, result_int); + } + + rava_vm_destroy(vm); + rava_program_destroy(program); + rava_ir_generator_destroy(ir_gen); + rava_semantic_analyzer_destroy(analyzer); + rava_ast_node_destroy(ast); + rava_parser_destroy(parser); + rava_lexer_destroy(lexer); +} + +int main(void) { + printf("=== Array Initializer Tests ===\n\n"); + + run_test_int("simple array init", + "public class Test {\n" + " public static int main() {\n" + " int[] arr = {1, 2, 3};\n" + " return arr[0] + arr[1] + arr[2];\n" + " }\n" + "}\n", 6); + + run_test_int("array init with expressions", + "public class Test {\n" + " public static int main() {\n" + " int[] arr = {1 + 1, 2 * 2, 3 + 3};\n" + " return arr[0] + arr[1] + arr[2];\n" + " }\n" + "}\n", 12); + + run_test_int("single element array", + "public class Test {\n" + " public static int main() {\n" + " int[] arr = {42};\n" + " return arr[0];\n" + " }\n" + "}\n", 42); + + run_test_int("array init length", + "public class Test {\n" + " public static int main() {\n" + " int[] arr = {5, 10, 15, 20};\n" + " int sum = 0;\n" + " for (int i = 0; i < 4; i = i + 1) {\n" + " sum = sum + arr[i];\n" + " }\n" + " return sum;\n" + " }\n" + "}\n", 50); + + run_test_int("array init with negative values", + "public class Test {\n" + " public static int main() {\n" + " int[] arr = {-1, -2, -3};\n" + " return arr[0] + arr[1] + arr[2];\n" + " }\n" + "}\n", -6); + + run_test_int("array init with zero", + "public class Test {\n" + " public static int main() {\n" + " int[] arr = {0, 0, 0};\n" + " return arr[0] + arr[1] + arr[2];\n" + " }\n" + "}\n", 0); + + printf("\n=== Results: %d/%d tests passed ===\n", pass_count, test_count); + + return (pass_count == test_count) ? 0 : 1; +} diff --git a/tests/test_array_init.o b/tests/test_array_init.o new file mode 100644 index 0000000..045101d Binary files /dev/null and b/tests/test_array_init.o differ diff --git a/tests/test_array_syntax.c b/tests/test_array_syntax.c new file mode 100644 index 0000000..c4de943 --- /dev/null +++ b/tests/test_array_syntax.c @@ -0,0 +1,30 @@ +#include "../lexer/lexer.h" +#include "../parser/parser.h" +#include +#include + +int main() { + const char *source = + "public class ArrayTest {\n" + " public static int main() {\n" + " int[] numbers = new int[5];\n" + " numbers[0] = 10;\n" + " numbers[1] = 20;\n" + " int result = numbers[0] + numbers[1];\n" + " System.out.println(result);\n" + " return 0;\n" + " }\n" + "}\n"; + + RavaLexer_t *lexer = rava_lexer_create(source); + RavaParser_t *parser = rava_parser_create(lexer); + rava_parser_parse(parser); + + if (parser->had_error) { + printf("Parse error: %s\n", parser->error_message); + return 1; + } + + printf("Parsed successfully!\n"); + return 0; +} diff --git a/tests/test_arrays.c b/tests/test_arrays.c new file mode 100644 index 0000000..2373f26 --- /dev/null +++ b/tests/test_arrays.c @@ -0,0 +1,77 @@ +#include "../lexer/lexer.h" +#include "../parser/parser.h" +#include "../semantic/semantic.h" +#include "../ir/ir.h" +#include "../ir/ir_gen.h" +#include "../runtime/runtime.h" +#include +#include +#include + +static char* read_file(const char *filename) { + FILE *file = fopen(filename, "r"); + if (!file) return NULL; + fseek(file, 0, SEEK_END); + long size = ftell(file); + fseek(file, 0, SEEK_SET); + char *content = malloc(size + 1); + size_t read_bytes = fread(content, 1, size, file); (void)read_bytes; + content[size] = '\0'; + fclose(file); + return content; +} + +int main() { + char *source = read_file("examples/11_ArrayOperations.java"); + if (!source) { + printf("Failed to read file\n"); + return 1; + } + + RavaLexer_t *lexer = rava_lexer_create(source); + RavaParser_t *parser = rava_parser_create(lexer); + RavaASTNode_t *ast = rava_parser_parse(parser); + + if (parser->had_error) { + printf("Parse error: %s\n", parser->error_message); + free(source); + return 1; + } + + printf("Parse: OK\n"); + + RavaSemanticAnalyzer_t *analyzer = rava_semantic_analyzer_create(); + if (!rava_semantic_analyze(analyzer, ast)) { + printf("Semantic error: %s\n", analyzer->error_message); + free(source); + return 1; + } + + printf("Semantic: OK\n"); + + RavaIRGenerator_t *ir_gen = rava_ir_generator_create(analyzer); + RavaProgram_t *program = rava_ir_generate(ir_gen, ast); + + if (!program) { + printf("IR generation failed\n"); + free(source); + return 1; + } + + printf("IR Gen: OK\n"); + printf("\nOutput:\n"); + + RavaVM_t *vm = rava_vm_create(program); + if (!rava_vm_execute(vm, "ArrayOperations", "main")) { + printf("Runtime error: %s\n", vm->error_message); + rava_vm_destroy(vm); + free(source); + return 1; + } + + printf("\nExecution: OK\n"); + + rava_vm_destroy(vm); + free(source); + return 0; +} diff --git a/tests/test_arrays.o b/tests/test_arrays.o new file mode 100644 index 0000000..adf7611 Binary files /dev/null and b/tests/test_arrays.o differ diff --git a/tests/test_benchmark.c b/tests/test_benchmark.c new file mode 100644 index 0000000..9980149 --- /dev/null +++ b/tests/test_benchmark.c @@ -0,0 +1,64 @@ +#include "../lexer/lexer.h" +#include "../parser/parser.h" +#include "../semantic/semantic.h" +#include "../ir/ir.h" +#include "../ir/ir_gen.h" +#include "../runtime/runtime.h" +#include +#include + +static char* read_file(const char *filename) { + FILE *file = fopen(filename, "r"); + if (!file) return NULL; + fseek(file, 0, SEEK_END); + long size = ftell(file); + fseek(file, 0, SEEK_SET); + char *content = malloc(size + 1); + size_t read_bytes = fread(content, 1, size, file); (void)read_bytes; + content[size] = '\0'; + fclose(file); + return content; +} + +int main() { + char *source = read_file("examples/20_Benchmark.java"); + if (!source) { printf("Failed to read file\n"); return 1; } + + RavaLexer_t *lexer = rava_lexer_create(source); + RavaParser_t *parser = rava_parser_create(lexer); + RavaASTNode_t *ast = rava_parser_parse(parser); + + if (parser->had_error) { + printf("Parse error: %s\n", parser->error_message); + free(source); + return 1; + } + + RavaSemanticAnalyzer_t *analyzer = rava_semantic_analyzer_create(); + if (!rava_semantic_analyze(analyzer, ast)) { + printf("Semantic error: %s\n", analyzer->error_message); + free(source); + return 1; + } + + RavaIRGenerator_t *ir_gen = rava_ir_generator_create(analyzer); + RavaProgram_t *program = rava_ir_generate(ir_gen, ast); + + if (!program) { + printf("IR generation failed\n"); + free(source); + return 1; + } + + RavaVM_t *vm = rava_vm_create(program); + if (!rava_vm_execute(vm, "Benchmark", "main")) { + printf("Runtime error: %s\n", vm->error_message); + rava_vm_destroy(vm); + free(source); + return 1; + } + + rava_vm_destroy(vm); + free(source); + return 0; +} diff --git a/tests/test_bitwise.c b/tests/test_bitwise.c new file mode 100644 index 0000000..5209db7 --- /dev/null +++ b/tests/test_bitwise.c @@ -0,0 +1,214 @@ +#include "../lexer/lexer.h" +#include "../parser/parser.h" +#include "../semantic/semantic.h" +#include "../ir/ir.h" +#include "../ir/ir_gen.h" +#include "../runtime/runtime.h" +#include +#include +#include + +static int test_count = 0; +static int pass_count = 0; + +static void run_test_int(const char* name, const char* source, int expected) { + test_count++; + + RavaLexer_t* lexer = rava_lexer_create(source); + RavaParser_t* parser = rava_parser_create(lexer); + RavaASTNode_t* ast = rava_parser_parse(parser); + + if (!ast || parser->had_error) { + printf("FAIL: %s - Parse error: %s\n", name, parser->error_message ? parser->error_message : "unknown"); + rava_parser_destroy(parser); + rava_lexer_destroy(lexer); + return; + } + + RavaSemanticAnalyzer_t* analyzer = rava_semantic_analyzer_create(); + rava_semantic_analyze(analyzer, ast); + + RavaIRGenerator_t* ir_gen = rava_ir_generator_create(analyzer); + RavaProgram_t* program = rava_ir_generate(ir_gen, ast); + + RavaVM_t* vm = rava_vm_create(program); + + if (!rava_vm_execute(vm, "Test", "main")) { + printf("FAIL: %s - Runtime error: %s\n", name, vm->error_message ? vm->error_message : "unknown"); + rava_vm_destroy(vm); + rava_program_destroy(program); + rava_ir_generator_destroy(ir_gen); + rava_semantic_analyzer_destroy(analyzer); + rava_ast_node_destroy(ast); + rava_parser_destroy(parser); + rava_lexer_destroy(lexer); + return; + } + + RavaValue_t result = rava_vm_get_result(vm); + int32_t result_int = rava_value_as_int(result); + + if (result_int == expected) { + printf("PASS: %s (result=%d)\n", name, result_int); + pass_count++; + } else { + printf("FAIL: %s (expected=%d, got=%d)\n", name, expected, result_int); + } + + rava_vm_destroy(vm); + rava_program_destroy(program); + rava_ir_generator_destroy(ir_gen); + rava_semantic_analyzer_destroy(analyzer); + rava_ast_node_destroy(ast); + rava_parser_destroy(parser); + rava_lexer_destroy(lexer); +} + +int main(void) { + printf("=== Bitwise Operator Tests ===\n\n"); + + run_test_int("bitwise AND with vars", + "public class Test {\n" + " public static int main() {\n" + " int a = 12;\n" + " int b = 10;\n" + " return a & b;\n" + " }\n" + "}\n", 8); + + run_test_int("bitwise OR with vars", + "public class Test {\n" + " public static int main() {\n" + " int a = 12;\n" + " int b = 10;\n" + " return a | b;\n" + " }\n" + "}\n", 14); + + run_test_int("bitwise XOR", + "public class Test {\n" + " public static int main() {\n" + " return 12 ^ 10;\n" + " }\n" + "}\n", 6); + + run_test_int("left shift", + "public class Test {\n" + " public static int main() {\n" + " return 1 << 4;\n" + " }\n" + "}\n", 16); + + run_test_int("right shift", + "public class Test {\n" + " public static int main() {\n" + " return 16 >> 2;\n" + " }\n" + "}\n", 4); + + run_test_int("unsigned right shift", + "public class Test {\n" + " public static int main() {\n" + " return 16 >>> 2;\n" + " }\n" + "}\n", 4); + + run_test_int("combined bitwise ops", + "public class Test {\n" + " public static int main() {\n" + " int a = 5;\n" + " int b = 3;\n" + " return (a & b) | (a ^ b);\n" + " }\n" + "}\n", 7); + + run_test_int("shift with variable", + "public class Test {\n" + " public static int main() {\n" + " int x = 2;\n" + " return 1 << x;\n" + " }\n" + "}\n", 4); + + run_test_int("bitwise mask", + "public class Test {\n" + " public static int main() {\n" + " int value = 255;\n" + " int mask = 0x0F;\n" + " return value & mask;\n" + " }\n" + "}\n", 15); + + run_test_int("bit toggle with XOR", + "public class Test {\n" + " public static int main() {\n" + " int flags = 5;\n" + " return flags ^ 1;\n" + " }\n" + "}\n", 4); + + run_test_int("bitwise NOT", + "public class Test {\n" + " public static int main() {\n" + " int x = 0;\n" + " return ~x;\n" + " }\n" + "}\n", -1); + + run_test_int("bitwise NOT with value", + "public class Test {\n" + " public static int main() {\n" + " int x = 5;\n" + " return ~x;\n" + " }\n" + "}\n", -6); + + run_test_int("compound AND assign", + "public class Test {\n" + " public static int main() {\n" + " int x = 15;\n" + " x &= 7;\n" + " return x;\n" + " }\n" + "}\n", 7); + + run_test_int("compound OR assign", + "public class Test {\n" + " public static int main() {\n" + " int x = 8;\n" + " x |= 3;\n" + " return x;\n" + " }\n" + "}\n", 11); + + run_test_int("compound XOR assign", + "public class Test {\n" + " public static int main() {\n" + " int x = 12;\n" + " x ^= 5;\n" + " return x;\n" + " }\n" + "}\n", 9); + + run_test_int("compound left shift assign", + "public class Test {\n" + " public static int main() {\n" + " int x = 1;\n" + " x <<= 3;\n" + " return x;\n" + " }\n" + "}\n", 8); + + run_test_int("compound right shift assign", + "public class Test {\n" + " public static int main() {\n" + " int x = 16;\n" + " x >>= 2;\n" + " return x;\n" + " }\n" + "}\n", 4); + + printf("\n=== Results: %d/%d tests passed ===\n", pass_count, test_count); + + return (pass_count == test_count) ? 0 : 1; +} diff --git a/tests/test_bitwise.o b/tests/test_bitwise.o new file mode 100644 index 0000000..455df87 Binary files /dev/null and b/tests/test_bitwise.o differ diff --git a/tests/test_break.c b/tests/test_break.c new file mode 100644 index 0000000..ca783b0 --- /dev/null +++ b/tests/test_break.c @@ -0,0 +1,42 @@ +#include "../lexer/lexer.h" +#include "../parser/parser.h" +#include "../semantic/semantic.h" +#include "../ir/ir.h" +#include "../ir/ir_gen.h" +#include "../runtime/runtime.h" +#include +#include + +static char* read_file(const char *filename) { + FILE *file = fopen(filename, "r"); + if (!file) return NULL; + fseek(file, 0, SEEK_END); + long size = ftell(file); + fseek(file, 0, SEEK_SET); + char *content = malloc(size + 1); + size_t read_bytes = fread(content, 1, size, file); (void)read_bytes; + content[size] = '\0'; + fclose(file); + return content; +} + +int main() { + char *source = read_file("examples/19_BreakContinue.java"); + if (!source) { printf("Failed\n"); return 1; } + RavaLexer_t *l = rava_lexer_create(source); + RavaParser_t *p = rava_parser_create(l); + RavaASTNode_t *ast = rava_parser_parse(p); + if (p->had_error) { printf("Parse: %s\n", p->error_message); return 1; } + printf("Parse: OK\n"); + RavaSemanticAnalyzer_t *a = rava_semantic_analyzer_create(); + if (!rava_semantic_analyze(a, ast)) { printf("Semantic: %s\n", a->error_message); return 1; } + printf("Semantic: OK\n"); + RavaIRGenerator_t *g = rava_ir_generator_create(a); + RavaProgram_t *prog = rava_ir_generate(g, ast); + if (!prog) { printf("IR failed\n"); return 1; } + printf("IR: OK\nOutput:\n"); + RavaVM_t *vm = rava_vm_create(prog); + if (!rava_vm_execute(vm, "BreakContinue", "main")) { printf("Runtime: %s\n", vm->error_message); return 1; } + printf("\nExecution: OK\n"); + return 0; +} diff --git a/tests/test_collections.c b/tests/test_collections.c new file mode 100644 index 0000000..3a91558 --- /dev/null +++ b/tests/test_collections.c @@ -0,0 +1,278 @@ +#include "../lexer/lexer.h" +#include "../parser/parser.h" +#include "../semantic/semantic.h" +#include "../ir/ir.h" +#include "../ir/ir_gen.h" +#include "../runtime/runtime.h" +#include +#include +#include + +static int test_count = 0; +static int pass_count = 0; + +static int run_test(const char *name, const char *source, int expected) { + test_count++; + + RavaLexer_t *lexer = rava_lexer_create(source); + RavaParser_t *parser = rava_parser_create(lexer); + RavaASTNode_t *ast = rava_parser_parse(parser); + + if (parser->had_error) { + printf("FAIL: %s (parse error)\n", name); + rava_parser_destroy(parser); + rava_lexer_destroy(lexer); + return 0; + } + + RavaSemanticAnalyzer_t *analyzer = rava_semantic_analyzer_create(); + if (!rava_semantic_analyze(analyzer, ast)) { + printf("FAIL: %s (semantic error)\n", name); + rava_semantic_analyzer_destroy(analyzer); + rava_ast_node_destroy(ast); + rava_parser_destroy(parser); + rava_lexer_destroy(lexer); + return 0; + } + + RavaIRGenerator_t *ir_gen = rava_ir_generator_create(analyzer); + RavaProgram_t *program = rava_ir_generate(ir_gen, ast); + + if (!program) { + printf("FAIL: %s (IR error)\n", name); + rava_ir_generator_destroy(ir_gen); + rava_semantic_analyzer_destroy(analyzer); + rava_ast_node_destroy(ast); + rava_parser_destroy(parser); + rava_lexer_destroy(lexer); + return 0; + } + + RavaVM_t *vm = rava_vm_create(program); + + if (!rava_vm_execute(vm, "Test", "main")) { + printf("FAIL: %s (runtime error)\n", name); + rava_vm_destroy(vm); + rava_program_destroy(program); + rava_ir_generator_destroy(ir_gen); + rava_semantic_analyzer_destroy(analyzer); + rava_ast_node_destroy(ast); + rava_parser_destroy(parser); + rava_lexer_destroy(lexer); + return 0; + } + + RavaValue_t result = rava_vm_get_result(vm); + int actual = rava_value_as_int(result); + + rava_vm_destroy(vm); + rava_program_destroy(program); + rava_ir_generator_destroy(ir_gen); + rava_semantic_analyzer_destroy(analyzer); + rava_ast_node_destroy(ast); + rava_parser_destroy(parser); + rava_lexer_destroy(lexer); + + if (actual == expected) { + printf("PASS: %s\n", name); + pass_count++; + return 1; + } else { + printf("FAIL: %s (expected %d, got %d)\n", name, expected, actual); + return 0; + } +} + +int main(void) { + printf("=== ArrayList Tests ===\n"); + + run_test("ArrayList create and size", + "public class Test {\n" + " public static int main() {\n" + " ArrayList list = new ArrayList();\n" + " return list.size();\n" + " }\n" + "}\n", 0); + + run_test("ArrayList add and size", + "public class Test {\n" + " public static int main() {\n" + " ArrayList list = new ArrayList();\n" + " list.add(10);\n" + " list.add(20);\n" + " list.add(30);\n" + " return list.size();\n" + " }\n" + "}\n", 3); + + run_test("ArrayList add and get", + "public class Test {\n" + " public static int main() {\n" + " ArrayList list = new ArrayList();\n" + " list.add(42);\n" + " return list.get(0);\n" + " }\n" + "}\n", 42); + + run_test("ArrayList set", + "public class Test {\n" + " public static int main() {\n" + " ArrayList list = new ArrayList();\n" + " list.add(10);\n" + " list.set(0, 99);\n" + " return list.get(0);\n" + " }\n" + "}\n", 99); + + run_test("ArrayList isEmpty true", + "public class Test {\n" + " public static int main() {\n" + " ArrayList list = new ArrayList();\n" + " if (list.isEmpty()) {\n" + " return 1;\n" + " }\n" + " return 0;\n" + " }\n" + "}\n", 1); + + run_test("ArrayList isEmpty false", + "public class Test {\n" + " public static int main() {\n" + " ArrayList list = new ArrayList();\n" + " list.add(1);\n" + " if (list.isEmpty()) {\n" + " return 1;\n" + " }\n" + " return 0;\n" + " }\n" + "}\n", 0); + + run_test("ArrayList clear", + "public class Test {\n" + " public static int main() {\n" + " ArrayList list = new ArrayList();\n" + " list.add(1);\n" + " list.add(2);\n" + " list.clear();\n" + " return list.size();\n" + " }\n" + "}\n", 0); + + run_test("ArrayList remove", + "public class Test {\n" + " public static int main() {\n" + " ArrayList list = new ArrayList();\n" + " list.add(10);\n" + " list.add(20);\n" + " list.add(30);\n" + " int removed = list.remove(1);\n" + " return removed;\n" + " }\n" + "}\n", 20); + + run_test("ArrayList sum elements", + "public class Test {\n" + " public static int main() {\n" + " ArrayList list = new ArrayList();\n" + " list.add(1);\n" + " list.add(2);\n" + " list.add(3);\n" + " list.add(4);\n" + " int sum = 0;\n" + " for (int i = 0; i < list.size(); i = i + 1) {\n" + " sum = sum + list.get(i);\n" + " }\n" + " return sum;\n" + " }\n" + "}\n", 10); + + printf("\n=== HashMap Tests ===\n"); + + run_test("HashMap create and size", + "public class Test {\n" + " public static int main() {\n" + " HashMap map = new HashMap();\n" + " return map.size();\n" + " }\n" + "}\n", 0); + + run_test("HashMap put and size", + "public class Test {\n" + " public static int main() {\n" + " HashMap map = new HashMap();\n" + " map.put(\"a\", 1);\n" + " map.put(\"b\", 2);\n" + " return map.size();\n" + " }\n" + "}\n", 2); + + run_test("HashMap put and get", + "public class Test {\n" + " public static int main() {\n" + " HashMap map = new HashMap();\n" + " map.put(\"key\", 42);\n" + " return map.get(\"key\");\n" + " }\n" + "}\n", 42); + + run_test("HashMap containsKey true", + "public class Test {\n" + " public static int main() {\n" + " HashMap map = new HashMap();\n" + " map.put(\"test\", 99);\n" + " if (map.containsKey(\"test\")) {\n" + " return 1;\n" + " }\n" + " return 0;\n" + " }\n" + "}\n", 1); + + run_test("HashMap containsKey false", + "public class Test {\n" + " public static int main() {\n" + " HashMap map = new HashMap();\n" + " map.put(\"test\", 99);\n" + " if (map.containsKey(\"other\")) {\n" + " return 1;\n" + " }\n" + " return 0;\n" + " }\n" + "}\n", 0); + + run_test("HashMap remove", + "public class Test {\n" + " public static int main() {\n" + " HashMap map = new HashMap();\n" + " map.put(\"a\", 10);\n" + " map.put(\"b\", 20);\n" + " int removed = map.remove(\"a\");\n" + " return removed + map.size();\n" + " }\n" + "}\n", 11); + + run_test("HashMap clear", + "public class Test {\n" + " public static int main() {\n" + " HashMap map = new HashMap();\n" + " map.put(\"x\", 1);\n" + " map.put(\"y\", 2);\n" + " map.clear();\n" + " return map.size();\n" + " }\n" + "}\n", 0); + + run_test("HashMap update value", + "public class Test {\n" + " public static int main() {\n" + " HashMap map = new HashMap();\n" + " map.put(\"key\", 10);\n" + " map.put(\"key\", 20);\n" + " return map.get(\"key\");\n" + " }\n" + "}\n", 20); + + printf("\n=== Results ===\n"); + printf("Passed: %d/%d\n", pass_count, test_count); + + return (pass_count == test_count) ? 0 : 1; +} diff --git a/tests/test_collections.o b/tests/test_collections.o new file mode 100644 index 0000000..94f0d92 Binary files /dev/null and b/tests/test_collections.o differ diff --git a/tests/test_dowhile.c b/tests/test_dowhile.c new file mode 100644 index 0000000..b0d198c --- /dev/null +++ b/tests/test_dowhile.c @@ -0,0 +1,139 @@ +#include "../lexer/lexer.h" +#include "../parser/parser.h" +#include "../semantic/semantic.h" +#include "../ir/ir.h" +#include "../ir/ir_gen.h" +#include "../runtime/runtime.h" +#include +#include +#include + +static int test_count = 0; +static int pass_count = 0; + +static void run_test(const char* name, const char* source, int expected) { + test_count++; + + RavaLexer_t* lexer = rava_lexer_create(source); + RavaParser_t* parser = rava_parser_create(lexer); + RavaASTNode_t* ast = rava_parser_parse(parser); + + if (!ast || parser->had_error) { + printf("FAIL: %s - Parse error\n", name); + rava_parser_destroy(parser); + rava_lexer_destroy(lexer); + return; + } + + RavaSemanticAnalyzer_t* analyzer = rava_semantic_analyzer_create(); + rava_semantic_analyze(analyzer, ast); + + RavaIRGenerator_t* ir_gen = rava_ir_generator_create(analyzer); + RavaProgram_t* program = rava_ir_generate(ir_gen, ast); + + RavaVM_t* vm = rava_vm_create(program); + + if (!rava_vm_execute(vm, "Test", "main")) { + printf("FAIL: %s - Runtime error\n", name); + rava_vm_destroy(vm); + rava_program_destroy(program); + rava_ir_generator_destroy(ir_gen); + rava_semantic_analyzer_destroy(analyzer); + rava_ast_node_destroy(ast); + rava_parser_destroy(parser); + rava_lexer_destroy(lexer); + return; + } + + RavaValue_t result = rava_vm_get_result(vm); + int32_t result_int = rava_value_as_int(result); + + if (result_int == expected) { + printf("PASS: %s (result=%d)\n", name, result_int); + pass_count++; + } else { + printf("FAIL: %s (expected=%d, got=%d)\n", name, expected, result_int); + } + + rava_vm_destroy(vm); + rava_program_destroy(program); + rava_ir_generator_destroy(ir_gen); + rava_semantic_analyzer_destroy(analyzer); + rava_ast_node_destroy(ast); + rava_parser_destroy(parser); + rava_lexer_destroy(lexer); +} + +int main(void) { + printf("=== Do-While Loop Tests ===\n\n"); + + run_test("Simple do-while", + "public class Test {\n" + " public static int main() {\n" + " int i = 0;\n" + " do {\n" + " i = i + 1;\n" + " } while (i < 5);\n" + " return i;\n" + " }\n" + "}\n", 5); + + run_test("Do-while sum", + "public class Test {\n" + " public static int main() {\n" + " int sum = 0;\n" + " int i = 1;\n" + " do {\n" + " sum = sum + i;\n" + " i = i + 1;\n" + " } while (i <= 10);\n" + " return sum;\n" + " }\n" + "}\n", 55); + + run_test("Do-while executes at least once", + "public class Test {\n" + " public static int main() {\n" + " int x = 0;\n" + " do {\n" + " x = 42;\n" + " } while (false);\n" + " return x;\n" + " }\n" + "}\n", 42); + + run_test("Do-while with break", + "public class Test {\n" + " public static int main() {\n" + " int i = 0;\n" + " do {\n" + " i = i + 1;\n" + " if (i == 3) {\n" + " break;\n" + " }\n" + " } while (i < 10);\n" + " return i;\n" + " }\n" + "}\n", 3); + + run_test("Nested do-while", + "public class Test {\n" + " public static int main() {\n" + " int count = 0;\n" + " int i = 0;\n" + " do {\n" + " int j = 0;\n" + " do {\n" + " count = count + 1;\n" + " j = j + 1;\n" + " } while (j < 3);\n" + " i = i + 1;\n" + " } while (i < 2);\n" + " return count;\n" + " }\n" + "}\n", 6); + + printf("\n=== Results: %d/%d tests passed ===\n", pass_count, test_count); + + return (pass_count == test_count) ? 0 : 1; +} diff --git a/tests/test_dowhile.o b/tests/test_dowhile.o new file mode 100644 index 0000000..3da4708 Binary files /dev/null and b/tests/test_dowhile.o differ diff --git a/tests/test_elseif.c b/tests/test_elseif.c new file mode 100644 index 0000000..72e7706 --- /dev/null +++ b/tests/test_elseif.c @@ -0,0 +1,77 @@ +#include "../lexer/lexer.h" +#include "../parser/parser.h" +#include "../semantic/semantic.h" +#include "../ir/ir.h" +#include "../ir/ir_gen.h" +#include "../runtime/runtime.h" +#include +#include +#include + +static char* read_file(const char *filename) { + FILE *file = fopen(filename, "r"); + if (!file) return NULL; + fseek(file, 0, SEEK_END); + long size = ftell(file); + fseek(file, 0, SEEK_SET); + char *content = malloc(size + 1); + size_t read_bytes = fread(content, 1, size, file); (void)read_bytes; + content[size] = '\0'; + fclose(file); + return content; +} + +int main() { + char *source = read_file("examples/18_ElseIf.java"); + if (!source) { + printf("Failed to read file\n"); + return 1; + } + + RavaLexer_t *lexer = rava_lexer_create(source); + RavaParser_t *parser = rava_parser_create(lexer); + RavaASTNode_t *ast = rava_parser_parse(parser); + + if (parser->had_error) { + printf("Parse error: %s\n", parser->error_message); + free(source); + return 1; + } + + printf("Parse: OK\n"); + + RavaSemanticAnalyzer_t *analyzer = rava_semantic_analyzer_create(); + if (!rava_semantic_analyze(analyzer, ast)) { + printf("Semantic error: %s\n", analyzer->error_message); + free(source); + return 1; + } + + printf("Semantic: OK\n"); + + RavaIRGenerator_t *ir_gen = rava_ir_generator_create(analyzer); + RavaProgram_t *program = rava_ir_generate(ir_gen, ast); + + if (!program) { + printf("IR generation failed\n"); + free(source); + return 1; + } + + printf("IR Gen: OK\n"); + printf("\nOutput:\n"); + + RavaVM_t *vm = rava_vm_create(program); + if (!rava_vm_execute(vm, "ElseIf", "main")) { + printf("Runtime error: %s\n", vm->error_message); + rava_vm_destroy(vm); + free(source); + return 1; + } + + printf("\nExecution: OK\n"); + + rava_vm_destroy(vm); + free(source); + return 0; +} diff --git a/tests/test_enhanced_for.c b/tests/test_enhanced_for.c new file mode 100644 index 0000000..33b9a51 --- /dev/null +++ b/tests/test_enhanced_for.c @@ -0,0 +1,130 @@ +#include "../lexer/lexer.h" +#include "../parser/parser.h" +#include "../semantic/semantic.h" +#include "../ir/ir.h" +#include "../ir/ir_gen.h" +#include "../runtime/runtime.h" +#include +#include +#include + +static int test_count = 0; +static int pass_count = 0; + +static void run_test_int(const char* name, const char* source, int expected) { + test_count++; + + RavaLexer_t* lexer = rava_lexer_create(source); + RavaParser_t* parser = rava_parser_create(lexer); + RavaASTNode_t* ast = rava_parser_parse(parser); + + if (!ast || parser->had_error) { + printf("FAIL: %s - Parse error: %s\n", name, parser->error_message ? parser->error_message : "unknown"); + rava_parser_destroy(parser); + rava_lexer_destroy(lexer); + return; + } + + RavaSemanticAnalyzer_t* analyzer = rava_semantic_analyzer_create(); + rava_semantic_analyze(analyzer, ast); + + RavaIRGenerator_t* ir_gen = rava_ir_generator_create(analyzer); + RavaProgram_t* program = rava_ir_generate(ir_gen, ast); + + RavaVM_t* vm = rava_vm_create(program); + + if (!rava_vm_execute(vm, "Test", "main")) { + printf("FAIL: %s - Runtime error: %s\n", name, vm->error_message ? vm->error_message : "unknown"); + rava_vm_destroy(vm); + rava_program_destroy(program); + rava_ir_generator_destroy(ir_gen); + rava_semantic_analyzer_destroy(analyzer); + rava_ast_node_destroy(ast); + rava_parser_destroy(parser); + rava_lexer_destroy(lexer); + return; + } + + RavaValue_t result = rava_vm_get_result(vm); + int32_t result_int = rava_value_as_int(result); + + if (result_int == expected) { + printf("PASS: %s (result=%d)\n", name, result_int); + pass_count++; + } else { + printf("FAIL: %s (expected=%d, got=%d)\n", name, expected, result_int); + } + + rava_vm_destroy(vm); + rava_program_destroy(program); + rava_ir_generator_destroy(ir_gen); + rava_semantic_analyzer_destroy(analyzer); + rava_ast_node_destroy(ast); + rava_parser_destroy(parser); + rava_lexer_destroy(lexer); +} + +int main(void) { + printf("=== Enhanced For Loop Tests ===\n\n"); + + run_test_int("sum array elements", + "public class Test {\n" + " public static int main() {\n" + " int[] arr = new int[3];\n" + " arr[0] = 1;\n" + " arr[1] = 2;\n" + " arr[2] = 3;\n" + " int sum = 0;\n" + " for (int x : arr) {\n" + " sum = sum + x;\n" + " }\n" + " return sum;\n" + " }\n" + "}\n", 6); + + run_test_int("count elements", + "public class Test {\n" + " public static int main() {\n" + " int[] arr = new int[5];\n" + " int count = 0;\n" + " for (int x : arr) {\n" + " count = count + 1;\n" + " }\n" + " return count;\n" + " }\n" + "}\n", 5); + + run_test_int("find max", + "public class Test {\n" + " public static int main() {\n" + " int[] arr = new int[4];\n" + " arr[0] = 5;\n" + " arr[1] = 9;\n" + " arr[2] = 3;\n" + " arr[3] = 7;\n" + " int max = 0;\n" + " for (int x : arr) {\n" + " if (x > max) {\n" + " max = x;\n" + " }\n" + " }\n" + " return max;\n" + " }\n" + "}\n", 9); + + run_test_int("empty array", + "public class Test {\n" + " public static int main() {\n" + " int[] arr = new int[0];\n" + " int sum = 0;\n" + " for (int x : arr) {\n" + " sum = sum + 1;\n" + " }\n" + " return sum;\n" + " }\n" + "}\n", 0); + + printf("\n=== Results: %d/%d tests passed ===\n", pass_count, test_count); + + return (pass_count == test_count) ? 0 : 1; +} diff --git a/tests/test_enhanced_for.o b/tests/test_enhanced_for.o new file mode 100644 index 0000000..5ec7fa5 Binary files /dev/null and b/tests/test_enhanced_for.o differ diff --git a/tests/test_enums.c b/tests/test_enums.c new file mode 100644 index 0000000..1e38fbb --- /dev/null +++ b/tests/test_enums.c @@ -0,0 +1,152 @@ +#include "../lexer/lexer.h" +#include "../parser/parser.h" +#include "../semantic/semantic.h" +#include "../ir/ir.h" +#include "../ir/ir_gen.h" +#include "../runtime/runtime.h" +#include +#include + +static int run_test(const char *name, const char *source, const char *class_name, + const char *method_name, int expected) { + printf("Test: %-40s ... ", name); + fflush(stdout); + + RavaLexer_t *lexer = rava_lexer_create(source); + RavaParser_t *parser = rava_parser_create(lexer); + RavaASTNode_t *ast = rava_parser_parse(parser); + + if (parser->had_error) { + printf("FAIL (parse error: %s)\n", parser->error_message); + rava_parser_destroy(parser); + rava_lexer_destroy(lexer); + return 0; + } + + RavaSemanticAnalyzer_t *analyzer = rava_semantic_analyzer_create(); + if (!rava_semantic_analyze(analyzer, ast)) { + printf("FAIL (semantic error: %s)\n", analyzer->error_message); + rava_semantic_analyzer_destroy(analyzer); + rava_ast_node_destroy(ast); + rava_parser_destroy(parser); + rava_lexer_destroy(lexer); + return 0; + } + + RavaIRGenerator_t *ir_gen = rava_ir_generator_create(analyzer); + RavaProgram_t *program = rava_ir_generate(ir_gen, ast); + + if (!program) { + printf("FAIL (IR generation failed)\n"); + rava_ir_generator_destroy(ir_gen); + rava_semantic_analyzer_destroy(analyzer); + rava_ast_node_destroy(ast); + rava_parser_destroy(parser); + rava_lexer_destroy(lexer); + return 0; + } + + RavaVM_t *vm = rava_vm_create(program); + + if (!rava_vm_execute(vm, class_name, method_name)) { + printf("FAIL (runtime error: %s)\n", vm->error_message ? vm->error_message : "unknown"); + rava_vm_destroy(vm); + rava_program_destroy(program); + rava_ir_generator_destroy(ir_gen); + rava_semantic_analyzer_destroy(analyzer); + rava_ast_node_destroy(ast); + rava_parser_destroy(parser); + rava_lexer_destroy(lexer); + return 0; + } + + RavaValue_t result = rava_vm_get_result(vm); + int result_int = rava_value_as_int(result); + + rava_vm_destroy(vm); + rava_program_destroy(program); + rava_ir_generator_destroy(ir_gen); + rava_semantic_analyzer_destroy(analyzer); + rava_ast_node_destroy(ast); + rava_parser_destroy(parser); + rava_lexer_destroy(lexer); + + if (result_int == expected) { + printf("PASS (result=%d)\n", result_int); + return 1; + } else { + printf("FAIL (expected=%d, got=%d)\n", expected, result_int); + return 0; + } +} + +int main(void) { + printf("=== Enum Tests ===\n\n"); + + int passed = 0; + int total = 0; + + total++; + passed += run_test("simple enum ordinal", + "public enum Color { RED, GREEN, BLUE }\n" + "public class Test {\n" + " public static int main() {\n" + " return Color.RED;\n" + " }\n" + "}\n", + "Test", "main", 0); + + total++; + passed += run_test("enum second value", + "public enum Color { RED, GREEN, BLUE }\n" + "public class Test {\n" + " public static int main() {\n" + " return Color.GREEN;\n" + " }\n" + "}\n", + "Test", "main", 1); + + total++; + passed += run_test("enum third value", + "public enum Color { RED, GREEN, BLUE }\n" + "public class Test {\n" + " public static int main() {\n" + " return Color.BLUE;\n" + " }\n" + "}\n", + "Test", "main", 2); + + total++; + passed += run_test("enum comparison", + "public enum Day { MON, TUE, WED, THU, FRI }\n" + "public class Test {\n" + " public static int main() {\n" + " int day = Day.WED;\n" + " if (day == 2) {\n" + " return 42;\n" + " }\n" + " return 0;\n" + " }\n" + "}\n", + "Test", "main", 42); + + total++; + passed += run_test("enum in switch", + "public enum Status { OK, ERROR, PENDING }\n" + "public class Test {\n" + " public static int main() {\n" + " int s = Status.ERROR;\n" + " switch (s) {\n" + " case 0: return 10;\n" + " case 1: return 20;\n" + " case 2: return 30;\n" + " default: return 0;\n" + " }\n" + " }\n" + "}\n", + "Test", "main", 20); + + printf("\n=== Results: %d/%d tests passed ===\n", passed, total); + + return (passed == total) ? 0 : 1; +} diff --git a/tests/test_enums.o b/tests/test_enums.o new file mode 100644 index 0000000..e72d4ed Binary files /dev/null and b/tests/test_enums.o differ diff --git a/tests/test_exceptions.c b/tests/test_exceptions.c new file mode 100644 index 0000000..44ecd67 --- /dev/null +++ b/tests/test_exceptions.c @@ -0,0 +1,127 @@ +#include "../lexer/lexer.h" +#include "../parser/parser.h" +#include "../semantic/semantic.h" +#include "../ir/ir.h" +#include "../ir/ir_gen.h" +#include "../runtime/runtime.h" +#include +#include +#include + +static int test_count = 0; +static int pass_count = 0; + +static void run_test_int(const char* name, const char* source, int expected) { + test_count++; + + RavaLexer_t* lexer = rava_lexer_create(source); + RavaParser_t* parser = rava_parser_create(lexer); + RavaASTNode_t* ast = rava_parser_parse(parser); + + if (!ast || parser->had_error) { + printf("FAIL: %s - Parse error: %s\n", name, parser->error_message ? parser->error_message : "unknown"); + rava_parser_destroy(parser); + rava_lexer_destroy(lexer); + return; + } + + RavaSemanticAnalyzer_t* analyzer = rava_semantic_analyzer_create(); + rava_semantic_analyze(analyzer, ast); + + RavaIRGenerator_t* ir_gen = rava_ir_generator_create(analyzer); + RavaProgram_t* program = rava_ir_generate(ir_gen, ast); + + RavaVM_t* vm = rava_vm_create(program); + + if (!rava_vm_execute(vm, "Test", "main")) { + printf("FAIL: %s - Runtime error: %s\n", name, vm->error_message ? vm->error_message : "unknown"); + rava_vm_destroy(vm); + rava_program_destroy(program); + rava_ir_generator_destroy(ir_gen); + rava_semantic_analyzer_destroy(analyzer); + rava_ast_node_destroy(ast); + rava_parser_destroy(parser); + rava_lexer_destroy(lexer); + return; + } + + RavaValue_t result = rava_vm_get_result(vm); + int32_t result_int = rava_value_as_int(result); + + if (result_int == expected) { + printf("PASS: %s (result=%d)\n", name, result_int); + pass_count++; + } else { + printf("FAIL: %s (expected=%d, got=%d)\n", name, expected, result_int); + } + + rava_vm_destroy(vm); + rava_program_destroy(program); + rava_ir_generator_destroy(ir_gen); + rava_semantic_analyzer_destroy(analyzer); + rava_ast_node_destroy(ast); + rava_parser_destroy(parser); + rava_lexer_destroy(lexer); +} + +int main(void) { + printf("=== Exception Handling Tests ===\n\n"); + + run_test_int("basic try-catch", + "public class Test {\n" + " public static int main() {\n" + " int result = 0;\n" + " try {\n" + " throw 42;\n" + " } catch (Exception e) {\n" + " result = e;\n" + " }\n" + " return result;\n" + " }\n" + "}\n", 42); + + run_test_int("try without exception", + "public class Test {\n" + " public static int main() {\n" + " int result = 10;\n" + " try {\n" + " result = 20;\n" + " } catch (Exception e) {\n" + " result = 99;\n" + " }\n" + " return result;\n" + " }\n" + "}\n", 20); + + run_test_int("catch modifies value", + "public class Test {\n" + " public static int main() {\n" + " int x = 5;\n" + " try {\n" + " throw 10;\n" + " } catch (Exception e) {\n" + " x = x + e;\n" + " }\n" + " return x;\n" + " }\n" + "}\n", 15); + + run_test_int("try-finally without exception", + "public class Test {\n" + " public static int main() {\n" + " int result = 0;\n" + " try {\n" + " result = 10;\n" + " } catch (Exception e) {\n" + " result = 99;\n" + " } finally {\n" + " result = result + 5;\n" + " }\n" + " return result;\n" + " }\n" + "}\n", 15); + + printf("\n=== Results: %d/%d tests passed ===\n", pass_count, test_count); + + return (pass_count == test_count) ? 0 : 1; +} diff --git a/tests/test_exceptions.o b/tests/test_exceptions.o new file mode 100644 index 0000000..2fc7d6d Binary files /dev/null and b/tests/test_exceptions.o differ diff --git a/tests/test_fastframe.c b/tests/test_fastframe.c new file mode 100644 index 0000000..e636620 --- /dev/null +++ b/tests/test_fastframe.c @@ -0,0 +1,142 @@ +#include +#include +#include "../runtime/fastframe.h" + +static int tests_passed = 0; + +#define TEST(name) static void test_##name(void) +#define RUN_TEST(name) do { \ + printf("Running %s... ", #name); \ + test_##name(); \ + printf("PASSED\n"); \ + tests_passed++; \ +} while(0) + +TEST(init) { + rava_fastframe_init(); + assert(rava_fastframe_get_depth() == 0); + assert(rava_fastframe_current() == NULL); +} + +TEST(push_pop) { + rava_fastframe_init(); + + FastFrame_t* frame = rava_fastframe_push(NULL, 4); + assert(frame != NULL); + assert(rava_fastframe_get_depth() == 1); + assert(rava_fastframe_current() == frame); + + rava_fastframe_pop(); + assert(rava_fastframe_get_depth() == 0); + assert(rava_fastframe_current() == NULL); +} + +TEST(nested_frames) { + rava_fastframe_init(); + + FastFrame_t* f1 = rava_fastframe_push(NULL, 2); + FastFrame_t* f2 = rava_fastframe_push(NULL, 2); + FastFrame_t* f3 = rava_fastframe_push(NULL, 2); + + assert(rava_fastframe_get_depth() == 3); + assert(rava_fastframe_current() == f3); + + rava_fastframe_pop(); + assert(rava_fastframe_current() == f2); + + rava_fastframe_pop(); + assert(rava_fastframe_current() == f1); + + rava_fastframe_pop(); + assert(rava_fastframe_current() == NULL); +} + +TEST(stack_operations) { + rava_fastframe_init(); + + FastFrame_t* frame = rava_fastframe_push(NULL, 4); + assert(rava_fastframe_stack_is_empty(frame)); + + rava_fastframe_stack_push(frame, rava_nanbox_int(10)); + rava_fastframe_stack_push(frame, rava_nanbox_int(20)); + rava_fastframe_stack_push(frame, rava_nanbox_int(30)); + + assert(!rava_fastframe_stack_is_empty(frame)); + assert(frame->stack_top == 3); + + RavaNanboxValue_t top = rava_fastframe_stack_peek(frame); + assert(rava_nanbox_as_int(top) == 30); + assert(frame->stack_top == 3); + + RavaNanboxValue_t v1 = rava_fastframe_stack_pop(frame); + RavaNanboxValue_t v2 = rava_fastframe_stack_pop(frame); + RavaNanboxValue_t v3 = rava_fastframe_stack_pop(frame); + + assert(rava_nanbox_as_int(v1) == 30); + assert(rava_nanbox_as_int(v2) == 20); + assert(rava_nanbox_as_int(v3) == 10); + assert(rava_fastframe_stack_is_empty(frame)); + + rava_fastframe_reset(); +} + +TEST(locals) { + rava_fastframe_init(); + + FastFrame_t* frame = rava_fastframe_push(NULL, 8); + + frame->locals[0] = rava_nanbox_int(100); + frame->locals[1] = rava_nanbox_int(200); + frame->locals[2] = rava_nanbox_bool(true); + + assert(rava_nanbox_as_int(frame->locals[0]) == 100); + assert(rava_nanbox_as_int(frame->locals[1]) == 200); + assert(rava_nanbox_as_bool(frame->locals[2]) == true); + + rava_fastframe_reset(); +} + +TEST(reset) { + rava_fastframe_init(); + + rava_fastframe_push(NULL, 2); + rava_fastframe_push(NULL, 2); + rava_fastframe_push(NULL, 2); + + assert(rava_fastframe_get_depth() == 3); + + rava_fastframe_reset(); + assert(rava_fastframe_get_depth() == 0); +} + +TEST(stack_clear) { + rava_fastframe_init(); + + FastFrame_t* frame = rava_fastframe_push(NULL, 4); + rava_fastframe_stack_push(frame, rava_nanbox_int(1)); + rava_fastframe_stack_push(frame, rava_nanbox_int(2)); + rava_fastframe_stack_push(frame, rava_nanbox_int(3)); + + assert(frame->stack_top == 3); + + rava_fastframe_stack_clear(frame); + assert(frame->stack_top == 0); + assert(rava_fastframe_stack_is_empty(frame)); + + rava_fastframe_reset(); +} + +int main(void) { + printf("=== Fast Frame Unit Tests ===\n\n"); + + RUN_TEST(init); + RUN_TEST(push_pop); + RUN_TEST(nested_frames); + RUN_TEST(stack_operations); + RUN_TEST(locals); + RUN_TEST(reset); + RUN_TEST(stack_clear); + + printf("\n=== Results: %d tests passed ===\n", tests_passed); + return 0; +} diff --git a/tests/test_fileio.c b/tests/test_fileio.c new file mode 100644 index 0000000..6da6fa9 --- /dev/null +++ b/tests/test_fileio.c @@ -0,0 +1,77 @@ +#include "../lexer/lexer.h" +#include "../parser/parser.h" +#include "../semantic/semantic.h" +#include "../ir/ir.h" +#include "../ir/ir_gen.h" +#include "../runtime/runtime.h" +#include +#include +#include + +static char* read_file(const char *filename) { + FILE *file = fopen(filename, "r"); + if (!file) return NULL; + fseek(file, 0, SEEK_END); + long size = ftell(file); + fseek(file, 0, SEEK_SET); + char *content = malloc(size + 1); + size_t read_bytes = fread(content, 1, size, file); (void)read_bytes; + content[size] = '\0'; + fclose(file); + return content; +} + +int main() { + char *source = read_file("examples/15_FileIO.java"); + if (!source) { + printf("Failed to read file\n"); + return 1; + } + + RavaLexer_t *lexer = rava_lexer_create(source); + RavaParser_t *parser = rava_parser_create(lexer); + RavaASTNode_t *ast = rava_parser_parse(parser); + + if (parser->had_error) { + printf("Parse error: %s\n", parser->error_message); + free(source); + return 1; + } + + printf("Parse: OK\n"); + + RavaSemanticAnalyzer_t *analyzer = rava_semantic_analyzer_create(); + if (!rava_semantic_analyze(analyzer, ast)) { + printf("Semantic error: %s\n", analyzer->error_message); + free(source); + return 1; + } + + printf("Semantic: OK\n"); + + RavaIRGenerator_t *ir_gen = rava_ir_generator_create(analyzer); + RavaProgram_t *program = rava_ir_generate(ir_gen, ast); + + if (!program) { + printf("IR generation failed\n"); + free(source); + return 1; + } + + printf("IR Gen: OK\n"); + printf("\nOutput:\n"); + + RavaVM_t *vm = rava_vm_create(program); + if (!rava_vm_execute(vm, "FileIO", "main")) { + printf("Runtime error: %s\n", vm->error_message); + rava_vm_destroy(vm); + free(source); + return 1; + } + + printf("\nExecution: OK\n"); + + rava_vm_destroy(vm); + free(source); + return 0; +} diff --git a/tests/test_fileio.o b/tests/test_fileio.o new file mode 100644 index 0000000..2fb4b88 Binary files /dev/null and b/tests/test_fileio.o differ diff --git a/tests/test_forloop.c b/tests/test_forloop.c new file mode 100644 index 0000000..e46be99 --- /dev/null +++ b/tests/test_forloop.c @@ -0,0 +1,77 @@ +#include "../lexer/lexer.h" +#include "../parser/parser.h" +#include "../semantic/semantic.h" +#include "../ir/ir.h" +#include "../ir/ir_gen.h" +#include "../runtime/runtime.h" +#include +#include +#include + +static char* read_file(const char *filename) { + FILE *file = fopen(filename, "r"); + if (!file) return NULL; + fseek(file, 0, SEEK_END); + long size = ftell(file); + fseek(file, 0, SEEK_SET); + char *content = malloc(size + 1); + size_t read_bytes = fread(content, 1, size, file); (void)read_bytes; + content[size] = '\0'; + fclose(file); + return content; +} + +int main() { + char *source = read_file("examples/16_ForLoop.java"); + if (!source) { + printf("Failed to read file\n"); + return 1; + } + + RavaLexer_t *lexer = rava_lexer_create(source); + RavaParser_t *parser = rava_parser_create(lexer); + RavaASTNode_t *ast = rava_parser_parse(parser); + + if (parser->had_error) { + printf("Parse error: %s\n", parser->error_message); + free(source); + return 1; + } + + printf("Parse: OK\n"); + + RavaSemanticAnalyzer_t *analyzer = rava_semantic_analyzer_create(); + if (!rava_semantic_analyze(analyzer, ast)) { + printf("Semantic error: %s\n", analyzer->error_message); + free(source); + return 1; + } + + printf("Semantic: OK\n"); + + RavaIRGenerator_t *ir_gen = rava_ir_generator_create(analyzer); + RavaProgram_t *program = rava_ir_generate(ir_gen, ast); + + if (!program) { + printf("IR generation failed\n"); + free(source); + return 1; + } + + printf("IR Gen: OK\n"); + printf("\nOutput:\n"); + + RavaVM_t *vm = rava_vm_create(program); + if (!rava_vm_execute(vm, "ForLoop", "main")) { + printf("Runtime error: %s\n", vm->error_message); + rava_vm_destroy(vm); + free(source); + return 1; + } + + printf("\nExecution: OK\n"); + + rava_vm_destroy(vm); + free(source); + return 0; +} diff --git a/tests/test_inheritance.c b/tests/test_inheritance.c new file mode 100644 index 0000000..728284d --- /dev/null +++ b/tests/test_inheritance.c @@ -0,0 +1,77 @@ +#include "../lexer/lexer.h" +#include "../parser/parser.h" +#include "../semantic/semantic.h" +#include "../ir/ir.h" +#include "../ir/ir_gen.h" +#include "../runtime/runtime.h" +#include +#include +#include + +static char* read_file(const char *filename) { + FILE *file = fopen(filename, "r"); + if (!file) return NULL; + fseek(file, 0, SEEK_END); + long size = ftell(file); + fseek(file, 0, SEEK_SET); + char *content = malloc(size + 1); + size_t read_bytes = fread(content, 1, size, file); (void)read_bytes; + content[size] = '\0'; + fclose(file); + return content; +} + +int main() { + char *source = read_file("examples/17_Inheritance.java"); + if (!source) { + printf("Failed to read file\n"); + return 1; + } + + RavaLexer_t *lexer = rava_lexer_create(source); + RavaParser_t *parser = rava_parser_create(lexer); + RavaASTNode_t *ast = rava_parser_parse(parser); + + if (parser->had_error) { + printf("Parse error: %s\n", parser->error_message); + free(source); + return 1; + } + + printf("Parse: OK\n"); + + RavaSemanticAnalyzer_t *analyzer = rava_semantic_analyzer_create(); + if (!rava_semantic_analyze(analyzer, ast)) { + printf("Semantic error: %s\n", analyzer->error_message); + free(source); + return 1; + } + + printf("Semantic: OK\n"); + + RavaIRGenerator_t *ir_gen = rava_ir_generator_create(analyzer); + RavaProgram_t *program = rava_ir_generate(ir_gen, ast); + + if (!program) { + printf("IR generation failed\n"); + free(source); + return 1; + } + + printf("IR Gen: OK\n"); + printf("\nOutput:\n"); + + RavaVM_t *vm = rava_vm_create(program); + if (!rava_vm_execute(vm, "Inheritance", "main")) { + printf("Runtime error: %s\n", vm->error_message); + rava_vm_destroy(vm); + free(source); + return 1; + } + + printf("\nExecution: OK\n"); + + rava_vm_destroy(vm); + free(source); + return 0; +} diff --git a/tests/test_instance_methods.c b/tests/test_instance_methods.c new file mode 100644 index 0000000..d127a99 --- /dev/null +++ b/tests/test_instance_methods.c @@ -0,0 +1,77 @@ +#include "../lexer/lexer.h" +#include "../parser/parser.h" +#include "../semantic/semantic.h" +#include "../ir/ir.h" +#include "../ir/ir_gen.h" +#include "../runtime/runtime.h" +#include +#include +#include + +static char* read_file(const char *filename) { + FILE *file = fopen(filename, "r"); + if (!file) return NULL; + fseek(file, 0, SEEK_END); + long size = ftell(file); + fseek(file, 0, SEEK_SET); + char *content = malloc(size + 1); + size_t read_bytes = fread(content, 1, size, file); (void)read_bytes; + content[size] = '\0'; + fclose(file); + return content; +} + +int main() { + char *source = read_file("examples/14_InstanceMethods.java"); + if (!source) { + printf("Failed to read file\n"); + return 1; + } + + RavaLexer_t *lexer = rava_lexer_create(source); + RavaParser_t *parser = rava_parser_create(lexer); + RavaASTNode_t *ast = rava_parser_parse(parser); + + if (parser->had_error) { + printf("Parse error: %s\n", parser->error_message); + free(source); + return 1; + } + + printf("Parse: OK\n"); + + RavaSemanticAnalyzer_t *analyzer = rava_semantic_analyzer_create(); + if (!rava_semantic_analyze(analyzer, ast)) { + printf("Semantic error: %s\n", analyzer->error_message); + free(source); + return 1; + } + + printf("Semantic: OK\n"); + + RavaIRGenerator_t *ir_gen = rava_ir_generator_create(analyzer); + RavaProgram_t *program = rava_ir_generate(ir_gen, ast); + + if (!program) { + printf("IR generation failed\n"); + free(source); + return 1; + } + + printf("IR Gen: OK\n"); + printf("\nOutput:\n"); + + RavaVM_t *vm = rava_vm_create(program); + if (!rava_vm_execute(vm, "InstanceMethods", "main")) { + printf("Runtime error: %s\n", vm->error_message); + rava_vm_destroy(vm); + free(source); + return 1; + } + + printf("\nExecution: OK\n"); + + rava_vm_destroy(vm); + free(source); + return 0; +} diff --git a/tests/test_instance_methods.o b/tests/test_instance_methods.o new file mode 100644 index 0000000..d2468fc Binary files /dev/null and b/tests/test_instance_methods.o differ diff --git a/tests/test_instanceof.c b/tests/test_instanceof.c new file mode 100644 index 0000000..d857cf1 --- /dev/null +++ b/tests/test_instanceof.c @@ -0,0 +1,105 @@ +#include "../lexer/lexer.h" +#include "../parser/parser.h" +#include "../semantic/semantic.h" +#include "../ir/ir.h" +#include "../ir/ir_gen.h" +#include "../runtime/runtime.h" +#include +#include +#include + +static int test_count = 0; +static int pass_count = 0; + +static void run_test_int(const char* name, const char* source, int expected) { + test_count++; + + RavaLexer_t* lexer = rava_lexer_create(source); + RavaParser_t* parser = rava_parser_create(lexer); + RavaASTNode_t* ast = rava_parser_parse(parser); + + if (!ast || parser->had_error) { + printf("FAIL: %s - Parse error: %s\n", name, parser->error_message ? parser->error_message : "unknown"); + rava_parser_destroy(parser); + rava_lexer_destroy(lexer); + return; + } + + RavaSemanticAnalyzer_t* analyzer = rava_semantic_analyzer_create(); + rava_semantic_analyze(analyzer, ast); + + RavaIRGenerator_t* ir_gen = rava_ir_generator_create(analyzer); + RavaProgram_t* program = rava_ir_generate(ir_gen, ast); + + RavaVM_t* vm = rava_vm_create(program); + + if (!rava_vm_execute(vm, "Test", "main")) { + printf("FAIL: %s - Runtime error: %s\n", name, vm->error_message ? vm->error_message : "unknown"); + rava_vm_destroy(vm); + rava_program_destroy(program); + rava_ir_generator_destroy(ir_gen); + rava_semantic_analyzer_destroy(analyzer); + rava_ast_node_destroy(ast); + rava_parser_destroy(parser); + rava_lexer_destroy(lexer); + return; + } + + RavaValue_t result = rava_vm_get_result(vm); + int32_t result_int = rava_value_as_int(result); + + if (result_int == expected) { + printf("PASS: %s (result=%d)\n", name, result_int); + pass_count++; + } else { + printf("FAIL: %s (expected=%d, got=%d)\n", name, expected, result_int); + } + + rava_vm_destroy(vm); + rava_program_destroy(program); + rava_ir_generator_destroy(ir_gen); + rava_semantic_analyzer_destroy(analyzer); + rava_ast_node_destroy(ast); + rava_parser_destroy(parser); + rava_lexer_destroy(lexer); +} + +int main(void) { + printf("=== Instanceof Tests ===\n\n"); + + run_test_int("instanceof true", + "public class Animal {}\n" + "public class Test {\n" + " public static int main() {\n" + " Animal a = new Animal();\n" + " if (a instanceof Animal) { return 1; }\n" + " return 0;\n" + " }\n" + "}\n", 1); + + run_test_int("instanceof false", + "public class Animal {}\n" + "public class Dog {}\n" + "public class Test {\n" + " public static int main() {\n" + " Dog d = new Dog();\n" + " if (d instanceof Animal) { return 1; }\n" + " return 0;\n" + " }\n" + "}\n", 0); + + run_test_int("instanceof in expression", + "public class Person {}\n" + "public class Test {\n" + " public static int main() {\n" + " Person p = new Person();\n" + " int result = 0;\n" + " if (p instanceof Person) { result = 42; }\n" + " return result;\n" + " }\n" + "}\n", 42); + + printf("\n=== Results: %d/%d tests passed ===\n", pass_count, test_count); + + return (pass_count == test_count) ? 0 : 1; +} diff --git a/tests/test_instanceof.o b/tests/test_instanceof.o new file mode 100644 index 0000000..730ddcd Binary files /dev/null and b/tests/test_instanceof.o differ diff --git a/tests/test_interfaces.c b/tests/test_interfaces.c new file mode 100644 index 0000000..f1f5f34 --- /dev/null +++ b/tests/test_interfaces.c @@ -0,0 +1,148 @@ +#include "../lexer/lexer.h" +#include "../parser/parser.h" +#include "../semantic/semantic.h" +#include "../ir/ir.h" +#include "../ir/ir_gen.h" +#include "../runtime/runtime.h" +#include +#include +#include + +static int test_count = 0; +static int pass_count = 0; + +static void run_test_int(const char* name, const char* source, int expected) { + test_count++; + + RavaLexer_t* lexer = rava_lexer_create(source); + RavaParser_t* parser = rava_parser_create(lexer); + RavaASTNode_t* ast = rava_parser_parse(parser); + + if (!ast || parser->had_error) { + printf("FAIL: %s - Parse error: %s\n", name, parser->error_message ? parser->error_message : "unknown"); + rava_parser_destroy(parser); + rava_lexer_destroy(lexer); + return; + } + + RavaSemanticAnalyzer_t* analyzer = rava_semantic_analyzer_create(); + rava_semantic_analyze(analyzer, ast); + + RavaIRGenerator_t* ir_gen = rava_ir_generator_create(analyzer); + RavaProgram_t* program = rava_ir_generate(ir_gen, ast); + + RavaVM_t* vm = rava_vm_create(program); + + if (!rava_vm_execute(vm, "Test", "main")) { + printf("FAIL: %s - Runtime error: %s\n", name, vm->error_message ? vm->error_message : "unknown"); + rava_vm_destroy(vm); + rava_program_destroy(program); + rava_ir_generator_destroy(ir_gen); + rava_semantic_analyzer_destroy(analyzer); + rava_ast_node_destroy(ast); + rava_parser_destroy(parser); + rava_lexer_destroy(lexer); + return; + } + + RavaValue_t result = rava_vm_get_result(vm); + int32_t result_int = rava_value_as_int(result); + + if (result_int == expected) { + printf("PASS: %s (result=%d)\n", name, result_int); + pass_count++; + } else { + printf("FAIL: %s (expected=%d, got=%d)\n", name, expected, result_int); + } + + rava_vm_destroy(vm); + rava_program_destroy(program); + rava_ir_generator_destroy(ir_gen); + rava_semantic_analyzer_destroy(analyzer); + rava_ast_node_destroy(ast); + rava_parser_destroy(parser); + rava_lexer_destroy(lexer); +} + +int main(void) { + printf("=== Interface Tests ===\n\n"); + + run_test_int("interface with implementing class", + "interface Addable {\n" + " int add(int a, int b);\n" + "}\n" + "class Calculator implements Addable {\n" + " int add(int a, int b) {\n" + " return a + b;\n" + " }\n" + "}\n" + "public class Test {\n" + " public static int main() {\n" + " Calculator calc = new Calculator();\n" + " return calc.add(10, 20);\n" + " }\n" + "}\n", 30); + + run_test_int("class implements multiple interfaces", + "interface Addable {\n" + " int add(int a, int b);\n" + "}\n" + "interface Subtractable {\n" + " int subtract(int a, int b);\n" + "}\n" + "class Calculator implements Addable, Subtractable {\n" + " int add(int a, int b) {\n" + " return a + b;\n" + " }\n" + " int subtract(int a, int b) {\n" + " return a - b;\n" + " }\n" + "}\n" + "public class Test {\n" + " public static int main() {\n" + " Calculator calc = new Calculator();\n" + " return calc.add(100, 50) - calc.subtract(30, 10);\n" + " }\n" + "}\n", 130); + + run_test_int("class extends and implements", + "interface Printable {\n" + " int getValue();\n" + "}\n" + "class Base {\n" + " int baseValue;\n" + " Base() {\n" + " this.baseValue = 100;\n" + " }\n" + "}\n" + "class Derived extends Base implements Printable {\n" + " int getValue() {\n" + " return this.baseValue + 50;\n" + " }\n" + "}\n" + "public class Test {\n" + " public static int main() {\n" + " Derived d = new Derived();\n" + " return d.getValue();\n" + " }\n" + "}\n", 150); + + run_test_int("empty interface", + "interface Empty {\n" + "}\n" + "class MyClass implements Empty {\n" + " int getValue() {\n" + " return 42;\n" + " }\n" + "}\n" + "public class Test {\n" + " public static int main() {\n" + " MyClass obj = new MyClass();\n" + " return obj.getValue();\n" + " }\n" + "}\n", 42); + + printf("\n=== Results: %d/%d tests passed ===\n", pass_count, test_count); + + return (pass_count == test_count) ? 0 : 1; +} diff --git a/tests/test_interfaces.o b/tests/test_interfaces.o new file mode 100644 index 0000000..3379f18 Binary files /dev/null and b/tests/test_interfaces.o differ diff --git a/tests/test_ir.c b/tests/test_ir.c new file mode 100644 index 0000000..a97eeab --- /dev/null +++ b/tests/test_ir.c @@ -0,0 +1,66 @@ +#include "../lexer/lexer.h" +#include "../parser/parser.h" +#include "../semantic/semantic.h" +#include "../ir/ir.h" +#include "../ir/ir_gen.h" +#include +#include + +int main() { + const char *source = + "public class Math {\n" + " public static int add(int a, int b) {\n" + " int result = a + b;\n" + " return result;\n" + " }\n" + "\n" + " public static int factorial(int n) {\n" + " if (n <= 1) {\n" + " return 1;\n" + " }\n" + " return n * factorial(n - 1);\n" + " }\n" + "}\n"; + + printf("Source code:\n%s\n", source); + printf("\nIR Generation:\n"); + printf("================================================================================\n\n"); + + RavaLexer_t *lexer = rava_lexer_create(source); + RavaParser_t *parser = rava_parser_create(lexer); + RavaASTNode_t *ast = rava_parser_parse(parser); + + if (parser->had_error) { + printf("Parse error: %s\n", parser->error_message ? parser->error_message : "Unknown error"); + return 1; + } + + RavaSemanticAnalyzer_t *analyzer = rava_semantic_analyzer_create(); + bool semantic_ok = rava_semantic_analyze(analyzer, ast); + + if (!semantic_ok) { + printf("Semantic error: %s\n", analyzer->error_message ? analyzer->error_message : "Unknown error"); + return 1; + } + + RavaIRGenerator_t *ir_gen = rava_ir_generator_create(analyzer); + RavaProgram_t *program = rava_ir_generate(ir_gen, ast); + + if (program) { + rava_ir_print(program); + printf("\n✓ IR generation completed successfully!\n"); + } else { + printf("✗ IR generation failed!\n"); + return 1; + } + + rava_program_destroy(program); + rava_ir_generator_destroy(ir_gen); + rava_semantic_analyzer_destroy(analyzer); + rava_ast_node_destroy(ast); + rava_parser_destroy(parser); + rava_lexer_destroy(lexer); + + printf("\nIR test completed!\n"); + return 0; +} diff --git a/tests/test_ir.o b/tests/test_ir.o new file mode 100644 index 0000000..0f81dc2 Binary files /dev/null and b/tests/test_ir.o differ diff --git a/tests/test_labeltable.c b/tests/test_labeltable.c new file mode 100644 index 0000000..d63419b --- /dev/null +++ b/tests/test_labeltable.c @@ -0,0 +1,124 @@ +#include +#include +#include +#include "../ir/ir.h" +#include "../runtime/labeltable.h" + +static int tests_passed = 0; + +#define TEST(name) static void test_##name(void) +#define RUN_TEST(name) do { \ + printf("Running %s... ", #name); \ + test_##name(); \ + printf("PASSED\n"); \ + tests_passed++; \ +} while(0) + +TEST(create_empty) { + RavaInstructionList_t* list = rava_instruction_list_create(); + LabelTable_t* table = rava_labeltable_create(list); + assert(table != NULL); + rava_labeltable_destroy(table); + rava_instruction_list_destroy(list); +} + +TEST(create_null) { + LabelTable_t* table = rava_labeltable_create(NULL); + assert(table == NULL); +} + +TEST(single_label) { + RavaInstructionList_t* list = rava_instruction_list_create(); + + RavaInstruction_t instr1 = {.opcode = RAVA_OP_LOAD_CONST, .operand.int_value = 10}; + RavaInstruction_t instr2 = {.opcode = RAVA_OP_LABEL, .operand.label_id = 0}; + RavaInstruction_t instr3 = {.opcode = RAVA_OP_LOAD_CONST, .operand.int_value = 20}; + + rava_instruction_list_add(list, instr1); + rava_instruction_list_add(list, instr2); + rava_instruction_list_add(list, instr3); + + LabelTable_t* table = rava_labeltable_create(list); + assert(table != NULL); + + size_t pc = rava_labeltable_lookup(table, 0); + assert(pc == 2); + + rava_labeltable_destroy(table); + rava_instruction_list_destroy(list); +} + +TEST(multiple_labels) { + RavaInstructionList_t* list = rava_instruction_list_create(); + + RavaInstruction_t instr0 = {.opcode = RAVA_OP_LOAD_CONST, .operand.int_value = 0}; + RavaInstruction_t label0 = {.opcode = RAVA_OP_LABEL, .operand.label_id = 0}; + RavaInstruction_t instr1 = {.opcode = RAVA_OP_LOAD_CONST, .operand.int_value = 1}; + RavaInstruction_t label1 = {.opcode = RAVA_OP_LABEL, .operand.label_id = 1}; + RavaInstruction_t instr2 = {.opcode = RAVA_OP_LOAD_CONST, .operand.int_value = 2}; + RavaInstruction_t label2 = {.opcode = RAVA_OP_LABEL, .operand.label_id = 2}; + + rava_instruction_list_add(list, instr0); + rava_instruction_list_add(list, label0); + rava_instruction_list_add(list, instr1); + rava_instruction_list_add(list, label1); + rava_instruction_list_add(list, instr2); + rava_instruction_list_add(list, label2); + + LabelTable_t* table = rava_labeltable_create(list); + assert(table != NULL); + + assert(rava_labeltable_lookup(table, 0) == 2); + assert(rava_labeltable_lookup(table, 1) == 4); + assert(rava_labeltable_lookup(table, 2) == 6); + + rava_labeltable_destroy(table); + rava_instruction_list_destroy(list); +} + +TEST(missing_label) { + RavaInstructionList_t* list = rava_instruction_list_create(); + + RavaInstruction_t label = {.opcode = RAVA_OP_LABEL, .operand.label_id = 5}; + rava_instruction_list_add(list, label); + + LabelTable_t* table = rava_labeltable_create(list); + assert(table != NULL); + + assert(rava_labeltable_lookup(table, 0) == 0); + assert(rava_labeltable_lookup(table, 1) == 0); + assert(rava_labeltable_lookup(table, 5) == 1); + + rava_labeltable_destroy(table); + rava_instruction_list_destroy(list); +} + +TEST(out_of_range) { + RavaInstructionList_t* list = rava_instruction_list_create(); + + RavaInstruction_t label = {.opcode = RAVA_OP_LABEL, .operand.label_id = 2}; + rava_instruction_list_add(list, label); + + LabelTable_t* table = rava_labeltable_create(list); + assert(table != NULL); + + assert(rava_labeltable_lookup(table, 100) == 0); + assert(rava_labeltable_lookup(table, -1) == 0); + + rava_labeltable_destroy(table); + rava_instruction_list_destroy(list); +} + +int main(void) { + printf("=== Label Table Unit Tests ===\n\n"); + + RUN_TEST(create_empty); + RUN_TEST(create_null); + RUN_TEST(single_label); + RUN_TEST(multiple_labels); + RUN_TEST(missing_label); + RUN_TEST(out_of_range); + + printf("\n=== Results: %d tests passed ===\n", tests_passed); + return 0; +} diff --git a/tests/test_lexer.c b/tests/test_lexer.c new file mode 100644 index 0000000..7c0f9c5 --- /dev/null +++ b/tests/test_lexer.c @@ -0,0 +1,95 @@ +#include "../lexer/lexer.h" +#include +#include + +static const char* token_type_to_string(RavaTokenType_e type) { + switch (type) { + case RAVA_TOKEN_EOF: return "EOF"; + case RAVA_TOKEN_KEYWORD_CLASS: return "KEYWORD_CLASS"; + case RAVA_TOKEN_KEYWORD_PUBLIC: return "KEYWORD_PUBLIC"; + case RAVA_TOKEN_KEYWORD_STATIC: return "KEYWORD_STATIC"; + case RAVA_TOKEN_KEYWORD_VOID: return "KEYWORD_VOID"; + case RAVA_TOKEN_KEYWORD_INT: return "KEYWORD_INT"; + case RAVA_TOKEN_KEYWORD_RETURN: return "KEYWORD_RETURN"; + case RAVA_TOKEN_KEYWORD_IF: return "KEYWORD_IF"; + case RAVA_TOKEN_KEYWORD_ELSE: return "KEYWORD_ELSE"; + case RAVA_TOKEN_IDENTIFIER: return "IDENTIFIER"; + case RAVA_TOKEN_LITERAL_INTEGER: return "LITERAL_INTEGER"; + case RAVA_TOKEN_LITERAL_STRING: return "LITERAL_STRING"; + case RAVA_TOKEN_LITERAL_TRUE: return "LITERAL_TRUE"; + case RAVA_TOKEN_LITERAL_FALSE: return "LITERAL_FALSE"; + case RAVA_TOKEN_LITERAL_NULL: return "LITERAL_NULL"; + case RAVA_TOKEN_LPAREN: return "LPAREN"; + case RAVA_TOKEN_RPAREN: return "RPAREN"; + case RAVA_TOKEN_LBRACE: return "LBRACE"; + case RAVA_TOKEN_RBRACE: return "RBRACE"; + case RAVA_TOKEN_SEMICOLON: return "SEMICOLON"; + case RAVA_TOKEN_COMMA: return "COMMA"; + case RAVA_TOKEN_DOT: return "DOT"; + case RAVA_TOKEN_ASSIGN: return "ASSIGN"; + case RAVA_TOKEN_PLUS: return "PLUS"; + case RAVA_TOKEN_MINUS: return "MINUS"; + case RAVA_TOKEN_STAR: return "STAR"; + case RAVA_TOKEN_EQUAL: return "EQUAL"; + case RAVA_TOKEN_LT: return "LT"; + case RAVA_TOKEN_GT: return "GT"; + case RAVA_TOKEN_ERROR: return "ERROR"; + default: return "UNKNOWN"; + } +} + +int main() { + const char *source = + "public class HelloWorld {\n" + " public static void main(String[] args) {\n" + " int x = 42;\n" + " if (x > 0) {\n" + " System.out.println(\"Hello, World!\");\n" + " }\n" + " return;\n" + " }\n" + "}\n"; + + printf("Source code:\n%s\n", source); + printf("\nTokens:\n"); + printf("%-20s %-30s %s\n", "Type", "Lexeme", "Location"); + printf("--------------------------------------------------------------------------------\n"); + + RavaLexer_t *lexer = rava_lexer_create(source); + RavaToken_t *token; + + do { + token = rava_lexer_next_token(lexer); + if (token->type == RAVA_TOKEN_ERROR) { + printf("ERROR: %s at line %d, column %d\n", + lexer->error_message ? lexer->error_message : "Unknown error", + token->line, token->column); + rava_token_destroy(token); + break; + } + + printf("%-20s %-30s Line %d, Col %d\n", + token_type_to_string(token->type), + token->lexeme, + token->line, + token->column); + + if (token->type == RAVA_TOKEN_LITERAL_INTEGER) { + printf(" Value: %lld\n", (long long)token->value.int_value); + } else if (token->type == RAVA_TOKEN_LITERAL_STRING) { + printf(" String Value: \"%s\"\n", token->value.string_value); + } + + RavaTokenType_e type = token->type; + rava_token_destroy(token); + + if (type == RAVA_TOKEN_EOF) { + break; + } + } while (1); + + rava_lexer_destroy(lexer); + + printf("\nLexer test completed successfully!\n"); + return 0; +} diff --git a/tests/test_lexer.o b/tests/test_lexer.o new file mode 100644 index 0000000..67139d5 Binary files /dev/null and b/tests/test_lexer.o differ diff --git a/tests/test_math.c b/tests/test_math.c new file mode 100644 index 0000000..4e6d54f --- /dev/null +++ b/tests/test_math.c @@ -0,0 +1,166 @@ +#include "../lexer/lexer.h" +#include "../parser/parser.h" +#include "../semantic/semantic.h" +#include "../ir/ir.h" +#include "../ir/ir_gen.h" +#include "../runtime/runtime.h" +#include +#include +#include +#include + +static int test_count = 0; +static int pass_count = 0; + +static void run_test_int(const char* name, const char* source, int expected) { + test_count++; + + RavaLexer_t* lexer = rava_lexer_create(source); + RavaParser_t* parser = rava_parser_create(lexer); + RavaASTNode_t* ast = rava_parser_parse(parser); + + if (!ast || parser->had_error) { + printf("FAIL: %s - Parse error: %s\n", name, parser->error_message ? parser->error_message : "unknown"); + rava_parser_destroy(parser); + rava_lexer_destroy(lexer); + return; + } + + RavaSemanticAnalyzer_t* analyzer = rava_semantic_analyzer_create(); + rava_semantic_analyze(analyzer, ast); + + RavaIRGenerator_t* ir_gen = rava_ir_generator_create(analyzer); + RavaProgram_t* program = rava_ir_generate(ir_gen, ast); + + RavaVM_t* vm = rava_vm_create(program); + + if (!rava_vm_execute(vm, "Test", "main")) { + printf("FAIL: %s - Runtime error: %s\n", name, vm->error_message ? vm->error_message : "unknown"); + rava_vm_destroy(vm); + rava_program_destroy(program); + rava_ir_generator_destroy(ir_gen); + rava_semantic_analyzer_destroy(analyzer); + rava_ast_node_destroy(ast); + rava_parser_destroy(parser); + rava_lexer_destroy(lexer); + return; + } + + RavaValue_t result = rava_vm_get_result(vm); + int32_t result_int = rava_value_as_int(result); + + if (result_int == expected) { + printf("PASS: %s (result=%d)\n", name, result_int); + pass_count++; + } else { + printf("FAIL: %s (expected=%d, got=%d)\n", name, expected, result_int); + } + + rava_vm_destroy(vm); + rava_program_destroy(program); + rava_ir_generator_destroy(ir_gen); + rava_semantic_analyzer_destroy(analyzer); + rava_ast_node_destroy(ast); + rava_parser_destroy(parser); + rava_lexer_destroy(lexer); +} + +int main(void) { + printf("=== Math Class Tests ===\n\n"); + + run_test_int("Math.abs positive", + "public class Test {\n" + " public static int main() {\n" + " return Math.abs(42);\n" + " }\n" + "}\n", 42); + + run_test_int("Math.abs negative", + "public class Test {\n" + " public static int main() {\n" + " return Math.abs(-42);\n" + " }\n" + "}\n", 42); + + run_test_int("Math.min", + "public class Test {\n" + " public static int main() {\n" + " return Math.min(10, 5);\n" + " }\n" + "}\n", 5); + + run_test_int("Math.max", + "public class Test {\n" + " public static int main() {\n" + " return Math.max(10, 5);\n" + " }\n" + "}\n", 10); + + run_test_int("(int)Math.pow 2^8", + "public class Test {\n" + " public static int main() {\n" + " int result = (int)Math.pow(2, 8);\n" + " return result;\n" + " }\n" + "}\n", 256); + + run_test_int("(int)Math.sqrt 25", + "public class Test {\n" + " public static int main() {\n" + " int result = (int)Math.sqrt(25);\n" + " return result;\n" + " }\n" + "}\n", 5); + + run_test_int("(int)Math.floor 4.9", + "public class Test {\n" + " public static int main() {\n" + " int result = (int)Math.floor(4.9);\n" + " return result;\n" + " }\n" + "}\n", 4); + + run_test_int("(int)Math.ceil 4.1", + "public class Test {\n" + " public static int main() {\n" + " int result = (int)Math.ceil(4.1);\n" + " return result;\n" + " }\n" + "}\n", 5); + + run_test_int("(int)Math.round 4.7", + "public class Test {\n" + " public static int main() {\n" + " int result = (int)Math.round(4.7);\n" + " return result;\n" + " }\n" + "}\n", 5); + + run_test_int("(int)Math.round 4.2", + "public class Test {\n" + " public static int main() {\n" + " int result = (int)Math.round(4.2);\n" + " return result;\n" + " }\n" + "}\n", 4); + + run_test_int("(int) double cast", + "public class Test {\n" + " public static int main() {\n" + " int result = (int)3.14159;\n" + " return result;\n" + " }\n" + "}\n", 3); + + run_test_int("(int) negative double", + "public class Test {\n" + " public static int main() {\n" + " int result = (int)(-7.8);\n" + " return result;\n" + " }\n" + "}\n", -7); + + printf("\n=== Results: %d/%d tests passed ===\n", pass_count, test_count); + + return (pass_count == test_count) ? 0 : 1; +} diff --git a/tests/test_math.o b/tests/test_math.o new file mode 100644 index 0000000..4bbbb3f Binary files /dev/null and b/tests/test_math.o differ diff --git a/tests/test_methodcache.c b/tests/test_methodcache.c new file mode 100644 index 0000000..53d81ca --- /dev/null +++ b/tests/test_methodcache.c @@ -0,0 +1,119 @@ +#include +#include +#include "../runtime/methodcache.h" + +static int tests_passed = 0; + +#define TEST(name) static void test_##name(void) +#define RUN_TEST(name) do { \ + printf("Running %s... ", #name); \ + test_##name(); \ + printf("PASSED\n"); \ + tests_passed++; \ +} while(0) + +TEST(create_destroy) { + MethodCache_t* cache = rava_methodcache_create(); + assert(cache != NULL); + rava_methodcache_destroy(cache); +} + +TEST(insert_lookup) { + MethodCache_t* cache = rava_methodcache_create(); + assert(cache != NULL); + + int dummy_method = 42; + RavaMethod_t* method = (RavaMethod_t*)&dummy_method; + + rava_methodcache_insert(cache, "TestClass", "testMethod", method); + + RavaMethod_t* found = rava_methodcache_lookup(cache, "TestClass", "testMethod"); + assert(found == method); + + rava_methodcache_destroy(cache); +} + +TEST(lookup_miss) { + MethodCache_t* cache = rava_methodcache_create(); + assert(cache != NULL); + + RavaMethod_t* found = rava_methodcache_lookup(cache, "NonExistent", "method"); + assert(found == NULL); + + rava_methodcache_destroy(cache); +} + +TEST(multiple_methods) { + MethodCache_t* cache = rava_methodcache_create(); + assert(cache != NULL); + + int m1 = 1, m2 = 2; + RavaMethod_t* method1 = (RavaMethod_t*)&m1; + RavaMethod_t* method2 = (RavaMethod_t*)&m2; + + rava_methodcache_insert(cache, "TestClass", "methodA", method1); + RavaMethod_t* found1 = rava_methodcache_lookup(cache, "TestClass", "methodA"); + assert(found1 == method1); + + rava_methodcache_insert(cache, "OtherClass", "methodB", method2); + RavaMethod_t* found2 = rava_methodcache_lookup(cache, "OtherClass", "methodB"); + assert(found2 == method2); + + rava_methodcache_destroy(cache); +} + +TEST(clear) { + MethodCache_t* cache = rava_methodcache_create(); + assert(cache != NULL); + + int dummy = 42; + RavaMethod_t* method = (RavaMethod_t*)&dummy; + + rava_methodcache_insert(cache, "TestClass", "testMethod", method); + assert(rava_methodcache_lookup(cache, "TestClass", "testMethod") == method); + + rava_methodcache_clear(cache); + assert(rava_methodcache_lookup(cache, "TestClass", "testMethod") == NULL); + + rava_methodcache_destroy(cache); +} + +TEST(null_params) { + MethodCache_t* cache = rava_methodcache_create(); + + rava_methodcache_insert(NULL, "Class", "method", NULL); + rava_methodcache_insert(cache, NULL, "method", NULL); + rava_methodcache_insert(cache, "Class", NULL, NULL); + + assert(rava_methodcache_lookup(NULL, "Class", "method") == NULL); + assert(rava_methodcache_lookup(cache, NULL, "method") == NULL); + assert(rava_methodcache_lookup(cache, "Class", NULL) == NULL); + + rava_methodcache_destroy(cache); +} + +TEST(hash_function) { + uint32_t h1 = rava_methodcache_hash("hello"); + uint32_t h2 = rava_methodcache_hash("hello"); + uint32_t h3 = rava_methodcache_hash("world"); + + assert(h1 == h2); + assert(h1 != h3); + assert(h1 != 0); + assert(h3 != 0); +} + +int main(void) { + printf("=== Method Cache Unit Tests ===\n\n"); + + RUN_TEST(create_destroy); + RUN_TEST(insert_lookup); + RUN_TEST(lookup_miss); + RUN_TEST(multiple_methods); + RUN_TEST(clear); + RUN_TEST(null_params); + RUN_TEST(hash_function); + + printf("\n=== Results: %d tests passed ===\n", tests_passed); + return 0; +} diff --git a/tests/test_multidim_arrays.c b/tests/test_multidim_arrays.c new file mode 100644 index 0000000..9978650 --- /dev/null +++ b/tests/test_multidim_arrays.c @@ -0,0 +1,149 @@ +#include "../lexer/lexer.h" +#include "../parser/parser.h" +#include "../semantic/semantic.h" +#include "../ir/ir.h" +#include "../ir/ir_gen.h" +#include "../runtime/runtime.h" +#include +#include +#include + +static int test_count = 0; +static int pass_count = 0; + +static void run_test_int(const char* name, const char* source, int expected) { + test_count++; + + RavaLexer_t* lexer = rava_lexer_create(source); + RavaParser_t* parser = rava_parser_create(lexer); + RavaASTNode_t* ast = rava_parser_parse(parser); + + if (!ast || parser->had_error) { + printf("FAIL: %s - Parse error: %s\n", name, parser->error_message ? parser->error_message : "unknown"); + rava_parser_destroy(parser); + rava_lexer_destroy(lexer); + return; + } + + RavaSemanticAnalyzer_t* analyzer = rava_semantic_analyzer_create(); + rava_semantic_analyze(analyzer, ast); + + RavaIRGenerator_t* ir_gen = rava_ir_generator_create(analyzer); + RavaProgram_t* program = rava_ir_generate(ir_gen, ast); + + RavaVM_t* vm = rava_vm_create(program); + + if (!rava_vm_execute(vm, "Test", "main")) { + printf("FAIL: %s - Runtime error: %s\n", name, vm->error_message ? vm->error_message : "unknown"); + rava_vm_destroy(vm); + rava_program_destroy(program); + rava_ir_generator_destroy(ir_gen); + rava_semantic_analyzer_destroy(analyzer); + rava_ast_node_destroy(ast); + rava_parser_destroy(parser); + rava_lexer_destroy(lexer); + return; + } + + RavaValue_t result = rava_vm_get_result(vm); + int32_t result_int = rava_value_as_int(result); + + if (result_int == expected) { + printf("PASS: %s (result=%d)\n", name, result_int); + pass_count++; + } else { + printf("FAIL: %s (expected=%d, got=%d)\n", name, expected, result_int); + } + + rava_vm_destroy(vm); + rava_program_destroy(program); + rava_ir_generator_destroy(ir_gen); + rava_semantic_analyzer_destroy(analyzer); + rava_ast_node_destroy(ast); + rava_parser_destroy(parser); + rava_lexer_destroy(lexer); +} + +int main(void) { + printf("=== Multi-dimensional Array Tests ===\n\n"); + + run_test_int("2d array outer length", + "public class Test {\n" + " public static int main() {\n" + " int[][] a = new int[4][5];\n" + " return a.length;\n" + " }\n" + "}\n", 4); + + run_test_int("2d array inner length", + "public class Test {\n" + " public static int main() {\n" + " int[][] a = new int[4][5];\n" + " return a[0].length;\n" + " }\n" + "}\n", 5); + + run_test_int("2d array basic store and load", + "public class Test {\n" + " public static int main() {\n" + " int[][] a = new int[2][3];\n" + " a[0][1] = 15;\n" + " return a[0][1];\n" + " }\n" + "}\n", 15); + + run_test_int("2d array multiple cells", + "public class Test {\n" + " public static int main() {\n" + " int[][] a = new int[2][3];\n" + " a[0][0] = 1;\n" + " a[0][1] = 2;\n" + " a[1][0] = 3;\n" + " a[1][1] = 4;\n" + " return a[0][0] + a[0][1] + a[1][0] + a[1][1];\n" + " }\n" + "}\n", 10); + + run_test_int("2d array row iteration", + "public class Test {\n" + " public static int main() {\n" + " int[][] a = new int[3][2];\n" + " a[0][0] = 1; a[0][1] = 2;\n" + " a[1][0] = 3; a[1][1] = 4;\n" + " a[2][0] = 5; a[2][1] = 6;\n" + " int sum = 0;\n" + " for (int i = 0; i < a.length; i++) {\n" + " sum = sum + a[i][0] + a[i][1];\n" + " }\n" + " return sum;\n" + " }\n" + "}\n", 21); + + run_test_int("2d array nested loop", + "public class Test {\n" + " public static int main() {\n" + " int[][] a = new int[2][3];\n" + " int v = 1;\n" + " for (int i = 0; i < 2; i++) {\n" + " for (int j = 0; j < 3; j++) {\n" + " a[i][j] = v;\n" + " v = v + 1;\n" + " }\n" + " }\n" + " return a[0][0] + a[0][2] + a[1][1];\n" + " }\n" + "}\n", 9); + + run_test_int("2d array different inner lengths", + "public class Test {\n" + " public static int main() {\n" + " int[][] a = new int[3][4];\n" + " int[][] b = new int[2][6];\n" + " return a[0].length + b[0].length;\n" + " }\n" + "}\n", 10); + + printf("\n=== Results: %d/%d tests passed ===\n", pass_count, test_count); + + return (pass_count == test_count) ? 0 : 1; +} diff --git a/tests/test_multidim_arrays.o b/tests/test_multidim_arrays.o new file mode 100644 index 0000000..095fcec Binary files /dev/null and b/tests/test_multidim_arrays.o differ diff --git a/tests/test_nanbox.c b/tests/test_nanbox.c new file mode 100644 index 0000000..2897b4f --- /dev/null +++ b/tests/test_nanbox.c @@ -0,0 +1,146 @@ +#include +#include +#include +#include "../runtime/nanbox.h" + +static int tests_passed = 0; +static int tests_failed = 0; + +#define TEST(name) static void test_##name(void) +#define RUN_TEST(name) do { \ + printf("Running %s... ", #name); \ + test_##name(); \ + printf("PASSED\n"); \ + tests_passed++; \ +} while(0) + +TEST(int_basic) { + RavaNanboxValue_t val = rava_nanbox_int(42); + assert(rava_nanbox_is_int(val)); + assert(!rava_nanbox_is_bool(val)); + assert(!rava_nanbox_is_null(val)); + assert(rava_nanbox_as_int(val) == 42); +} + +TEST(int_negative) { + RavaNanboxValue_t val = rava_nanbox_int(-100); + assert(rava_nanbox_is_int(val)); + assert(rava_nanbox_as_int(val) == -100); +} + +TEST(int_zero) { + RavaNanboxValue_t val = rava_nanbox_int(0); + assert(rava_nanbox_is_int(val)); + assert(rava_nanbox_as_int(val) == 0); +} + +TEST(long_basic) { + RavaNanboxValue_t val = rava_nanbox_long(1000000000000LL); + assert(rava_nanbox_is_long(val)); + int64_t result = rava_nanbox_as_long(val); + (void)result; +} + +TEST(bool_true) { + RavaNanboxValue_t val = rava_nanbox_bool(true); + assert(rava_nanbox_is_bool(val)); + assert(rava_nanbox_as_bool(val) == true); +} + +TEST(bool_false) { + RavaNanboxValue_t val = rava_nanbox_bool(false); + assert(rava_nanbox_is_bool(val)); + assert(rava_nanbox_as_bool(val) == false); +} + +TEST(null) { + RavaNanboxValue_t val = rava_nanbox_null(); + assert(rava_nanbox_is_null(val)); + assert(!rava_nanbox_is_int(val)); + assert(!rava_nanbox_is_bool(val)); +} + +TEST(double_basic) { + RavaNanboxValue_t val = rava_nanbox_double(3.14159); + assert(rava_nanbox_is_double(val)); + double d = rava_nanbox_as_double(val); + assert(fabs(d - 3.14159) < 0.0001); +} + +TEST(double_negative) { + RavaNanboxValue_t val = rava_nanbox_double(-123.456); + assert(rava_nanbox_is_double(val)); + double d = rava_nanbox_as_double(val); + assert(fabs(d - (-123.456)) < 0.0001); +} + +TEST(conversion_int_to_long) { + RavaNanboxValue_t val = rava_nanbox_int(42); + assert(rava_nanbox_to_long(val) == 42); +} + +TEST(conversion_int_to_double) { + RavaNanboxValue_t val = rava_nanbox_int(10); + assert(fabs(rava_nanbox_to_double(val) - 10.0) < 0.0001); +} + +TEST(conversion_bool_to_int) { + RavaNanboxValue_t t = rava_nanbox_bool(true); + RavaNanboxValue_t f = rava_nanbox_bool(false); + assert(rava_nanbox_to_int(t) == 1); + assert(rava_nanbox_to_int(f) == 0); +} + +TEST(to_bool) { + assert(rava_nanbox_to_bool(rava_nanbox_null()) == false); + assert(rava_nanbox_to_bool(rava_nanbox_bool(true)) == true); + assert(rava_nanbox_to_bool(rava_nanbox_bool(false)) == false); + assert(rava_nanbox_to_bool(rava_nanbox_int(0)) == false); + assert(rava_nanbox_to_bool(rava_nanbox_int(1)) == true); + assert(rava_nanbox_to_bool(rava_nanbox_int(-1)) == true); +} + +TEST(object_pointer) { + int dummy = 42; + RavaNanboxValue_t val = rava_nanbox_object(&dummy); + assert(rava_nanbox_is_object(val)); + assert(rava_nanbox_as_object(val) == &dummy); +} + +TEST(string_pointer) { + const char* str = "hello"; + RavaNanboxValue_t val = rava_nanbox_string(str); + assert(rava_nanbox_is_string(val)); + assert(rava_nanbox_as_string(val) == str); +} + +TEST(array_pointer) { + int arr[10]; + RavaNanboxValue_t val = rava_nanbox_array(arr); + assert(rava_nanbox_is_array(val)); + assert(rava_nanbox_as_array(val) == arr); +} + +int main(void) { + printf("=== NaN Boxing Unit Tests ===\n\n"); + + RUN_TEST(int_basic); + RUN_TEST(int_negative); + RUN_TEST(int_zero); + RUN_TEST(long_basic); + RUN_TEST(bool_true); + RUN_TEST(bool_false); + RUN_TEST(null); + RUN_TEST(double_basic); + RUN_TEST(double_negative); + RUN_TEST(conversion_int_to_long); + RUN_TEST(conversion_int_to_double); + RUN_TEST(conversion_bool_to_int); + RUN_TEST(to_bool); + RUN_TEST(object_pointer); + RUN_TEST(string_pointer); + RUN_TEST(array_pointer); + + printf("\n=== Results: %d passed, %d failed ===\n", tests_passed, tests_failed); + return tests_failed > 0 ? 1 : 0; +} diff --git a/tests/test_negative.c b/tests/test_negative.c new file mode 100644 index 0000000..45947e9 --- /dev/null +++ b/tests/test_negative.c @@ -0,0 +1,234 @@ +#include "../lexer/lexer.h" +#include "../parser/parser.h" +#include "../semantic/semantic.h" +#include "../ir/ir.h" +#include "../ir/ir_gen.h" +#include "../runtime/runtime.h" +#include +#include +#include + +typedef enum { + EXPECT_PARSE_ERROR, + EXPECT_SEMANTIC_ERROR, + EXPECT_RUNTIME_ERROR, + EXPECT_MISSING_CLASS, + EXPECT_MISSING_METHOD +} ExpectedError_e; + +static bool test_error(const char *name, const char *source, ExpectedError_e expected, + const char *exec_class, const char *exec_method) { + printf("Test: %-40s ... ", name); + fflush(stdout); + + if (!source || strlen(source) == 0) { + printf("PASS (skipped empty input)\n"); + return true; + } + + RavaLexer_t *lexer = rava_lexer_create(source); + if (!lexer) { + bool success = (expected == EXPECT_PARSE_ERROR); + printf("%s\n", success ? "PASS" : "FAIL"); + return success; + } + + RavaParser_t *parser = rava_parser_create(lexer); + RavaASTNode_t *ast = rava_parser_parse(parser); + + if (parser->had_error) { + bool success = (expected == EXPECT_PARSE_ERROR); + printf("%s\n", success ? "PASS" : "FAIL"); + rava_parser_destroy(parser); + rava_lexer_destroy(lexer); + return success; + } + + if (expected == EXPECT_PARSE_ERROR) { + printf("FAIL (expected parse error)\n"); + rava_ast_node_destroy(ast); + rava_parser_destroy(parser); + rava_lexer_destroy(lexer); + return false; + } + + RavaSemanticAnalyzer_t *analyzer = rava_semantic_analyzer_create(); + if (!rava_semantic_analyze(analyzer, ast)) { + bool success = (expected == EXPECT_SEMANTIC_ERROR); + printf("%s\n", success ? "PASS" : "FAIL"); + rava_semantic_analyzer_destroy(analyzer); + rava_ast_node_destroy(ast); + rava_parser_destroy(parser); + rava_lexer_destroy(lexer); + return success; + } + + if (expected == EXPECT_SEMANTIC_ERROR) { + printf("FAIL (expected semantic error)\n"); + rava_semantic_analyzer_destroy(analyzer); + rava_ast_node_destroy(ast); + rava_parser_destroy(parser); + rava_lexer_destroy(lexer); + return false; + } + + RavaIRGenerator_t *ir_gen = rava_ir_generator_create(analyzer); + RavaProgram_t *program = rava_ir_generate(ir_gen, ast); + + if (!program) { + bool success = (expected == EXPECT_RUNTIME_ERROR); + printf("%s\n", success ? "PASS" : "FAIL"); + rava_ir_generator_destroy(ir_gen); + rava_semantic_analyzer_destroy(analyzer); + rava_ast_node_destroy(ast); + rava_parser_destroy(parser); + rava_lexer_destroy(lexer); + return success; + } + + RavaVM_t *vm = rava_vm_create(program); + + if (!rava_vm_execute(vm, exec_class, exec_method)) { + bool success = (expected == EXPECT_RUNTIME_ERROR || + expected == EXPECT_MISSING_CLASS || + expected == EXPECT_MISSING_METHOD); + printf("%s\n", success ? "PASS" : "FAIL"); + rava_vm_destroy(vm); + rava_program_destroy(program); + rava_ir_generator_destroy(ir_gen); + rava_semantic_analyzer_destroy(analyzer); + rava_ast_node_destroy(ast); + rava_parser_destroy(parser); + rava_lexer_destroy(lexer); + return success; + } + + printf("FAIL (expected error)\n"); + rava_vm_destroy(vm); + rava_program_destroy(program); + rava_ir_generator_destroy(ir_gen); + rava_semantic_analyzer_destroy(analyzer); + rava_ast_node_destroy(ast); + rava_parser_destroy(parser); + rava_lexer_destroy(lexer); + return false; +} + +int main(void) { + printf("=== NEGATIVE TEST CASES ===\n\n"); + + int passed = 0; + int total = 0; + + total++; + if (test_error("Missing class body", + "public class Test", + EXPECT_PARSE_ERROR, "Test", "main")) { + passed++; + } + + total++; + if (test_error("Missing method body", + "public class Test {\n" + " public static int main()\n" + "}\n", + EXPECT_PARSE_ERROR, "Test", "main")) { + passed++; + } + + total++; + if (test_error("Unclosed brace", + "public class Test {\n" + " public static int main() {\n" + " return 0;\n" + "}\n", + EXPECT_PARSE_ERROR, "Test", "main")) { + passed++; + } + + total++; + if (test_error("Missing semicolon", + "public class Test {\n" + " public static int main() {\n" + " int x = 5\n" + " return x;\n" + " }\n" + "}\n", + EXPECT_PARSE_ERROR, "Test", "main")) { + passed++; + } + + total++; + if (test_error("Undefined variable", + "public class Test {\n" + " public static int main() {\n" + " return undefinedVar;\n" + " }\n" + "}\n", + EXPECT_SEMANTIC_ERROR, "Test", "main")) { + passed++; + } + + total++; + if (test_error("Undefined method call", + "public class Test {\n" + " public static int main() {\n" + " return undefinedMethod();\n" + " }\n" + "}\n", + EXPECT_SEMANTIC_ERROR, "Test", "main")) { + passed++; + } + + total++; + if (test_error("Missing class at runtime", + "public class Test {\n" + " public static int main() {\n" + " return 0;\n" + " }\n" + "}\n", + EXPECT_MISSING_CLASS, "NonExistent", "main")) { + passed++; + } + + total++; + if (test_error("Missing method at runtime", + "public class Test {\n" + " public static int main() {\n" + " return 0;\n" + " }\n" + "}\n", + EXPECT_MISSING_METHOD, "Test", "nonExistent")) { + passed++; + } + + total++; + if (test_error("Duplicate variable", + "public class Test {\n" + " public static int main() {\n" + " int x = 5;\n" + " int x = 10;\n" + " return x;\n" + " }\n" + "}\n", + EXPECT_SEMANTIC_ERROR, "Test", "main")) { + passed++; + } + + total++; + if (test_error("Malformed for loop", + "public class Test {\n" + " public static int main() {\n" + " for (int i = 0; i < 10) {\n" + " }\n" + " return 0;\n" + " }\n" + "}\n", + EXPECT_PARSE_ERROR, "Test", "main")) { + passed++; + } + + printf("\n=== Results: %d/%d tests passed ===\n", passed, total); + + return (passed == total) ? 0 : 1; +} diff --git a/tests/test_negative.o b/tests/test_negative.o new file mode 100644 index 0000000..30a237c Binary files /dev/null and b/tests/test_negative.o differ diff --git a/tests/test_objects.c b/tests/test_objects.c new file mode 100644 index 0000000..11fbdcf --- /dev/null +++ b/tests/test_objects.c @@ -0,0 +1,77 @@ +#include "../lexer/lexer.h" +#include "../parser/parser.h" +#include "../semantic/semantic.h" +#include "../ir/ir.h" +#include "../ir/ir_gen.h" +#include "../runtime/runtime.h" +#include +#include +#include + +static char* read_file(const char *filename) { + FILE *file = fopen(filename, "r"); + if (!file) return NULL; + fseek(file, 0, SEEK_END); + long size = ftell(file); + fseek(file, 0, SEEK_SET); + char *content = malloc(size + 1); + size_t read_bytes = fread(content, 1, size, file); (void)read_bytes; + content[size] = '\0'; + fclose(file); + return content; +} + +int main() { + char *source = read_file("examples/13_SimpleObject.java"); + if (!source) { + printf("Failed to read file\n"); + return 1; + } + + RavaLexer_t *lexer = rava_lexer_create(source); + RavaParser_t *parser = rava_parser_create(lexer); + RavaASTNode_t *ast = rava_parser_parse(parser); + + if (parser->had_error) { + printf("Parse error: %s\n", parser->error_message); + free(source); + return 1; + } + + printf("Parse: OK\n"); + + RavaSemanticAnalyzer_t *analyzer = rava_semantic_analyzer_create(); + if (!rava_semantic_analyze(analyzer, ast)) { + printf("Semantic error: %s\n", analyzer->error_message); + free(source); + return 1; + } + + printf("Semantic: OK\n"); + + RavaIRGenerator_t *ir_gen = rava_ir_generator_create(analyzer); + RavaProgram_t *program = rava_ir_generate(ir_gen, ast); + + if (!program) { + printf("IR generation failed\n"); + free(source); + return 1; + } + + printf("IR Gen: OK\n"); + printf("\nOutput:\n"); + + RavaVM_t *vm = rava_vm_create(program); + if (!rava_vm_execute(vm, "SimpleObject", "main")) { + printf("Runtime error: %s\n", vm->error_message); + rava_vm_destroy(vm); + free(source); + return 1; + } + + printf("\nExecution: OK\n"); + + rava_vm_destroy(vm); + free(source); + return 0; +} diff --git a/tests/test_objects.o b/tests/test_objects.o new file mode 100644 index 0000000..cc8677f Binary files /dev/null and b/tests/test_objects.o differ diff --git a/tests/test_opcode_count.c b/tests/test_opcode_count.c new file mode 100644 index 0000000..549a434 --- /dev/null +++ b/tests/test_opcode_count.c @@ -0,0 +1,17 @@ +#include +#include "../ir/ir.h" + +int main(void) { + printf("RAVA_OP_NOP = %d\n", RAVA_OP_NOP); + printf("RAVA_OP_LOAD_CONST = %d\n", RAVA_OP_LOAD_CONST); + printf("RAVA_OP_CALL = %d\n", RAVA_OP_CALL); + printf("RAVA_OP_CALL_STATIC = %d\n", RAVA_OP_CALL_STATIC); + printf("RAVA_OP_CALL_RECURSIVE = %d\n", RAVA_OP_CALL_RECURSIVE); + printf("RAVA_OP_CALL_VIRTUAL = %d\n", RAVA_OP_CALL_VIRTUAL); + printf("RAVA_OP_CALL_SUPER = %d\n", RAVA_OP_CALL_SUPER); + printf("RAVA_OP_CALL_NATIVE = %d\n", RAVA_OP_CALL_NATIVE); + printf("RAVA_OP_RETURN = %d\n", RAVA_OP_RETURN); + printf("RAVA_OP_MATH_RANDOM = %d\n", RAVA_OP_MATH_RANDOM); + printf("Total opcodes: %d\n", RAVA_OP_MATH_RANDOM + 1); + return 0; +} diff --git a/tests/test_parser.c b/tests/test_parser.c new file mode 100644 index 0000000..db97901 --- /dev/null +++ b/tests/test_parser.c @@ -0,0 +1,50 @@ +#include "../lexer/lexer.h" +#include "../parser/parser.h" +#include +#include + +extern void rava_ast_print(RavaASTNode_t *node, int depth); + +int main() { + const char *source = + "public class Calculator {\n" + " public static int add(int a, int b) {\n" + " int result = a + b;\n" + " return result;\n" + " }\n" + "\n" + " public static void main(String[] args) {\n" + " int x = 10;\n" + " int y = 20;\n" + " int sum = add(x, y);\n" + " if (sum > 0) {\n" + " System.out.println(\"Positive result\");\n" + " }\n" + " }\n" + "}\n"; + + printf("Source code:\n%s\n", source); + printf("\nAbstract Syntax Tree:\n"); + printf("================================================================================\n\n"); + + RavaLexer_t *lexer = rava_lexer_create(source); + RavaParser_t *parser = rava_parser_create(lexer); + + RavaASTNode_t *ast = rava_parser_parse(parser); + + if (parser->had_error) { + printf("Parse error: %s\n", parser->error_message ? parser->error_message : "Unknown error"); + rava_parser_destroy(parser); + rava_lexer_destroy(lexer); + return 1; + } + + rava_ast_print(ast, 0); + + rava_ast_node_destroy(ast); + rava_parser_destroy(parser); + rava_lexer_destroy(lexer); + + printf("\nParser test completed successfully!\n"); + return 0; +} diff --git a/tests/test_parser.o b/tests/test_parser.o new file mode 100644 index 0000000..f4e5f47 Binary files /dev/null and b/tests/test_parser.o differ diff --git a/tests/test_pascal_only.c b/tests/test_pascal_only.c new file mode 100644 index 0000000..875b873 --- /dev/null +++ b/tests/test_pascal_only.c @@ -0,0 +1,91 @@ +#include "../lexer/lexer.h" +#include "../parser/parser.h" +#include "../semantic/semantic.h" +#include "../ir/ir.h" +#include "../ir/ir_gen.h" +#include "../runtime/runtime.h" +#include +#include +#include + +static char* read_file(const char *filename) { + FILE *file = fopen(filename, "r"); + if (!file) return NULL; + fseek(file, 0, SEEK_END); + long size = ftell(file); + fseek(file, 0, SEEK_SET); + char *content = malloc(size + 1); + size_t read_bytes = fread(content, 1, size, file); (void)read_bytes; + content[size] = '\0'; + fclose(file); + return content; +} + +int main() { + char *source = read_file("examples/08_PascalTriangle.java"); + if (!source) return 1; + + RavaLexer_t *lexer = rava_lexer_create(source); + RavaParser_t *parser = rava_parser_create(lexer); + RavaASTNode_t *ast = rava_parser_parse(parser); + if (parser->had_error) { + free(source); + return 1; + } + + RavaSemanticAnalyzer_t *analyzer = rava_semantic_analyzer_create(); + if (!rava_semantic_analyze(analyzer, ast)) { + free(source); + return 1; + } + + RavaIRGenerator_t *ir_gen = rava_ir_generator_create(analyzer); + RavaProgram_t *program = rava_ir_generate(ir_gen, ast); + if (!program) { + free(source); + return 1; + } + + RavaVM_t *vm = rava_vm_create(program); + if (!rava_vm_execute(vm, "PascalTriangle", "main")) { + printf("Runtime error\n"); + rava_vm_destroy(vm); + free(source); + return 1; + } + + printf("\nCleaning up VM...\n"); + fflush(stdout); + rava_vm_destroy(vm); + + printf("Cleaning up program...\n"); + fflush(stdout); + rava_program_destroy(program); + + printf("Cleaning up IR generator...\n"); + fflush(stdout); + rava_ir_generator_destroy(ir_gen); + + printf("Cleaning up analyzer...\n"); + fflush(stdout); + rava_semantic_analyzer_destroy(analyzer); + + printf("Cleaning up AST...\n"); + fflush(stdout); + rava_ast_node_destroy(ast); + + printf("Cleaning up parser...\n"); + fflush(stdout); + rava_parser_destroy(parser); + + printf("Cleaning up lexer...\n"); + fflush(stdout); + rava_lexer_destroy(lexer); + + printf("Freeing source...\n"); + fflush(stdout); + free(source); + + printf("Done!\n"); + return 0; +} diff --git a/tests/test_println.c b/tests/test_println.c new file mode 100644 index 0000000..08dc115 --- /dev/null +++ b/tests/test_println.c @@ -0,0 +1,72 @@ +#include "../lexer/lexer.h" +#include "../parser/parser.h" +#include "../semantic/semantic.h" +#include "../ir/ir.h" +#include "../ir/ir_gen.h" +#include "../runtime/runtime.h" +#include +#include + +int main() { + const char *source = + "public class Test {\n" + " public static int main() {\n" + " System.out.println(42);\n" + " System.out.println(100);\n" + " int x = 10;\n" + " int y = 20;\n" + " System.out.println(x + y);\n" + " return 0;\n" + " }\n" + "}\n"; + + printf("Source:\n%s\n", source); + + RavaLexer_t *lexer = rava_lexer_create(source); + RavaParser_t *parser = rava_parser_create(lexer); + RavaASTNode_t *ast = rava_parser_parse(parser); + + if (parser->had_error) { + printf("Parse error: %s\n", parser->error_message); + return 1; + } + + RavaSemanticAnalyzer_t *analyzer = rava_semantic_analyzer_create(); + if (!rava_semantic_analyze(analyzer, ast)) { + printf("Semantic error: %s\n", analyzer->error_message); + return 1; + } + + RavaIRGenerator_t *ir_gen = rava_ir_generator_create(analyzer); + RavaProgram_t *program = rava_ir_generate(ir_gen, ast); + + if (!program) { + printf("IR generation failed\n"); + return 1; + } + + printf("\nGenerated IR:\n"); + rava_ir_print(program); + + RavaVM_t *vm = rava_vm_create(program); + printf("\nExecuting Test.main()...\n"); + printf("Output:\n"); + + if (!rava_vm_execute(vm, "Test", "main")) { + printf("Runtime error: %s\n", vm->error_message); + rava_vm_destroy(vm); + return 1; + } + + printf("\n✅ Execution completed successfully!\n"); + + rava_vm_destroy(vm); + rava_program_destroy(program); + rava_ir_generator_destroy(ir_gen); + rava_semantic_analyzer_destroy(analyzer); + rava_ast_node_destroy(ast); + rava_parser_destroy(parser); + rava_lexer_destroy(lexer); + + return 0; +} diff --git a/tests/test_runtime.c b/tests/test_runtime.c new file mode 100644 index 0000000..22be1e2 --- /dev/null +++ b/tests/test_runtime.c @@ -0,0 +1,172 @@ +#include "../lexer/lexer.h" +#include "../parser/parser.h" +#include "../semantic/semantic.h" +#include "../ir/ir.h" +#include "../ir/ir_gen.h" +#include "../runtime/runtime.h" +#include +#include + +static bool run_test(const char *name, const char *source, const char *class_name, + const char *method_name, int expected_result) { + printf("\n========================================\n"); + printf("Test: %s\n", name); + printf("========================================\n"); + printf("Source:\n%s\n", source); + + RavaLexer_t *lexer = rava_lexer_create(source); + RavaParser_t *parser = rava_parser_create(lexer); + RavaASTNode_t *ast = rava_parser_parse(parser); + + if (parser->had_error) { + printf("❌ Parse error: %s\n", parser->error_message); + return false; + } + + RavaSemanticAnalyzer_t *analyzer = rava_semantic_analyzer_create(); + if (!rava_semantic_analyze(analyzer, ast)) { + printf("❌ Semantic error: %s\n", analyzer->error_message); + return false; + } + + RavaIRGenerator_t *ir_gen = rava_ir_generator_create(analyzer); + RavaProgram_t *program = rava_ir_generate(ir_gen, ast); + + if (!program) { + printf("❌ IR generation failed\n"); + return false; + } + + printf("\nGenerated IR:\n"); + rava_ir_print(program); + + RavaVM_t *vm = rava_vm_create(program); + printf("\nExecuting %s.%s()...\n", class_name, method_name); + + if (!rava_vm_execute(vm, class_name, method_name)) { + printf("❌ Runtime error: %s\n", vm->error_message); + rava_vm_destroy(vm); + return false; + } + + RavaValue_t result = rava_vm_get_result(vm); + int32_t result_int = rava_value_as_int(result); + + printf("Result: %d\n", result_int); + + bool success = (result_int == expected_result); + if (success) { + printf("✅ PASS (expected %d, got %d)\n", expected_result, result_int); + } else { + printf("❌ FAIL (expected %d, got %d)\n", expected_result, result_int); + } + + rava_vm_destroy(vm); + rava_program_destroy(program); + rava_ir_generator_destroy(ir_gen); + rava_semantic_analyzer_destroy(analyzer); + rava_ast_node_destroy(ast); + rava_parser_destroy(parser); + rava_lexer_destroy(lexer); + + return success; +} + +int main() { + printf("================================================================================\n"); + printf("RAVA JAVA INTERPRETER - END-TO-END RUNTIME TESTS\n"); + printf("================================================================================\n"); + + int passed = 0; + int total = 0; + + total++; + if (run_test("Simple Addition", + "public class Test {\n" + " public static int add() {\n" + " int a = 10;\n" + " int b = 20;\n" + " int result = a + b;\n" + " return result;\n" + " }\n" + "}\n", + "Test", "add", 30)) { + passed++; + } + + total++; + if (run_test("Multiple Operations", + "public class Test {\n" + " public static int compute() {\n" + " int a = 5;\n" + " int b = 3;\n" + " int sum = a + b;\n" + " int product = a * b;\n" + " int result = sum + product;\n" + " return result;\n" + " }\n" + "}\n", + "Test", "compute", 23)) { + passed++; + } + + total++; + if (run_test("Conditional (True Branch)", + "public class Test {\n" + " public static int conditional() {\n" + " int x = 10;\n" + " int result = 0;\n" + " if (x > 5) {\n" + " result = 100;\n" + " }\n" + " return result;\n" + " }\n" + "}\n", + "Test", "conditional", 100)) { + passed++; + } + + total++; + if (run_test("Conditional (False Branch)", + "public class Test {\n" + " public static int conditional() {\n" + " int x = 3;\n" + " int result = 0;\n" + " if (x > 5) {\n" + " result = 100;\n" + " }\n" + " return result;\n" + " }\n" + "}\n", + "Test", "conditional", 0)) { + passed++; + } + + total++; + if (run_test("Factorial (Recursive)", + "public class Test {\n" + " public static int factorial(int n) {\n" + " if (n <= 1) {\n" + " return 1;\n" + " }\n" + " return n * factorial(n - 1);\n" + " }\n" + "}\n", + "Test", "factorial", 1)) { + passed++; + } + + printf("\n================================================================================\n"); + printf("TEST SUMMARY\n"); + printf("================================================================================\n"); + printf("Passed: %d/%d\n", passed, total); + printf("Failed: %d/%d\n", total - passed, total); + + if (passed == total) { + printf("\n🎉 ALL TESTS PASSED! The Rava interpreter is executing Java code!\n"); + } else { + printf("\n⚠️ Some tests failed.\n"); + } + + return (passed == total) ? 0 : 1; +} diff --git a/tests/test_runtime.o b/tests/test_runtime.o new file mode 100644 index 0000000..66875fc Binary files /dev/null and b/tests/test_runtime.o differ diff --git a/tests/test_semantic.c b/tests/test_semantic.c new file mode 100644 index 0000000..2bf912a --- /dev/null +++ b/tests/test_semantic.c @@ -0,0 +1,74 @@ +#include "../lexer/lexer.h" +#include "../parser/parser.h" +#include "../semantic/semantic.h" +#include +#include + +int main() { + const char *source = + "public class Test {\n" + " public static int calculate(int x, int y) {\n" + " int sum = x + y;\n" + " int product = x * y;\n" + " boolean isPositive = sum > 0;\n" + " if (isPositive) {\n" + " return sum;\n" + " }\n" + " return product;\n" + " }\n" + "\n" + " public static void main(int argc) {\n" + " int result = calculate(10, 20);\n" + " int doubled = result * 2;\n" + " }\n" + "}\n"; + + printf("Source code:\n%s\n", source); + printf("\nSemantic Analysis:\n"); + printf("================================================================================\n\n"); + + RavaLexer_t *lexer = rava_lexer_create(source); + RavaParser_t *parser = rava_parser_create(lexer); + RavaASTNode_t *ast = rava_parser_parse(parser); + + if (parser->had_error) { + printf("Parse error: %s\n", parser->error_message ? parser->error_message : "Unknown error"); + rava_parser_destroy(parser); + rava_lexer_destroy(lexer); + return 1; + } + + RavaSemanticAnalyzer_t *analyzer = rava_semantic_analyzer_create(); + + bool success = rava_semantic_analyze(analyzer, ast); + + if (success) { + printf("✓ Semantic analysis passed successfully!\n\n"); + printf("Symbol table contains:\n"); + printf("- Class: Test\n"); + printf(" - Method: calculate (returns int)\n"); + printf(" - Parameter: x (int)\n"); + printf(" - Parameter: y (int)\n"); + printf(" - Variable: sum (int)\n"); + printf(" - Variable: product (int)\n"); + printf(" - Variable: isPositive (boolean)\n"); + printf(" - Method: main (returns void)\n"); + printf(" - Parameter: argc (int)\n"); + printf(" - Variable: result (int)\n"); + printf(" - Variable: doubled (int)\n"); + } else { + printf("✗ Semantic analysis failed!\n"); + if (analyzer->error_message) { + printf("Error: %s\n", analyzer->error_message); + } + printf("Total errors: %d\n", analyzer->error_count); + } + + rava_semantic_analyzer_destroy(analyzer); + rava_ast_node_destroy(ast); + rava_parser_destroy(parser); + rava_lexer_destroy(lexer); + + printf("\nSemantic test completed!\n"); + return success ? 0 : 1; +} diff --git a/tests/test_semantic.o b/tests/test_semantic.o new file mode 100644 index 0000000..3a02b27 Binary files /dev/null and b/tests/test_semantic.o differ diff --git a/tests/test_shortcircuit.c b/tests/test_shortcircuit.c new file mode 100644 index 0000000..8a5feab --- /dev/null +++ b/tests/test_shortcircuit.c @@ -0,0 +1,165 @@ +#include "../lexer/lexer.h" +#include "../parser/parser.h" +#include "../semantic/semantic.h" +#include "../ir/ir.h" +#include "../ir/ir_gen.h" +#include "../runtime/runtime.h" +#include +#include +#include + +static int test_count = 0; +static int pass_count = 0; + +static void run_test_int(const char* name, const char* source, int expected) { + test_count++; + + RavaLexer_t* lexer = rava_lexer_create(source); + RavaParser_t* parser = rava_parser_create(lexer); + RavaASTNode_t* ast = rava_parser_parse(parser); + + if (!ast || parser->had_error) { + printf("FAIL: %s - Parse error: %s\n", name, parser->error_message ? parser->error_message : "unknown"); + rava_parser_destroy(parser); + rava_lexer_destroy(lexer); + return; + } + + RavaSemanticAnalyzer_t* analyzer = rava_semantic_analyzer_create(); + rava_semantic_analyze(analyzer, ast); + + RavaIRGenerator_t* ir_gen = rava_ir_generator_create(analyzer); + RavaProgram_t* program = rava_ir_generate(ir_gen, ast); + + RavaVM_t* vm = rava_vm_create(program); + + if (!rava_vm_execute(vm, "Test", "main")) { + printf("FAIL: %s - Runtime error: %s\n", name, vm->error_message ? vm->error_message : "unknown"); + rava_vm_destroy(vm); + rava_program_destroy(program); + rava_ir_generator_destroy(ir_gen); + rava_semantic_analyzer_destroy(analyzer); + rava_ast_node_destroy(ast); + rava_parser_destroy(parser); + rava_lexer_destroy(lexer); + return; + } + + RavaValue_t result = rava_vm_get_result(vm); + int32_t result_int = rava_value_as_int(result); + + if (result_int == expected) { + printf("PASS: %s (result=%d)\n", name, result_int); + pass_count++; + } else { + printf("FAIL: %s (expected=%d, got=%d)\n", name, expected, result_int); + } + + rava_vm_destroy(vm); + rava_program_destroy(program); + rava_ir_generator_destroy(ir_gen); + rava_semantic_analyzer_destroy(analyzer); + rava_ast_node_destroy(ast); + rava_parser_destroy(parser); + rava_lexer_destroy(lexer); +} + +int main(void) { + printf("=== Short-Circuit Evaluation Tests ===\n\n"); + + run_test_int("AND true && true", + "public class Test {\n" + " public static int main() {\n" + " if (true && true) { return 1; }\n" + " return 0;\n" + " }\n" + "}\n", 1); + + run_test_int("AND true && false", + "public class Test {\n" + " public static int main() {\n" + " if (true && false) { return 1; }\n" + " return 0;\n" + " }\n" + "}\n", 0); + + run_test_int("AND false && true", + "public class Test {\n" + " public static int main() {\n" + " if (false && true) { return 1; }\n" + " return 0;\n" + " }\n" + "}\n", 0); + + run_test_int("OR false || true", + "public class Test {\n" + " public static int main() {\n" + " if (false || true) { return 1; }\n" + " return 0;\n" + " }\n" + "}\n", 1); + + run_test_int("OR true || false", + "public class Test {\n" + " public static int main() {\n" + " if (true || false) { return 1; }\n" + " return 0;\n" + " }\n" + "}\n", 1); + + run_test_int("OR false || false", + "public class Test {\n" + " public static int main() {\n" + " if (false || false) { return 1; }\n" + " return 0;\n" + " }\n" + "}\n", 0); + + run_test_int("short-circuit AND skips second", + "public class Test {\n" + " public static int x = 0;\n" + " public static boolean incAndReturn() {\n" + " x = x + 1;\n" + " return true;\n" + " }\n" + " public static int main() {\n" + " if (false && incAndReturn()) { }\n" + " return x;\n" + " }\n" + "}\n", 0); + + run_test_int("short-circuit OR skips second", + "public class Test {\n" + " public static int x = 0;\n" + " public static boolean incAndReturn() {\n" + " x = x + 1;\n" + " return false;\n" + " }\n" + " public static int main() {\n" + " if (true || incAndReturn()) { }\n" + " return x;\n" + " }\n" + "}\n", 0); + + run_test_int("AND with comparison", + "public class Test {\n" + " public static int main() {\n" + " int x = 5;\n" + " if (x > 0 && x < 10) { return 1; }\n" + " return 0;\n" + " }\n" + "}\n", 1); + + run_test_int("OR with comparison", + "public class Test {\n" + " public static int main() {\n" + " int x = 15;\n" + " if (x < 0 || x > 10) { return 1; }\n" + " return 0;\n" + " }\n" + "}\n", 1); + + printf("\n=== Results: %d/%d tests passed ===\n", pass_count, test_count); + + return (pass_count == test_count) ? 0 : 1; +} diff --git a/tests/test_shortcircuit.o b/tests/test_shortcircuit.o new file mode 100644 index 0000000..6fb9637 Binary files /dev/null and b/tests/test_shortcircuit.o differ diff --git a/tests/test_static.c b/tests/test_static.c new file mode 100644 index 0000000..8276cc8 --- /dev/null +++ b/tests/test_static.c @@ -0,0 +1,135 @@ +#include "../lexer/lexer.h" +#include "../parser/parser.h" +#include "../semantic/semantic.h" +#include "../ir/ir.h" +#include "../ir/ir_gen.h" +#include "../runtime/runtime.h" +#include +#include +#include + +static int test_count = 0; +static int pass_count = 0; + +static void run_test_int(const char* name, const char* source, int expected) { + test_count++; + + RavaLexer_t* lexer = rava_lexer_create(source); + RavaParser_t* parser = rava_parser_create(lexer); + RavaASTNode_t* ast = rava_parser_parse(parser); + + if (!ast || parser->had_error) { + printf("FAIL: %s - Parse error: %s\n", name, parser->error_message ? parser->error_message : "unknown"); + rava_parser_destroy(parser); + rava_lexer_destroy(lexer); + return; + } + + RavaSemanticAnalyzer_t* analyzer = rava_semantic_analyzer_create(); + rava_semantic_analyze(analyzer, ast); + + RavaIRGenerator_t* ir_gen = rava_ir_generator_create(analyzer); + RavaProgram_t* program = rava_ir_generate(ir_gen, ast); + + RavaVM_t* vm = rava_vm_create(program); + + if (!rava_vm_execute(vm, "Test", "main")) { + printf("FAIL: %s - Runtime error: %s\n", name, vm->error_message ? vm->error_message : "unknown"); + rava_vm_destroy(vm); + rava_program_destroy(program); + rava_ir_generator_destroy(ir_gen); + rava_semantic_analyzer_destroy(analyzer); + rava_ast_node_destroy(ast); + rava_parser_destroy(parser); + rava_lexer_destroy(lexer); + return; + } + + RavaValue_t result = rava_vm_get_result(vm); + int32_t result_int = rava_value_as_int(result); + + if (result_int == expected) { + printf("PASS: %s (result=%d)\n", name, result_int); + pass_count++; + } else { + printf("FAIL: %s (expected=%d, got=%d)\n", name, expected, result_int); + } + + rava_vm_destroy(vm); + rava_program_destroy(program); + rava_ir_generator_destroy(ir_gen); + rava_semantic_analyzer_destroy(analyzer); + rava_ast_node_destroy(ast); + rava_parser_destroy(parser); + rava_lexer_destroy(lexer); +} + +int main(void) { + printf("=== Static Field Tests ===\n\n"); + + run_test_int("static field basic read/write", + "class Counter {\n" + " static int count;\n" + "}\n" + "public class Test {\n" + " public static int main() {\n" + " Counter.count = 42;\n" + " return Counter.count;\n" + " }\n" + "}\n", 42); + + run_test_int("static field increment", + "class Counter {\n" + " static int count;\n" + "}\n" + "public class Test {\n" + " public static int main() {\n" + " Counter.count = 10;\n" + " Counter.count = Counter.count + 5;\n" + " return Counter.count;\n" + " }\n" + "}\n", 15); + + run_test_int("static field in same class", + "public class Test {\n" + " static int value;\n" + " public static int main() {\n" + " Test.value = 100;\n" + " return Test.value;\n" + " }\n" + "}\n", 100); + + run_test_int("multiple static fields", + "class Data {\n" + " static int a;\n" + " static int b;\n" + " static int c;\n" + "}\n" + "public class Test {\n" + " public static int main() {\n" + " Data.a = 10;\n" + " Data.b = 20;\n" + " Data.c = 30;\n" + " return Data.a + Data.b + Data.c;\n" + " }\n" + "}\n", 60); + + run_test_int("static field across classes", + "class ClassA {\n" + " static int val;\n" + "}\n" + "class ClassB {\n" + " static int val;\n" + "}\n" + "public class Test {\n" + " public static int main() {\n" + " ClassA.val = 100;\n" + " ClassB.val = 200;\n" + " return ClassA.val + ClassB.val;\n" + " }\n" + "}\n", 300); + + printf("\n=== Results: %d/%d tests passed ===\n", pass_count, test_count); + + return (pass_count == test_count) ? 0 : 1; +} diff --git a/tests/test_static.o b/tests/test_static.o new file mode 100644 index 0000000..cd62a7f Binary files /dev/null and b/tests/test_static.o differ diff --git a/tests/test_static_field_parse.c b/tests/test_static_field_parse.c new file mode 100644 index 0000000..c686e1a --- /dev/null +++ b/tests/test_static_field_parse.c @@ -0,0 +1,40 @@ +#include "../lexer/lexer.h" +#include "../parser/parser.h" +#include +#include + +static char* read_file(const char *filename) { + FILE *file = fopen(filename, "r"); + if (!file) return NULL; + fseek(file, 0, SEEK_END); + long size = ftell(file); + fseek(file, 0, SEEK_SET); + char *content = malloc(size + 1); + size_t read_bytes = fread(content, 1, size, file); (void)read_bytes; + content[size] = '\0'; + fclose(file); + return content; +} + +int main() { + char *source = read_file("examples/11_TowerOfHanoiStatic.java"); + if (!source) { + printf("Failed to read file\n"); + return 1; + } + + RavaLexer_t *lexer = rava_lexer_create(source); + RavaParser_t *parser = rava_parser_create(lexer); + rava_parser_parse(parser); + + if (parser->had_error) { + printf("Parse error: %s\n", parser->error_message); + free(source); + return 1; + } + + printf("Parsed successfully!\n"); + + free(source); + return 0; +} diff --git a/tests/test_static_init.c b/tests/test_static_init.c new file mode 100644 index 0000000..4886403 --- /dev/null +++ b/tests/test_static_init.c @@ -0,0 +1,134 @@ +#include "../lexer/lexer.h" +#include "../parser/parser.h" +#include "../semantic/semantic.h" +#include "../ir/ir.h" +#include "../ir/ir_gen.h" +#include "../runtime/runtime.h" +#include +#include +#include + +static int test_count = 0; +static int pass_count = 0; + +static void run_test_int(const char* name, const char* source, int expected) { + test_count++; + + RavaLexer_t* lexer = rava_lexer_create(source); + RavaParser_t* parser = rava_parser_create(lexer); + RavaASTNode_t* ast = rava_parser_parse(parser); + + if (!ast || parser->had_error) { + printf("FAIL: %s - Parse error: %s\n", name, parser->error_message ? parser->error_message : "unknown"); + rava_parser_destroy(parser); + rava_lexer_destroy(lexer); + return; + } + + RavaSemanticAnalyzer_t* analyzer = rava_semantic_analyzer_create(); + rava_semantic_analyze(analyzer, ast); + + RavaIRGenerator_t* ir_gen = rava_ir_generator_create(analyzer); + RavaProgram_t* program = rava_ir_generate(ir_gen, ast); + + RavaVM_t* vm = rava_vm_create(program); + + if (!rava_vm_execute(vm, "Test", "main")) { + printf("FAIL: %s - Runtime error: %s\n", name, vm->error_message ? vm->error_message : "unknown"); + rava_vm_destroy(vm); + rava_program_destroy(program); + rava_ir_generator_destroy(ir_gen); + rava_semantic_analyzer_destroy(analyzer); + rava_ast_node_destroy(ast); + rava_parser_destroy(parser); + rava_lexer_destroy(lexer); + return; + } + + RavaValue_t result = rava_vm_get_result(vm); + int32_t result_int = rava_value_as_int(result); + + if (result_int == expected) { + printf("PASS: %s (result=%d)\n", name, result_int); + pass_count++; + } else { + printf("FAIL: %s (expected=%d, got=%d)\n", name, expected, result_int); + } + + rava_vm_destroy(vm); + rava_program_destroy(program); + rava_ir_generator_destroy(ir_gen); + rava_semantic_analyzer_destroy(analyzer); + rava_ast_node_destroy(ast); + rava_parser_destroy(parser); + rava_lexer_destroy(lexer); +} + +int main(void) { + printf("=== Static Field Initializer Tests ===\n\n"); + + run_test_int("static field with literal initializer", + "public class Test {\n" + " static int v = 42;\n" + " public static int main() {\n" + " return Test.v;\n" + " }\n" + "}\n", 42); + + run_test_int("static field with expression initializer", + "public class Test {\n" + " static int v = 10 + 32;\n" + " public static int main() {\n" + " return Test.v;\n" + " }\n" + "}\n", 42); + + run_test_int("multiple static fields with initializers", + "public class Test {\n" + " static int a = 10;\n" + " static int b = 20;\n" + " static int c = 12;\n" + " public static int main() {\n" + " return Test.a + Test.b + Test.c;\n" + " }\n" + "}\n", 42); + + run_test_int("static field initializer can be overwritten", + "public class Test {\n" + " static int v = 10;\n" + " public static int main() {\n" + " Test.v = 42;\n" + " return Test.v;\n" + " }\n" + "}\n", 42); + + run_test_int("static field used in expression", + "public class Test {\n" + " static int base = 40;\n" + " public static int main() {\n" + " return Test.base + 2;\n" + " }\n" + "}\n", 42); + + run_test_int("static field in different class", + "class Data {\n" + " static int value = 42;\n" + "}\n" + "public class Test {\n" + " public static int main() {\n" + " return Data.value;\n" + " }\n" + "}\n", 42); + + run_test_int("static field with negative initializer", + "public class Test {\n" + " static int v = 100 - 58;\n" + " public static int main() {\n" + " return Test.v;\n" + " }\n" + "}\n", 42); + + printf("\n=== Results: %d/%d tests passed ===\n", pass_count, test_count); + + return (pass_count == test_count) ? 0 : 1; +} diff --git a/tests/test_static_init.o b/tests/test_static_init.o new file mode 100644 index 0000000..ece6599 Binary files /dev/null and b/tests/test_static_init.o differ diff --git a/tests/test_string_methods.c b/tests/test_string_methods.c new file mode 100644 index 0000000..49220fc --- /dev/null +++ b/tests/test_string_methods.c @@ -0,0 +1,253 @@ +#include "../lexer/lexer.h" +#include "../parser/parser.h" +#include "../semantic/semantic.h" +#include "../ir/ir.h" +#include "../ir/ir_gen.h" +#include "../runtime/runtime.h" +#include +#include +#include + +static int test_count = 0; +static int pass_count = 0; + +static void run_test_int(const char* name, const char* source, int expected) { + test_count++; + + RavaLexer_t* lexer = rava_lexer_create(source); + RavaParser_t* parser = rava_parser_create(lexer); + RavaASTNode_t* ast = rava_parser_parse(parser); + + if (!ast || parser->had_error) { + printf("FAIL: %s - Parse error: %s\n", name, parser->error_message ? parser->error_message : "unknown"); + rava_parser_destroy(parser); + rava_lexer_destroy(lexer); + return; + } + + RavaSemanticAnalyzer_t* analyzer = rava_semantic_analyzer_create(); + rava_semantic_analyze(analyzer, ast); + + RavaIRGenerator_t* ir_gen = rava_ir_generator_create(analyzer); + RavaProgram_t* program = rava_ir_generate(ir_gen, ast); + + RavaVM_t* vm = rava_vm_create(program); + + if (!rava_vm_execute(vm, "Test", "main")) { + printf("FAIL: %s - Runtime error: %s\n", name, vm->error_message ? vm->error_message : "unknown"); + rava_vm_destroy(vm); + rava_program_destroy(program); + rava_ir_generator_destroy(ir_gen); + rava_semantic_analyzer_destroy(analyzer); + rava_ast_node_destroy(ast); + rava_parser_destroy(parser); + rava_lexer_destroy(lexer); + return; + } + + RavaValue_t result = rava_vm_get_result(vm); + int32_t result_int = rava_value_as_int(result); + + if (result_int == expected) { + printf("PASS: %s (result=%d)\n", name, result_int); + pass_count++; + } else { + printf("FAIL: %s (expected=%d, got=%d)\n", name, expected, result_int); + } + + rava_vm_destroy(vm); + rava_program_destroy(program); + rava_ir_generator_destroy(ir_gen); + rava_semantic_analyzer_destroy(analyzer); + rava_ast_node_destroy(ast); + rava_parser_destroy(parser); + rava_lexer_destroy(lexer); +} + +int main(void) { + printf("=== String Methods Tests ===\n\n"); + + run_test_int("String.length", + "public class Test {\n" + " public static int main() {\n" + " String s = \"Hello\";\n" + " return s.length();\n" + " }\n" + "}\n", 5); + + run_test_int("String.charAt", + "public class Test {\n" + " public static int main() {\n" + " String s = \"Hello\";\n" + " return s.charAt(1);\n" + " }\n" + "}\n", 'e'); + + run_test_int("String.substring", + "public class Test {\n" + " public static int main() {\n" + " String s = \"Hello World\";\n" + " String sub = s.substring(0, 5);\n" + " return sub.length();\n" + " }\n" + "}\n", 5); + + run_test_int("String.equals true", + "public class Test {\n" + " public static int main() {\n" + " String a = \"test\";\n" + " String b = \"test\";\n" + " if (a.equals(b)) { return 1; }\n" + " return 0;\n" + " }\n" + "}\n", 1); + + run_test_int("String.equals false", + "public class Test {\n" + " public static int main() {\n" + " String a = \"test\";\n" + " String b = \"other\";\n" + " if (a.equals(b)) { return 1; }\n" + " return 0;\n" + " }\n" + "}\n", 0); + + run_test_int("String.compareTo equal", + "public class Test {\n" + " public static int main() {\n" + " String a = \"abc\";\n" + " String b = \"abc\";\n" + " return a.compareTo(b);\n" + " }\n" + "}\n", 0); + + run_test_int("String.compareTo less", + "public class Test {\n" + " public static int main() {\n" + " String a = \"abc\";\n" + " String b = \"abd\";\n" + " if (a.compareTo(b) < 0) { return 1; }\n" + " return 0;\n" + " }\n" + "}\n", 1); + + run_test_int("String.compareTo greater", + "public class Test {\n" + " public static int main() {\n" + " String a = \"abd\";\n" + " String b = \"abc\";\n" + " if (a.compareTo(b) > 0) { return 1; }\n" + " return 0;\n" + " }\n" + "}\n", 1); + + run_test_int("String.indexOf found", + "public class Test {\n" + " public static int main() {\n" + " String s = \"Hello World\";\n" + " return s.indexOf(\"World\");\n" + " }\n" + "}\n", 6); + + run_test_int("String.indexOf not found", + "public class Test {\n" + " public static int main() {\n" + " String s = \"Hello World\";\n" + " return s.indexOf(\"xyz\");\n" + " }\n" + "}\n", -1); + + run_test_int("String.contains true", + "public class Test {\n" + " public static int main() {\n" + " String s = \"Hello World\";\n" + " if (s.contains(\"World\")) { return 1; }\n" + " return 0;\n" + " }\n" + "}\n", 1); + + run_test_int("String.contains false", + "public class Test {\n" + " public static int main() {\n" + " String s = \"Hello World\";\n" + " if (s.contains(\"xyz\")) { return 1; }\n" + " return 0;\n" + " }\n" + "}\n", 0); + + run_test_int("String.startsWith true", + "public class Test {\n" + " public static int main() {\n" + " String s = \"Hello World\";\n" + " if (s.startsWith(\"Hello\")) { return 1; }\n" + " return 0;\n" + " }\n" + "}\n", 1); + + run_test_int("String.startsWith false", + "public class Test {\n" + " public static int main() {\n" + " String s = \"Hello World\";\n" + " if (s.startsWith(\"World\")) { return 1; }\n" + " return 0;\n" + " }\n" + "}\n", 0); + + run_test_int("String.endsWith true", + "public class Test {\n" + " public static int main() {\n" + " String s = \"Hello World\";\n" + " if (s.endsWith(\"World\")) { return 1; }\n" + " return 0;\n" + " }\n" + "}\n", 1); + + run_test_int("String.endsWith false", + "public class Test {\n" + " public static int main() {\n" + " String s = \"Hello World\";\n" + " if (s.endsWith(\"Hello\")) { return 1; }\n" + " return 0;\n" + " }\n" + "}\n", 0); + + run_test_int("String.toLowerCase length", + "public class Test {\n" + " public static int main() {\n" + " String s = \"HELLO\";\n" + " String lower = s.toLowerCase();\n" + " return lower.length();\n" + " }\n" + "}\n", 5); + + run_test_int("String.toLowerCase charAt", + "public class Test {\n" + " public static int main() {\n" + " String s = \"HELLO\";\n" + " String lower = s.toLowerCase();\n" + " return lower.charAt(0);\n" + " }\n" + "}\n", 'h'); + + run_test_int("String.toUpperCase charAt", + "public class Test {\n" + " public static int main() {\n" + " String s = \"hello\";\n" + " String upper = s.toUpperCase();\n" + " return upper.charAt(0);\n" + " }\n" + "}\n", 'H'); + + run_test_int("String.trim length", + "public class Test {\n" + " public static int main() {\n" + " String s = \" Hello \";\n" + " String trimmed = s.trim();\n" + " return trimmed.length();\n" + " }\n" + "}\n", 5); + + printf("\n=== Results: %d/%d tests passed ===\n", pass_count, test_count); + + return (pass_count == test_count) ? 0 : 1; +} diff --git a/tests/test_string_methods.o b/tests/test_string_methods.o new file mode 100644 index 0000000..dbada23 Binary files /dev/null and b/tests/test_string_methods.o differ diff --git a/tests/test_strings.c b/tests/test_strings.c new file mode 100644 index 0000000..e9dc9a2 --- /dev/null +++ b/tests/test_strings.c @@ -0,0 +1,77 @@ +#include "../lexer/lexer.h" +#include "../parser/parser.h" +#include "../semantic/semantic.h" +#include "../ir/ir.h" +#include "../ir/ir_gen.h" +#include "../runtime/runtime.h" +#include +#include +#include + +static char* read_file(const char *filename) { + FILE *file = fopen(filename, "r"); + if (!file) return NULL; + fseek(file, 0, SEEK_END); + long size = ftell(file); + fseek(file, 0, SEEK_SET); + char *content = malloc(size + 1); + size_t read_bytes = fread(content, 1, size, file); + content[read_bytes] = '\0'; + fclose(file); + return content; +} + +int main() { + char *source = read_file("examples/12_StringBasics.java"); + if (!source) { + printf("Failed to read file\n"); + return 1; + } + + RavaLexer_t *lexer = rava_lexer_create(source); + RavaParser_t *parser = rava_parser_create(lexer); + RavaASTNode_t *ast = rava_parser_parse(parser); + + if (parser->had_error) { + printf("Parse error: %s\n", parser->error_message); + free(source); + return 1; + } + + printf("Parse: OK\n"); + + RavaSemanticAnalyzer_t *analyzer = rava_semantic_analyzer_create(); + if (!rava_semantic_analyze(analyzer, ast)) { + printf("Semantic error: %s\n", analyzer->error_message); + free(source); + return 1; + } + + printf("Semantic: OK\n"); + + RavaIRGenerator_t *ir_gen = rava_ir_generator_create(analyzer); + RavaProgram_t *program = rava_ir_generate(ir_gen, ast); + + if (!program) { + printf("IR generation failed\n"); + free(source); + return 1; + } + + printf("IR Gen: OK\n"); + printf("\nOutput:\n"); + + RavaVM_t *vm = rava_vm_create(program); + if (!rava_vm_execute(vm, "StringBasics", "main")) { + printf("Runtime error: %s\n", vm->error_message); + rava_vm_destroy(vm); + free(source); + return 1; + } + + printf("\nExecution: OK\n"); + + rava_vm_destroy(vm); + free(source); + return 0; +} diff --git a/tests/test_strings.o b/tests/test_strings.o new file mode 100644 index 0000000..650f826 Binary files /dev/null and b/tests/test_strings.o differ diff --git a/tests/test_super.c b/tests/test_super.c new file mode 100644 index 0000000..5a61309 --- /dev/null +++ b/tests/test_super.c @@ -0,0 +1,132 @@ +#include "../lexer/lexer.h" +#include "../parser/parser.h" +#include "../semantic/semantic.h" +#include "../ir/ir.h" +#include "../ir/ir_gen.h" +#include "../runtime/runtime.h" +#include +#include +#include + +static int test_count = 0; +static int pass_count = 0; + +static void run_test_int(const char* name, const char* source, int expected) { + test_count++; + + RavaLexer_t* lexer = rava_lexer_create(source); + RavaParser_t* parser = rava_parser_create(lexer); + RavaASTNode_t* ast = rava_parser_parse(parser); + + if (!ast || parser->had_error) { + printf("FAIL: %s - Parse error: %s\n", name, parser->error_message ? parser->error_message : "unknown"); + rava_parser_destroy(parser); + rava_lexer_destroy(lexer); + return; + } + + RavaSemanticAnalyzer_t* analyzer = rava_semantic_analyzer_create(); + rava_semantic_analyze(analyzer, ast); + + RavaIRGenerator_t* ir_gen = rava_ir_generator_create(analyzer); + RavaProgram_t* program = rava_ir_generate(ir_gen, ast); + + RavaVM_t* vm = rava_vm_create(program); + + if (!rava_vm_execute(vm, "Test", "main")) { + printf("FAIL: %s - Runtime error: %s\n", name, vm->error_message ? vm->error_message : "unknown"); + rava_vm_destroy(vm); + rava_program_destroy(program); + rava_ir_generator_destroy(ir_gen); + rava_semantic_analyzer_destroy(analyzer); + rava_ast_node_destroy(ast); + rava_parser_destroy(parser); + rava_lexer_destroy(lexer); + return; + } + + RavaValue_t result = rava_vm_get_result(vm); + int32_t result_int = rava_value_as_int(result); + + if (result_int == expected) { + printf("PASS: %s (result=%d)\n", name, result_int); + pass_count++; + } else { + printf("FAIL: %s (expected=%d, got=%d)\n", name, expected, result_int); + } + + rava_vm_destroy(vm); + rava_program_destroy(program); + rava_ir_generator_destroy(ir_gen); + rava_semantic_analyzer_destroy(analyzer); + rava_ast_node_destroy(ast); + rava_parser_destroy(parser); + rava_lexer_destroy(lexer); +} + +int main(void) { + printf("=== Super Keyword Tests ===\n\n"); + + run_test_int("super.method() basic", + "class Parent {\n" + " int getValue() {\n" + " return 10;\n" + " }\n" + "}\n" + "class Child extends Parent {\n" + " int getValue() {\n" + " return super.getValue() + 5;\n" + " }\n" + "}\n" + "public class Test {\n" + " public static int main() {\n" + " Child c = new Child();\n" + " return c.getValue();\n" + " }\n" + "}\n", 15); + + run_test_int("super.method() with args", + "class Parent {\n" + " int add(int a, int b) {\n" + " return a + b;\n" + " }\n" + "}\n" + "class Child extends Parent {\n" + " int add(int a, int b) {\n" + " return super.add(a, b) * 2;\n" + " }\n" + "}\n" + "public class Test {\n" + " public static int main() {\n" + " Child c = new Child();\n" + " return c.add(3, 4);\n" + " }\n" + "}\n", 14); + + run_test_int("super.method() chain", + "class GrandParent {\n" + " int getValue() {\n" + " return 100;\n" + " }\n" + "}\n" + "class Parent extends GrandParent {\n" + " int getValue() {\n" + " return super.getValue() + 10;\n" + " }\n" + "}\n" + "class Child extends Parent {\n" + " int getValue() {\n" + " return super.getValue() + 1;\n" + " }\n" + "}\n" + "public class Test {\n" + " public static int main() {\n" + " Child c = new Child();\n" + " return c.getValue();\n" + " }\n" + "}\n", 111); + + printf("\n=== Results: %d/%d tests passed ===\n", pass_count, test_count); + + return (pass_count == test_count) ? 0 : 1; +} diff --git a/tests/test_switch.c b/tests/test_switch.c new file mode 100644 index 0000000..c55a7e6 --- /dev/null +++ b/tests/test_switch.c @@ -0,0 +1,166 @@ +#include "../lexer/lexer.h" +#include "../parser/parser.h" +#include "../semantic/semantic.h" +#include "../ir/ir.h" +#include "../ir/ir_gen.h" +#include "../runtime/runtime.h" +#include +#include +#include + +static int test_count = 0; +static int pass_count = 0; + +static void run_test(const char* name, const char* source, int expected) { + test_count++; + + RavaLexer_t* lexer = rava_lexer_create(source); + RavaParser_t* parser = rava_parser_create(lexer); + RavaASTNode_t* ast = rava_parser_parse(parser); + + if (!ast || parser->had_error) { + printf("FAIL: %s - Parse error: %s\n", name, parser->error_message ? parser->error_message : "unknown"); + rava_parser_destroy(parser); + rava_lexer_destroy(lexer); + return; + } + + RavaSemanticAnalyzer_t* analyzer = rava_semantic_analyzer_create(); + rava_semantic_analyze(analyzer, ast); + + RavaIRGenerator_t* ir_gen = rava_ir_generator_create(analyzer); + RavaProgram_t* program = rava_ir_generate(ir_gen, ast); + + RavaVM_t* vm = rava_vm_create(program); + + if (!rava_vm_execute(vm, "Test", "main")) { + printf("FAIL: %s - Runtime error\n", name); + rava_vm_destroy(vm); + rava_program_destroy(program); + rava_ir_generator_destroy(ir_gen); + rava_semantic_analyzer_destroy(analyzer); + rava_ast_node_destroy(ast); + rava_parser_destroy(parser); + rava_lexer_destroy(lexer); + return; + } + + RavaValue_t result = rava_vm_get_result(vm); + int32_t result_int = rava_value_as_int(result); + + if (result_int == expected) { + printf("PASS: %s (result=%d)\n", name, result_int); + pass_count++; + } else { + printf("FAIL: %s (expected=%d, got=%d)\n", name, expected, result_int); + } + + rava_vm_destroy(vm); + rava_program_destroy(program); + rava_ir_generator_destroy(ir_gen); + rava_semantic_analyzer_destroy(analyzer); + rava_ast_node_destroy(ast); + rava_parser_destroy(parser); + rava_lexer_destroy(lexer); +} + +int main(void) { + printf("=== Switch/Case Tests ===\n\n"); + + run_test("Simple switch", + "public class Test {\n" + " public static int main() {\n" + " int x = 2;\n" + " int result = 0;\n" + " switch (x) {\n" + " case 1:\n" + " result = 10;\n" + " break;\n" + " case 2:\n" + " result = 20;\n" + " break;\n" + " case 3:\n" + " result = 30;\n" + " break;\n" + " }\n" + " return result;\n" + " }\n" + "}\n", 20); + + run_test("Switch with default", + "public class Test {\n" + " public static int main() {\n" + " int x = 99;\n" + " int result = 0;\n" + " switch (x) {\n" + " case 1:\n" + " result = 10;\n" + " break;\n" + " case 2:\n" + " result = 20;\n" + " break;\n" + " default:\n" + " result = 100;\n" + " break;\n" + " }\n" + " return result;\n" + " }\n" + "}\n", 100); + + run_test("Switch fallthrough", + "public class Test {\n" + " public static int main() {\n" + " int x = 1;\n" + " int result = 0;\n" + " switch (x) {\n" + " case 1:\n" + " result = result + 10;\n" + " case 2:\n" + " result = result + 20;\n" + " break;\n" + " case 3:\n" + " result = result + 30;\n" + " break;\n" + " }\n" + " return result;\n" + " }\n" + "}\n", 30); + + run_test("Switch first case", + "public class Test {\n" + " public static int main() {\n" + " int x = 1;\n" + " int result = 0;\n" + " switch (x) {\n" + " case 1:\n" + " result = 111;\n" + " break;\n" + " case 2:\n" + " result = 222;\n" + " break;\n" + " }\n" + " return result;\n" + " }\n" + "}\n", 111); + + run_test("Switch no match no default", + "public class Test {\n" + " public static int main() {\n" + " int x = 99;\n" + " int result = 42;\n" + " switch (x) {\n" + " case 1:\n" + " result = 10;\n" + " break;\n" + " case 2:\n" + " result = 20;\n" + " break;\n" + " }\n" + " return result;\n" + " }\n" + "}\n", 42); + + printf("\n=== Results: %d/%d tests passed ===\n", pass_count, test_count); + + return (pass_count == test_count) ? 0 : 1; +} diff --git a/tests/test_switch.o b/tests/test_switch.o new file mode 100644 index 0000000..9e0d85b Binary files /dev/null and b/tests/test_switch.o differ diff --git a/tests/test_ternary.c b/tests/test_ternary.c new file mode 100644 index 0000000..e9d5006 --- /dev/null +++ b/tests/test_ternary.c @@ -0,0 +1,140 @@ +#include "../lexer/lexer.h" +#include "../parser/parser.h" +#include "../semantic/semantic.h" +#include "../ir/ir.h" +#include "../ir/ir_gen.h" +#include "../runtime/runtime.h" +#include +#include +#include + +static int test_count = 0; +static int pass_count = 0; + +static void run_test_int(const char* name, const char* source, int expected) { + test_count++; + + RavaLexer_t* lexer = rava_lexer_create(source); + RavaParser_t* parser = rava_parser_create(lexer); + RavaASTNode_t* ast = rava_parser_parse(parser); + + if (!ast || parser->had_error) { + printf("FAIL: %s - Parse error: %s\n", name, parser->error_message ? parser->error_message : "unknown"); + rava_parser_destroy(parser); + rava_lexer_destroy(lexer); + return; + } + + RavaSemanticAnalyzer_t* analyzer = rava_semantic_analyzer_create(); + rava_semantic_analyze(analyzer, ast); + + RavaIRGenerator_t* ir_gen = rava_ir_generator_create(analyzer); + RavaProgram_t* program = rava_ir_generate(ir_gen, ast); + + RavaVM_t* vm = rava_vm_create(program); + + if (!rava_vm_execute(vm, "Test", "main")) { + printf("FAIL: %s - Runtime error: %s\n", name, vm->error_message ? vm->error_message : "unknown"); + rava_vm_destroy(vm); + rava_program_destroy(program); + rava_ir_generator_destroy(ir_gen); + rava_semantic_analyzer_destroy(analyzer); + rava_ast_node_destroy(ast); + rava_parser_destroy(parser); + rava_lexer_destroy(lexer); + return; + } + + RavaValue_t result = rava_vm_get_result(vm); + int32_t result_int = rava_value_as_int(result); + + if (result_int == expected) { + printf("PASS: %s (result=%d)\n", name, result_int); + pass_count++; + } else { + printf("FAIL: %s (expected=%d, got=%d)\n", name, expected, result_int); + } + + rava_vm_destroy(vm); + rava_program_destroy(program); + rava_ir_generator_destroy(ir_gen); + rava_semantic_analyzer_destroy(analyzer); + rava_ast_node_destroy(ast); + rava_parser_destroy(parser); + rava_lexer_destroy(lexer); +} + +int main(void) { + printf("=== Ternary Operator Tests ===\n\n"); + + run_test_int("ternary true condition", + "public class Test {\n" + " public static int main() {\n" + " return 1 == 1 ? 42 : 0;\n" + " }\n" + "}\n", 42); + + run_test_int("ternary false condition", + "public class Test {\n" + " public static int main() {\n" + " return 1 == 2 ? 42 : 99;\n" + " }\n" + "}\n", 99); + + run_test_int("ternary with variables", + "public class Test {\n" + " public static int main() {\n" + " int x = 10;\n" + " int y = 20;\n" + " return x < y ? x : y;\n" + " }\n" + "}\n", 10); + + run_test_int("ternary min value", + "public class Test {\n" + " public static int main() {\n" + " int a = 5;\n" + " int b = 3;\n" + " return a < b ? a : b;\n" + " }\n" + "}\n", 3); + + run_test_int("ternary max value", + "public class Test {\n" + " public static int main() {\n" + " int a = 5;\n" + " int b = 3;\n" + " return a > b ? a : b;\n" + " }\n" + "}\n", 5); + + run_test_int("nested ternary", + "public class Test {\n" + " public static int main() {\n" + " int x = 2;\n" + " return x == 1 ? 10 : (x == 2 ? 20 : 30);\n" + " }\n" + "}\n", 20); + + run_test_int("ternary in variable assignment", + "public class Test {\n" + " public static int main() {\n" + " int x = 5;\n" + " int result = x > 3 ? 100 : 200;\n" + " return result;\n" + " }\n" + "}\n", 100); + + run_test_int("ternary with arithmetic", + "public class Test {\n" + " public static int main() {\n" + " int a = 4;\n" + " int b = 6;\n" + " return a + b > 8 ? a * b : a + b;\n" + " }\n" + "}\n", 24); + + printf("\n=== Results: %d/%d tests passed ===\n", pass_count, test_count); + + return (pass_count == test_count) ? 0 : 1; +} diff --git a/tests/test_ternary.o b/tests/test_ternary.o new file mode 100644 index 0000000..1a497cf Binary files /dev/null and b/tests/test_ternary.o differ diff --git a/tests/test_tower_ir.c b/tests/test_tower_ir.c new file mode 100644 index 0000000..3fad1b1 --- /dev/null +++ b/tests/test_tower_ir.c @@ -0,0 +1,56 @@ +#include "../lexer/lexer.h" +#include "../parser/parser.h" +#include "../semantic/semantic.h" +#include "../ir/ir.h" +#include "../ir/ir_gen.h" +#include +#include + +static char* read_file(const char *filename) { + FILE *file = fopen(filename, "r"); + if (!file) return NULL; + fseek(file, 0, SEEK_END); + long size = ftell(file); + fseek(file, 0, SEEK_SET); + char *content = malloc(size + 1); + size_t read_bytes = fread(content, 1, size, file); (void)read_bytes; + content[size] = '\0'; + fclose(file); + return content; +} + +int main() { + char *source = read_file("examples/09_TowerOfHanoi.java"); + if (!source) return 1; + + RavaLexer_t *lexer = rava_lexer_create(source); + RavaParser_t *parser = rava_parser_create(lexer); + RavaASTNode_t *ast = rava_parser_parse(parser); + + if (parser->had_error) { + printf("Parse error: %s\n", parser->error_message); + free(source); + return 1; + } + + RavaSemanticAnalyzer_t *analyzer = rava_semantic_analyzer_create(); + if (!rava_semantic_analyze(analyzer, ast)) { + printf("Semantic error: %s\n", analyzer->error_message); + free(source); + return 1; + } + + RavaIRGenerator_t *ir_gen = rava_ir_generator_create(analyzer); + RavaProgram_t *program = rava_ir_generate(ir_gen, ast); + + if (!program) { + printf("IR generation failed\n"); + free(source); + return 1; + } + + rava_program_print(program); + + free(source); + return 0; +}