diff --git a/.gitignore b/.gitignore index 8b1e9cb..1dc139d 100644 --- a/.gitignore +++ b/.gitignore @@ -5,3 +5,4 @@ merge.py /test_* *.o run_examples +rava diff --git a/Makefile b/Makefile index fabdeda..5e3686d 100644 --- a/Makefile +++ b/Makefile @@ -302,6 +302,18 @@ benchmark: test_benchmark @python3 examples/benchmark.py @echo "" +rava: rava.o $(LEXER_OBJECTS) $(PARSER_OBJECTS) $(TYPES_OBJECTS) $(SEMANTIC_OBJECTS) $(IR_OBJECTS) $(RUNTIME_OBJECTS) $(LOADER_OBJECTS) + $(CC) $(CFLAGS) -o $@ $^ $(LDFLAGS) + +examples: rava + @echo "=== Running All Examples ===" + @for f in examples/*.java; do \ + echo "--- $$f ---"; \ + ./rava "$$f" || true; \ + echo ""; \ + done + @echo "=== Examples Complete ===" + test_nanbox: tests/test_nanbox.c runtime/nanbox.h $(UNITTEST_OBJECTS) $(CC) $(CFLAGS) -o $@ tests/test_nanbox.c $(UNITTEST_OBJECTS) $(LDFLAGS) @@ -347,9 +359,9 @@ clean: $(TEST_STRINGS_OBJECTS) $(TEST_ARRAYS_OBJECTS) $(TEST_OBJECTS_OBJECTS) $(TEST_INSTANCE_OBJECTS) $(TEST_FILEIO_OBJECTS) \ $(TEST_DOWHILE_OBJECTS) $(TEST_SWITCH_OBJECTS) $(TEST_MATH_OBJECTS) $(TEST_STRING_METHODS_OBJECTS) $(TEST_STATIC_OBJECTS) $(TEST_INTERFACES_OBJECTS) $(TEST_EXCEPTIONS_OBJECTS) $(TEST_TERNARY_OBJECTS) $(TEST_BITWISE_OBJECTS) $(TEST_ENHANCED_FOR_OBJECTS) $(TEST_ARRAY_INIT_OBJECTS) $(TEST_INSTANCEOF_OBJECTS) $(TEST_SHORTCIRCUIT_OBJECTS) $(TEST_MULTIDIM_ARRAYS_OBJECTS) $(TEST_STATIC_INIT_OBJECTS) $(TEST_NEGATIVE_OBJECTS) $(TEST_ENUMS_OBJECTS) $(TEST_COLLECTIONS_OBJECTS) $(TEST_SUPER_OBJECTS) $(TEST_INHERITANCE_OBJECTS) $(TEST_BREAK_OBJECTS) $(TEST_ELSEIF_OBJECTS) $(TEST_FORLOOP_OBJECTS) $(TEST_PRINTLN_OBJECTS) $(TEST_LOADER_OBJECTS) $(TEST_OBJECT_METHODS_OBJECTS) $(TEST_AUTOBOX_OBJECTS) $(TEST_SOCKETS_OBJECTS) $(TEST_METHOD_REF_OBJECTS) $(TEST_GC_OBJECTS) $(TEST_BENCHMARK_OBJECTS) \ test_lexer test_parser test_semantic test_ir test_runtime test_strings test_arrays test_objects test_instance_methods test_fileio test_dowhile test_switch test_math test_string_methods test_static test_interfaces test_exceptions test_ternary test_bitwise test_enhanced_for test_array_init test_instanceof test_shortcircuit test_multidim_arrays test_static_init test_negative test_enums test_collections test_super test_inheritance test_break test_elseif test_forloop test_println test_loader test_object_methods test_autobox test_sockets test_method_ref test_gc test_benchmark \ - test_nanbox test_fastframe test_labeltable test_methodcache test_benchmark_pgo test_unittest_demo *.gcda */*.gcda + test_nanbox test_fastframe test_labeltable test_methodcache test_benchmark_pgo test_unittest_demo rava rava.o *.gcda */*.gcda -.PHONY: all clean benchmark test_phase0 pgo test_benchmark_pgo_gen pgo_run test_benchmark_pgo test +.PHONY: all clean benchmark test_phase0 pgo test_benchmark_pgo_gen pgo_run test_benchmark_pgo test examples test: all @echo "=== Running All Tests ===" diff --git a/rava.c b/rava.c new file mode 100644 index 0000000..0d6677e --- /dev/null +++ b/rava.c @@ -0,0 +1,112 @@ +#include +#include +#include +#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" + +static char* read_file(const char *filename) { + FILE *file = fopen(filename, "r"); + if (!file) { + fprintf(stderr, "Error: Cannot open file '%s'\n", filename); + return NULL; + } + fseek(file, 0, SEEK_END); + long size = ftell(file); + fseek(file, 0, SEEK_SET); + char *content = malloc(size + 1); + if (!content) { + fclose(file); + return NULL; + } + size_t read_bytes = fread(content, 1, size, file); + content[read_bytes] = '\0'; + fclose(file); + return content; +} + +static const char* find_main_class(const char *source) { + static char class_name[256]; + const char *p = strstr(source, "public static"); + if (!p) p = strstr(source, "static public"); + if (!p) return "Main"; + + while (p > source) { + p--; + if (strncmp(p, "class ", 6) == 0) { + p += 6; + while (*p == ' ') p++; + int i = 0; + while (*p && *p != ' ' && *p != '{' && *p != '\n' && i < 255) { + class_name[i++] = *p++; + } + class_name[i] = '\0'; + return class_name; + } + } + return "Main"; +} + +int main(int argc, char **argv) { + if (argc < 2) { + fprintf(stderr, "Usage: %s [class] [method]\n", argv[0]); + return 1; + } + + char *source = read_file(argv[1]); + if (!source) return 1; + + const char *class_name = argc > 2 ? argv[2] : find_main_class(source); + const char *method_name = argc > 3 ? argv[3] : "main"; + + 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) { + fprintf(stderr, "Parse error: %s\n", parser->error_message ? parser->error_message : "unknown"); + free(source); + return 1; + } + + RavaSemanticAnalyzer_t *analyzer = rava_semantic_analyzer_create(); + if (!rava_semantic_analyze(analyzer, ast)) { + fprintf(stderr, "Semantic error: %s\n", analyzer->error_message ? analyzer->error_message : "unknown"); + free(source); + return 1; + } + + RavaIRGenerator_t *ir_gen = rava_ir_generator_create(analyzer); + RavaProgram_t *program = rava_ir_generate(ir_gen, ast); + if (!program) { + fprintf(stderr, "IR generation failed\n"); + free(source); + return 1; + } + + RavaVM_t *vm = rava_vm_create(program); + if (!rava_vm_execute(vm, class_name, method_name)) { + fprintf(stderr, "Runtime error: %s\n", vm->error_message ? vm->error_message : "unknown"); + free(source); + return 1; + } + + RavaValue_t result = rava_vm_get_result(vm); + if (result.type == RAVA_VAL_INT) { + return (int)result.data.int_val; + } + + 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 0; +}