Compare commits
8 Commits
cdcfdf375c
...
fca0ade573
| Author | SHA1 | Date | |
|---|---|---|---|
| fca0ade573 | |||
| b46f0d9ff4 | |||
| e33fa20c60 | |||
| de7f824feb | |||
| e2e0788953 | |||
| e953861621 | |||
| 5b5d2e1009 | |||
| f58f42a4a2 |
144
Makefile
144
Makefile
@ -17,9 +17,15 @@ SEMANTIC_OBJECTS = $(SEMANTIC_SOURCES:.c=.o)
|
|||||||
IR_SOURCES = ir/ir.c ir/ir_gen.c
|
IR_SOURCES = ir/ir.c ir/ir_gen.c
|
||||||
IR_OBJECTS = $(IR_SOURCES:.c=.o)
|
IR_OBJECTS = $(IR_SOURCES:.c=.o)
|
||||||
|
|
||||||
RUNTIME_SOURCES = runtime/runtime.c runtime/runtime_array.c runtime/runtime_object.c runtime/runtime_collections.c runtime/labeltable.c runtime/methodcache.c runtime/fastframe.c runtime/superinst.c
|
GC_SOURCES = runtime/gc/gc.c runtime/gc/gc_heap.c runtime/gc/gc_mark.c runtime/gc/gc_sweep.c runtime/gc/gc_roots.c
|
||||||
|
GC_OBJECTS = $(GC_SOURCES:.c=.o)
|
||||||
|
|
||||||
|
RUNTIME_SOURCES = runtime/runtime.c runtime/runtime_array.c runtime/runtime_object.c runtime/runtime_collections.c runtime/runtime_socket.c runtime/runtime_method_ref.c runtime/labeltable.c runtime/methodcache.c runtime/fastframe.c runtime/superinst.c $(GC_SOURCES)
|
||||||
RUNTIME_OBJECTS = $(RUNTIME_SOURCES:.c=.o)
|
RUNTIME_OBJECTS = $(RUNTIME_SOURCES:.c=.o)
|
||||||
|
|
||||||
|
LOADER_SOURCES = loader/loader.c
|
||||||
|
LOADER_OBJECTS = $(LOADER_SOURCES:.c=.o)
|
||||||
|
|
||||||
PHASE0_SOURCES = runtime/fastframe.c runtime/labeltable.c runtime/methodcache.c
|
PHASE0_SOURCES = runtime/fastframe.c runtime/labeltable.c runtime/methodcache.c
|
||||||
PHASE0_OBJECTS = $(PHASE0_SOURCES:.c=.o)
|
PHASE0_OBJECTS = $(PHASE0_SOURCES:.c=.o)
|
||||||
|
|
||||||
@ -116,13 +122,40 @@ TEST_INHERITANCE_OBJECTS = $(TEST_INHERITANCE_SOURCES:.c=.o)
|
|||||||
TEST_BREAK_SOURCES = tests/test_break.c
|
TEST_BREAK_SOURCES = tests/test_break.c
|
||||||
TEST_BREAK_OBJECTS = $(TEST_BREAK_SOURCES:.c=.o)
|
TEST_BREAK_OBJECTS = $(TEST_BREAK_SOURCES:.c=.o)
|
||||||
|
|
||||||
|
TEST_ELSEIF_SOURCES = tests/test_elseif.c
|
||||||
|
TEST_ELSEIF_OBJECTS = $(TEST_ELSEIF_SOURCES:.c=.o)
|
||||||
|
|
||||||
|
TEST_FORLOOP_SOURCES = tests/test_forloop.c
|
||||||
|
TEST_FORLOOP_OBJECTS = $(TEST_FORLOOP_SOURCES:.c=.o)
|
||||||
|
|
||||||
|
TEST_PRINTLN_SOURCES = tests/test_println.c
|
||||||
|
TEST_PRINTLN_OBJECTS = $(TEST_PRINTLN_SOURCES:.c=.o)
|
||||||
|
|
||||||
|
TEST_LOADER_SOURCES = tests/test_loader.c
|
||||||
|
TEST_LOADER_OBJECTS = $(TEST_LOADER_SOURCES:.c=.o)
|
||||||
|
|
||||||
|
TEST_OBJECT_METHODS_SOURCES = tests/test_object_methods.c
|
||||||
|
TEST_OBJECT_METHODS_OBJECTS = $(TEST_OBJECT_METHODS_SOURCES:.c=.o)
|
||||||
|
|
||||||
|
TEST_AUTOBOX_SOURCES = tests/test_autobox.c
|
||||||
|
TEST_AUTOBOX_OBJECTS = $(TEST_AUTOBOX_SOURCES:.c=.o)
|
||||||
|
|
||||||
|
TEST_SOCKETS_SOURCES = tests/test_sockets.c
|
||||||
|
TEST_SOCKETS_OBJECTS = $(TEST_SOCKETS_SOURCES:.c=.o)
|
||||||
|
|
||||||
|
TEST_METHOD_REF_SOURCES = tests/test_method_ref.c
|
||||||
|
TEST_METHOD_REF_OBJECTS = $(TEST_METHOD_REF_SOURCES:.c=.o)
|
||||||
|
|
||||||
|
TEST_GC_SOURCES = tests/test_gc.c
|
||||||
|
TEST_GC_OBJECTS = $(TEST_GC_SOURCES:.c=.o)
|
||||||
|
|
||||||
UNITTEST_SOURCES = tests/unittest.c
|
UNITTEST_SOURCES = tests/unittest.c
|
||||||
UNITTEST_OBJECTS = $(UNITTEST_SOURCES:.c=.o)
|
UNITTEST_OBJECTS = $(UNITTEST_SOURCES:.c=.o)
|
||||||
|
|
||||||
TEST_UNITTEST_DEMO_SOURCES = tests/test_unittest_demo.c
|
TEST_UNITTEST_DEMO_SOURCES = tests/test_unittest_demo.c
|
||||||
TEST_UNITTEST_DEMO_OBJECTS = $(TEST_UNITTEST_DEMO_SOURCES:.c=.o)
|
TEST_UNITTEST_DEMO_OBJECTS = $(TEST_UNITTEST_DEMO_SOURCES:.c=.o)
|
||||||
|
|
||||||
all: 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
|
all: 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_gc
|
||||||
|
|
||||||
test_lexer: $(LEXER_OBJECTS) $(UNITTEST_OBJECTS) $(TEST_LEXER_OBJECTS)
|
test_lexer: $(LEXER_OBJECTS) $(UNITTEST_OBJECTS) $(TEST_LEXER_OBJECTS)
|
||||||
$(CC) $(CFLAGS) -o $@ $^ $(LDFLAGS)
|
$(CC) $(CFLAGS) -o $@ $^ $(LDFLAGS)
|
||||||
@ -136,85 +169,112 @@ test_semantic: $(LEXER_OBJECTS) $(PARSER_OBJECTS) $(TYPES_OBJECTS) $(SEMANTIC_OB
|
|||||||
test_ir: $(LEXER_OBJECTS) $(PARSER_OBJECTS) $(TYPES_OBJECTS) $(SEMANTIC_OBJECTS) $(IR_OBJECTS) runtime/labeltable.o $(UNITTEST_OBJECTS) $(TEST_IR_OBJECTS)
|
test_ir: $(LEXER_OBJECTS) $(PARSER_OBJECTS) $(TYPES_OBJECTS) $(SEMANTIC_OBJECTS) $(IR_OBJECTS) runtime/labeltable.o $(UNITTEST_OBJECTS) $(TEST_IR_OBJECTS)
|
||||||
$(CC) $(CFLAGS) -o $@ $^ $(LDFLAGS)
|
$(CC) $(CFLAGS) -o $@ $^ $(LDFLAGS)
|
||||||
|
|
||||||
test_runtime: $(LEXER_OBJECTS) $(PARSER_OBJECTS) $(TYPES_OBJECTS) $(SEMANTIC_OBJECTS) $(IR_OBJECTS) $(RUNTIME_OBJECTS) $(UNITTEST_OBJECTS) $(TEST_RUNTIME_OBJECTS)
|
test_runtime: $(LEXER_OBJECTS) $(PARSER_OBJECTS) $(TYPES_OBJECTS) $(SEMANTIC_OBJECTS) $(IR_OBJECTS) $(RUNTIME_OBJECTS) $(LOADER_OBJECTS) $(UNITTEST_OBJECTS) $(TEST_RUNTIME_OBJECTS)
|
||||||
$(CC) $(CFLAGS) -o $@ $^ $(LDFLAGS)
|
$(CC) $(CFLAGS) -o $@ $^ $(LDFLAGS)
|
||||||
|
|
||||||
test_strings: $(LEXER_OBJECTS) $(PARSER_OBJECTS) $(TYPES_OBJECTS) $(SEMANTIC_OBJECTS) $(IR_OBJECTS) $(RUNTIME_OBJECTS) $(UNITTEST_OBJECTS) $(TEST_STRINGS_OBJECTS)
|
test_strings: $(LEXER_OBJECTS) $(PARSER_OBJECTS) $(TYPES_OBJECTS) $(SEMANTIC_OBJECTS) $(IR_OBJECTS) $(RUNTIME_OBJECTS) $(LOADER_OBJECTS) $(UNITTEST_OBJECTS) $(TEST_STRINGS_OBJECTS)
|
||||||
$(CC) $(CFLAGS) -o $@ $^ $(LDFLAGS)
|
$(CC) $(CFLAGS) -o $@ $^ $(LDFLAGS)
|
||||||
|
|
||||||
test_arrays: $(LEXER_OBJECTS) $(PARSER_OBJECTS) $(TYPES_OBJECTS) $(SEMANTIC_OBJECTS) $(IR_OBJECTS) $(RUNTIME_OBJECTS) $(UNITTEST_OBJECTS) $(TEST_ARRAYS_OBJECTS)
|
test_arrays: $(LEXER_OBJECTS) $(PARSER_OBJECTS) $(TYPES_OBJECTS) $(SEMANTIC_OBJECTS) $(IR_OBJECTS) $(RUNTIME_OBJECTS) $(LOADER_OBJECTS) $(UNITTEST_OBJECTS) $(TEST_ARRAYS_OBJECTS)
|
||||||
$(CC) $(CFLAGS) -o $@ $^ $(LDFLAGS)
|
$(CC) $(CFLAGS) -o $@ $^ $(LDFLAGS)
|
||||||
|
|
||||||
test_objects: $(LEXER_OBJECTS) $(PARSER_OBJECTS) $(TYPES_OBJECTS) $(SEMANTIC_OBJECTS) $(IR_OBJECTS) $(RUNTIME_OBJECTS) $(UNITTEST_OBJECTS) $(TEST_OBJECTS_OBJECTS)
|
test_objects: $(LEXER_OBJECTS) $(PARSER_OBJECTS) $(TYPES_OBJECTS) $(SEMANTIC_OBJECTS) $(IR_OBJECTS) $(RUNTIME_OBJECTS) $(LOADER_OBJECTS) $(UNITTEST_OBJECTS) $(TEST_OBJECTS_OBJECTS)
|
||||||
$(CC) $(CFLAGS) -o $@ $^ $(LDFLAGS)
|
$(CC) $(CFLAGS) -o $@ $^ $(LDFLAGS)
|
||||||
|
|
||||||
test_instance_methods: $(LEXER_OBJECTS) $(PARSER_OBJECTS) $(TYPES_OBJECTS) $(SEMANTIC_OBJECTS) $(IR_OBJECTS) $(RUNTIME_OBJECTS) $(UNITTEST_OBJECTS) $(TEST_INSTANCE_OBJECTS)
|
test_instance_methods: $(LEXER_OBJECTS) $(PARSER_OBJECTS) $(TYPES_OBJECTS) $(SEMANTIC_OBJECTS) $(IR_OBJECTS) $(RUNTIME_OBJECTS) $(LOADER_OBJECTS) $(UNITTEST_OBJECTS) $(TEST_INSTANCE_OBJECTS)
|
||||||
$(CC) $(CFLAGS) -o $@ $^ $(LDFLAGS)
|
$(CC) $(CFLAGS) -o $@ $^ $(LDFLAGS)
|
||||||
|
|
||||||
test_fileio: $(LEXER_OBJECTS) $(PARSER_OBJECTS) $(TYPES_OBJECTS) $(SEMANTIC_OBJECTS) $(IR_OBJECTS) $(RUNTIME_OBJECTS) $(UNITTEST_OBJECTS) $(TEST_FILEIO_OBJECTS)
|
test_fileio: $(LEXER_OBJECTS) $(PARSER_OBJECTS) $(TYPES_OBJECTS) $(SEMANTIC_OBJECTS) $(IR_OBJECTS) $(RUNTIME_OBJECTS) $(LOADER_OBJECTS) $(UNITTEST_OBJECTS) $(TEST_FILEIO_OBJECTS)
|
||||||
$(CC) $(CFLAGS) -o $@ $^ $(LDFLAGS)
|
$(CC) $(CFLAGS) -o $@ $^ $(LDFLAGS)
|
||||||
|
|
||||||
test_dowhile: $(LEXER_OBJECTS) $(PARSER_OBJECTS) $(TYPES_OBJECTS) $(SEMANTIC_OBJECTS) $(IR_OBJECTS) $(RUNTIME_OBJECTS) $(UNITTEST_OBJECTS) $(TEST_DOWHILE_OBJECTS)
|
test_dowhile: $(LEXER_OBJECTS) $(PARSER_OBJECTS) $(TYPES_OBJECTS) $(SEMANTIC_OBJECTS) $(IR_OBJECTS) $(RUNTIME_OBJECTS) $(LOADER_OBJECTS) $(UNITTEST_OBJECTS) $(TEST_DOWHILE_OBJECTS)
|
||||||
$(CC) $(CFLAGS) -o $@ $^ $(LDFLAGS)
|
$(CC) $(CFLAGS) -o $@ $^ $(LDFLAGS)
|
||||||
|
|
||||||
test_switch: $(LEXER_OBJECTS) $(PARSER_OBJECTS) $(TYPES_OBJECTS) $(SEMANTIC_OBJECTS) $(IR_OBJECTS) $(RUNTIME_OBJECTS) $(UNITTEST_OBJECTS) $(TEST_SWITCH_OBJECTS)
|
test_switch: $(LEXER_OBJECTS) $(PARSER_OBJECTS) $(TYPES_OBJECTS) $(SEMANTIC_OBJECTS) $(IR_OBJECTS) $(RUNTIME_OBJECTS) $(LOADER_OBJECTS) $(UNITTEST_OBJECTS) $(TEST_SWITCH_OBJECTS)
|
||||||
$(CC) $(CFLAGS) -o $@ $^ $(LDFLAGS)
|
$(CC) $(CFLAGS) -o $@ $^ $(LDFLAGS)
|
||||||
|
|
||||||
test_math: $(LEXER_OBJECTS) $(PARSER_OBJECTS) $(TYPES_OBJECTS) $(SEMANTIC_OBJECTS) $(IR_OBJECTS) $(RUNTIME_OBJECTS) $(UNITTEST_OBJECTS) $(TEST_MATH_OBJECTS)
|
test_math: $(LEXER_OBJECTS) $(PARSER_OBJECTS) $(TYPES_OBJECTS) $(SEMANTIC_OBJECTS) $(IR_OBJECTS) $(RUNTIME_OBJECTS) $(LOADER_OBJECTS) $(UNITTEST_OBJECTS) $(TEST_MATH_OBJECTS)
|
||||||
$(CC) $(CFLAGS) -o $@ $^ $(LDFLAGS)
|
$(CC) $(CFLAGS) -o $@ $^ $(LDFLAGS)
|
||||||
|
|
||||||
test_string_methods: $(LEXER_OBJECTS) $(PARSER_OBJECTS) $(TYPES_OBJECTS) $(SEMANTIC_OBJECTS) $(IR_OBJECTS) $(RUNTIME_OBJECTS) $(UNITTEST_OBJECTS) $(TEST_STRING_METHODS_OBJECTS)
|
test_string_methods: $(LEXER_OBJECTS) $(PARSER_OBJECTS) $(TYPES_OBJECTS) $(SEMANTIC_OBJECTS) $(IR_OBJECTS) $(RUNTIME_OBJECTS) $(LOADER_OBJECTS) $(UNITTEST_OBJECTS) $(TEST_STRING_METHODS_OBJECTS)
|
||||||
$(CC) $(CFLAGS) -o $@ $^ $(LDFLAGS)
|
$(CC) $(CFLAGS) -o $@ $^ $(LDFLAGS)
|
||||||
|
|
||||||
test_static: $(LEXER_OBJECTS) $(PARSER_OBJECTS) $(TYPES_OBJECTS) $(SEMANTIC_OBJECTS) $(IR_OBJECTS) $(RUNTIME_OBJECTS) $(UNITTEST_OBJECTS) $(TEST_STATIC_OBJECTS)
|
test_static: $(LEXER_OBJECTS) $(PARSER_OBJECTS) $(TYPES_OBJECTS) $(SEMANTIC_OBJECTS) $(IR_OBJECTS) $(RUNTIME_OBJECTS) $(LOADER_OBJECTS) $(UNITTEST_OBJECTS) $(TEST_STATIC_OBJECTS)
|
||||||
$(CC) $(CFLAGS) -o $@ $^ $(LDFLAGS)
|
$(CC) $(CFLAGS) -o $@ $^ $(LDFLAGS)
|
||||||
|
|
||||||
test_interfaces: $(LEXER_OBJECTS) $(PARSER_OBJECTS) $(TYPES_OBJECTS) $(SEMANTIC_OBJECTS) $(IR_OBJECTS) $(RUNTIME_OBJECTS) $(UNITTEST_OBJECTS) $(TEST_INTERFACES_OBJECTS)
|
test_interfaces: $(LEXER_OBJECTS) $(PARSER_OBJECTS) $(TYPES_OBJECTS) $(SEMANTIC_OBJECTS) $(IR_OBJECTS) $(RUNTIME_OBJECTS) $(LOADER_OBJECTS) $(UNITTEST_OBJECTS) $(TEST_INTERFACES_OBJECTS)
|
||||||
$(CC) $(CFLAGS) -o $@ $^ $(LDFLAGS)
|
$(CC) $(CFLAGS) -o $@ $^ $(LDFLAGS)
|
||||||
|
|
||||||
test_exceptions: $(LEXER_OBJECTS) $(PARSER_OBJECTS) $(TYPES_OBJECTS) $(SEMANTIC_OBJECTS) $(IR_OBJECTS) $(RUNTIME_OBJECTS) $(UNITTEST_OBJECTS) $(TEST_EXCEPTIONS_OBJECTS)
|
test_exceptions: $(LEXER_OBJECTS) $(PARSER_OBJECTS) $(TYPES_OBJECTS) $(SEMANTIC_OBJECTS) $(IR_OBJECTS) $(RUNTIME_OBJECTS) $(LOADER_OBJECTS) $(UNITTEST_OBJECTS) $(TEST_EXCEPTIONS_OBJECTS)
|
||||||
$(CC) $(CFLAGS) -o $@ $^ $(LDFLAGS)
|
$(CC) $(CFLAGS) -o $@ $^ $(LDFLAGS)
|
||||||
|
|
||||||
test_ternary: $(LEXER_OBJECTS) $(PARSER_OBJECTS) $(TYPES_OBJECTS) $(SEMANTIC_OBJECTS) $(IR_OBJECTS) $(RUNTIME_OBJECTS) $(UNITTEST_OBJECTS) $(TEST_TERNARY_OBJECTS)
|
test_ternary: $(LEXER_OBJECTS) $(PARSER_OBJECTS) $(TYPES_OBJECTS) $(SEMANTIC_OBJECTS) $(IR_OBJECTS) $(RUNTIME_OBJECTS) $(LOADER_OBJECTS) $(UNITTEST_OBJECTS) $(TEST_TERNARY_OBJECTS)
|
||||||
$(CC) $(CFLAGS) -o $@ $^ $(LDFLAGS)
|
$(CC) $(CFLAGS) -o $@ $^ $(LDFLAGS)
|
||||||
|
|
||||||
test_bitwise: $(LEXER_OBJECTS) $(PARSER_OBJECTS) $(TYPES_OBJECTS) $(SEMANTIC_OBJECTS) $(IR_OBJECTS) $(RUNTIME_OBJECTS) $(UNITTEST_OBJECTS) $(TEST_BITWISE_OBJECTS)
|
test_bitwise: $(LEXER_OBJECTS) $(PARSER_OBJECTS) $(TYPES_OBJECTS) $(SEMANTIC_OBJECTS) $(IR_OBJECTS) $(RUNTIME_OBJECTS) $(LOADER_OBJECTS) $(UNITTEST_OBJECTS) $(TEST_BITWISE_OBJECTS)
|
||||||
$(CC) $(CFLAGS) -o $@ $^ $(LDFLAGS)
|
$(CC) $(CFLAGS) -o $@ $^ $(LDFLAGS)
|
||||||
|
|
||||||
test_enhanced_for: $(LEXER_OBJECTS) $(PARSER_OBJECTS) $(TYPES_OBJECTS) $(SEMANTIC_OBJECTS) $(IR_OBJECTS) $(RUNTIME_OBJECTS) $(UNITTEST_OBJECTS) $(TEST_ENHANCED_FOR_OBJECTS)
|
test_enhanced_for: $(LEXER_OBJECTS) $(PARSER_OBJECTS) $(TYPES_OBJECTS) $(SEMANTIC_OBJECTS) $(IR_OBJECTS) $(RUNTIME_OBJECTS) $(LOADER_OBJECTS) $(UNITTEST_OBJECTS) $(TEST_ENHANCED_FOR_OBJECTS)
|
||||||
$(CC) $(CFLAGS) -o $@ $^ $(LDFLAGS)
|
$(CC) $(CFLAGS) -o $@ $^ $(LDFLAGS)
|
||||||
|
|
||||||
test_array_init: $(LEXER_OBJECTS) $(PARSER_OBJECTS) $(TYPES_OBJECTS) $(SEMANTIC_OBJECTS) $(IR_OBJECTS) $(RUNTIME_OBJECTS) $(UNITTEST_OBJECTS) $(TEST_ARRAY_INIT_OBJECTS)
|
test_array_init: $(LEXER_OBJECTS) $(PARSER_OBJECTS) $(TYPES_OBJECTS) $(SEMANTIC_OBJECTS) $(IR_OBJECTS) $(RUNTIME_OBJECTS) $(LOADER_OBJECTS) $(UNITTEST_OBJECTS) $(TEST_ARRAY_INIT_OBJECTS)
|
||||||
$(CC) $(CFLAGS) -o $@ $^ $(LDFLAGS)
|
$(CC) $(CFLAGS) -o $@ $^ $(LDFLAGS)
|
||||||
|
|
||||||
test_instanceof: $(LEXER_OBJECTS) $(PARSER_OBJECTS) $(TYPES_OBJECTS) $(SEMANTIC_OBJECTS) $(IR_OBJECTS) $(RUNTIME_OBJECTS) $(UNITTEST_OBJECTS) $(TEST_INSTANCEOF_OBJECTS)
|
test_instanceof: $(LEXER_OBJECTS) $(PARSER_OBJECTS) $(TYPES_OBJECTS) $(SEMANTIC_OBJECTS) $(IR_OBJECTS) $(RUNTIME_OBJECTS) $(LOADER_OBJECTS) $(UNITTEST_OBJECTS) $(TEST_INSTANCEOF_OBJECTS)
|
||||||
$(CC) $(CFLAGS) -o $@ $^ $(LDFLAGS)
|
$(CC) $(CFLAGS) -o $@ $^ $(LDFLAGS)
|
||||||
|
|
||||||
test_shortcircuit: $(LEXER_OBJECTS) $(PARSER_OBJECTS) $(TYPES_OBJECTS) $(SEMANTIC_OBJECTS) $(IR_OBJECTS) $(RUNTIME_OBJECTS) $(UNITTEST_OBJECTS) $(TEST_SHORTCIRCUIT_OBJECTS)
|
test_shortcircuit: $(LEXER_OBJECTS) $(PARSER_OBJECTS) $(TYPES_OBJECTS) $(SEMANTIC_OBJECTS) $(IR_OBJECTS) $(RUNTIME_OBJECTS) $(LOADER_OBJECTS) $(UNITTEST_OBJECTS) $(TEST_SHORTCIRCUIT_OBJECTS)
|
||||||
$(CC) $(CFLAGS) -o $@ $^ $(LDFLAGS)
|
$(CC) $(CFLAGS) -o $@ $^ $(LDFLAGS)
|
||||||
|
|
||||||
test_multidim_arrays: $(LEXER_OBJECTS) $(PARSER_OBJECTS) $(TYPES_OBJECTS) $(SEMANTIC_OBJECTS) $(IR_OBJECTS) $(RUNTIME_OBJECTS) $(UNITTEST_OBJECTS) $(TEST_MULTIDIM_ARRAYS_OBJECTS)
|
test_multidim_arrays: $(LEXER_OBJECTS) $(PARSER_OBJECTS) $(TYPES_OBJECTS) $(SEMANTIC_OBJECTS) $(IR_OBJECTS) $(RUNTIME_OBJECTS) $(LOADER_OBJECTS) $(UNITTEST_OBJECTS) $(TEST_MULTIDIM_ARRAYS_OBJECTS)
|
||||||
$(CC) $(CFLAGS) -o $@ $^ $(LDFLAGS)
|
$(CC) $(CFLAGS) -o $@ $^ $(LDFLAGS)
|
||||||
|
|
||||||
test_static_init: $(LEXER_OBJECTS) $(PARSER_OBJECTS) $(TYPES_OBJECTS) $(SEMANTIC_OBJECTS) $(IR_OBJECTS) $(RUNTIME_OBJECTS) $(UNITTEST_OBJECTS) $(TEST_STATIC_INIT_OBJECTS)
|
test_static_init: $(LEXER_OBJECTS) $(PARSER_OBJECTS) $(TYPES_OBJECTS) $(SEMANTIC_OBJECTS) $(IR_OBJECTS) $(RUNTIME_OBJECTS) $(LOADER_OBJECTS) $(UNITTEST_OBJECTS) $(TEST_STATIC_INIT_OBJECTS)
|
||||||
$(CC) $(CFLAGS) -o $@ $^ $(LDFLAGS)
|
$(CC) $(CFLAGS) -o $@ $^ $(LDFLAGS)
|
||||||
|
|
||||||
test_negative: $(LEXER_OBJECTS) $(PARSER_OBJECTS) $(TYPES_OBJECTS) $(SEMANTIC_OBJECTS) $(IR_OBJECTS) $(RUNTIME_OBJECTS) $(UNITTEST_OBJECTS) $(TEST_NEGATIVE_OBJECTS)
|
test_negative: $(LEXER_OBJECTS) $(PARSER_OBJECTS) $(TYPES_OBJECTS) $(SEMANTIC_OBJECTS) $(IR_OBJECTS) $(RUNTIME_OBJECTS) $(LOADER_OBJECTS) $(UNITTEST_OBJECTS) $(TEST_NEGATIVE_OBJECTS)
|
||||||
$(CC) $(CFLAGS) -o $@ $^ $(LDFLAGS)
|
$(CC) $(CFLAGS) -o $@ $^ $(LDFLAGS)
|
||||||
|
|
||||||
test_enums: $(LEXER_OBJECTS) $(PARSER_OBJECTS) $(TYPES_OBJECTS) $(SEMANTIC_OBJECTS) $(IR_OBJECTS) $(RUNTIME_OBJECTS) $(UNITTEST_OBJECTS) $(TEST_ENUMS_OBJECTS)
|
test_enums: $(LEXER_OBJECTS) $(PARSER_OBJECTS) $(TYPES_OBJECTS) $(SEMANTIC_OBJECTS) $(IR_OBJECTS) $(RUNTIME_OBJECTS) $(LOADER_OBJECTS) $(UNITTEST_OBJECTS) $(TEST_ENUMS_OBJECTS)
|
||||||
$(CC) $(CFLAGS) -o $@ $^ $(LDFLAGS)
|
$(CC) $(CFLAGS) -o $@ $^ $(LDFLAGS)
|
||||||
|
|
||||||
test_collections: $(LEXER_OBJECTS) $(PARSER_OBJECTS) $(TYPES_OBJECTS) $(SEMANTIC_OBJECTS) $(IR_OBJECTS) $(RUNTIME_OBJECTS) $(UNITTEST_OBJECTS) $(TEST_COLLECTIONS_OBJECTS)
|
test_collections: $(LEXER_OBJECTS) $(PARSER_OBJECTS) $(TYPES_OBJECTS) $(SEMANTIC_OBJECTS) $(IR_OBJECTS) $(RUNTIME_OBJECTS) $(LOADER_OBJECTS) $(UNITTEST_OBJECTS) $(TEST_COLLECTIONS_OBJECTS)
|
||||||
$(CC) $(CFLAGS) -o $@ $^ $(LDFLAGS)
|
$(CC) $(CFLAGS) -o $@ $^ $(LDFLAGS)
|
||||||
|
|
||||||
test_super: $(LEXER_OBJECTS) $(PARSER_OBJECTS) $(TYPES_OBJECTS) $(SEMANTIC_OBJECTS) $(IR_OBJECTS) $(RUNTIME_OBJECTS) $(UNITTEST_OBJECTS) $(TEST_SUPER_OBJECTS)
|
test_super: $(LEXER_OBJECTS) $(PARSER_OBJECTS) $(TYPES_OBJECTS) $(SEMANTIC_OBJECTS) $(IR_OBJECTS) $(RUNTIME_OBJECTS) $(LOADER_OBJECTS) $(UNITTEST_OBJECTS) $(TEST_SUPER_OBJECTS)
|
||||||
$(CC) $(CFLAGS) -o $@ $^ $(LDFLAGS)
|
$(CC) $(CFLAGS) -o $@ $^ $(LDFLAGS)
|
||||||
|
|
||||||
test_inheritance: $(LEXER_OBJECTS) $(PARSER_OBJECTS) $(TYPES_OBJECTS) $(SEMANTIC_OBJECTS) $(IR_OBJECTS) $(RUNTIME_OBJECTS) $(UNITTEST_OBJECTS) $(TEST_INHERITANCE_OBJECTS)
|
test_inheritance: $(LEXER_OBJECTS) $(PARSER_OBJECTS) $(TYPES_OBJECTS) $(SEMANTIC_OBJECTS) $(IR_OBJECTS) $(RUNTIME_OBJECTS) $(LOADER_OBJECTS) $(UNITTEST_OBJECTS) $(TEST_INHERITANCE_OBJECTS)
|
||||||
$(CC) $(CFLAGS) -o $@ $^ $(LDFLAGS)
|
$(CC) $(CFLAGS) -o $@ $^ $(LDFLAGS)
|
||||||
|
|
||||||
test_break: $(LEXER_OBJECTS) $(PARSER_OBJECTS) $(TYPES_OBJECTS) $(SEMANTIC_OBJECTS) $(IR_OBJECTS) $(RUNTIME_OBJECTS) $(UNITTEST_OBJECTS) $(TEST_BREAK_OBJECTS)
|
test_break: $(LEXER_OBJECTS) $(PARSER_OBJECTS) $(TYPES_OBJECTS) $(SEMANTIC_OBJECTS) $(IR_OBJECTS) $(RUNTIME_OBJECTS) $(LOADER_OBJECTS) $(UNITTEST_OBJECTS) $(TEST_BREAK_OBJECTS)
|
||||||
|
$(CC) $(CFLAGS) -o $@ $^ $(LDFLAGS)
|
||||||
|
|
||||||
|
test_elseif: $(LEXER_OBJECTS) $(PARSER_OBJECTS) $(TYPES_OBJECTS) $(SEMANTIC_OBJECTS) $(IR_OBJECTS) $(RUNTIME_OBJECTS) $(LOADER_OBJECTS) $(UNITTEST_OBJECTS) $(TEST_ELSEIF_OBJECTS)
|
||||||
|
$(CC) $(CFLAGS) -o $@ $^ $(LDFLAGS)
|
||||||
|
|
||||||
|
test_forloop: $(LEXER_OBJECTS) $(PARSER_OBJECTS) $(TYPES_OBJECTS) $(SEMANTIC_OBJECTS) $(IR_OBJECTS) $(RUNTIME_OBJECTS) $(LOADER_OBJECTS) $(UNITTEST_OBJECTS) $(TEST_FORLOOP_OBJECTS)
|
||||||
|
$(CC) $(CFLAGS) -o $@ $^ $(LDFLAGS)
|
||||||
|
|
||||||
|
test_println: $(LEXER_OBJECTS) $(PARSER_OBJECTS) $(TYPES_OBJECTS) $(SEMANTIC_OBJECTS) $(IR_OBJECTS) $(RUNTIME_OBJECTS) $(LOADER_OBJECTS) $(UNITTEST_OBJECTS) $(TEST_PRINTLN_OBJECTS)
|
||||||
|
$(CC) $(CFLAGS) -o $@ $^ $(LDFLAGS)
|
||||||
|
|
||||||
|
test_loader: $(LOADER_OBJECTS) $(RUNTIME_OBJECTS) $(IR_OBJECTS) $(TYPES_OBJECTS) $(SEMANTIC_OBJECTS) $(UNITTEST_OBJECTS) $(TEST_LOADER_OBJECTS)
|
||||||
|
$(CC) $(CFLAGS) -o $@ $^ $(LDFLAGS)
|
||||||
|
|
||||||
|
test_object_methods: $(LEXER_OBJECTS) $(PARSER_OBJECTS) $(TYPES_OBJECTS) $(SEMANTIC_OBJECTS) $(IR_OBJECTS) $(RUNTIME_OBJECTS) $(LOADER_OBJECTS) $(UNITTEST_OBJECTS) $(TEST_OBJECT_METHODS_OBJECTS)
|
||||||
|
$(CC) $(CFLAGS) -o $@ $^ $(LDFLAGS)
|
||||||
|
|
||||||
|
test_autobox: $(LEXER_OBJECTS) $(PARSER_OBJECTS) $(TYPES_OBJECTS) $(SEMANTIC_OBJECTS) $(IR_OBJECTS) $(RUNTIME_OBJECTS) $(LOADER_OBJECTS) $(UNITTEST_OBJECTS) $(TEST_AUTOBOX_OBJECTS)
|
||||||
|
$(CC) $(CFLAGS) -o $@ $^ $(LDFLAGS)
|
||||||
|
|
||||||
|
test_sockets: $(LEXER_OBJECTS) $(PARSER_OBJECTS) $(TYPES_OBJECTS) $(SEMANTIC_OBJECTS) $(IR_OBJECTS) $(RUNTIME_OBJECTS) $(LOADER_OBJECTS) $(UNITTEST_OBJECTS) $(TEST_SOCKETS_OBJECTS)
|
||||||
|
$(CC) $(CFLAGS) -o $@ $^ $(LDFLAGS)
|
||||||
|
|
||||||
|
test_method_ref: $(LEXER_OBJECTS) $(PARSER_OBJECTS) $(TYPES_OBJECTS) $(SEMANTIC_OBJECTS) $(IR_OBJECTS) $(RUNTIME_OBJECTS) $(LOADER_OBJECTS) $(UNITTEST_OBJECTS) $(TEST_METHOD_REF_OBJECTS)
|
||||||
|
$(CC) $(CFLAGS) -o $@ $^ $(LDFLAGS)
|
||||||
|
|
||||||
|
test_gc: $(LEXER_OBJECTS) $(PARSER_OBJECTS) $(TYPES_OBJECTS) $(SEMANTIC_OBJECTS) $(IR_OBJECTS) $(RUNTIME_OBJECTS) $(LOADER_OBJECTS) $(UNITTEST_OBJECTS) $(TEST_GC_OBJECTS)
|
||||||
$(CC) $(CFLAGS) -o $@ $^ $(LDFLAGS)
|
$(CC) $(CFLAGS) -o $@ $^ $(LDFLAGS)
|
||||||
|
|
||||||
test_unittest_demo: $(UNITTEST_OBJECTS) $(TEST_UNITTEST_DEMO_OBJECTS)
|
test_unittest_demo: $(UNITTEST_OBJECTS) $(TEST_UNITTEST_DEMO_OBJECTS)
|
||||||
@ -226,7 +286,7 @@ test_unittest_demo: $(UNITTEST_OBJECTS) $(TEST_UNITTEST_DEMO_OBJECTS)
|
|||||||
TEST_BENCHMARK_SOURCES = tests/test_benchmark.c
|
TEST_BENCHMARK_SOURCES = tests/test_benchmark.c
|
||||||
TEST_BENCHMARK_OBJECTS = $(TEST_BENCHMARK_SOURCES:.c=.o)
|
TEST_BENCHMARK_OBJECTS = $(TEST_BENCHMARK_SOURCES:.c=.o)
|
||||||
|
|
||||||
test_benchmark: $(LEXER_OBJECTS) $(PARSER_OBJECTS) $(TYPES_OBJECTS) $(SEMANTIC_OBJECTS) $(IR_OBJECTS) $(RUNTIME_OBJECTS) $(TEST_BENCHMARK_OBJECTS)
|
test_benchmark: $(LEXER_OBJECTS) $(PARSER_OBJECTS) $(TYPES_OBJECTS) $(SEMANTIC_OBJECTS) $(IR_OBJECTS) $(RUNTIME_OBJECTS) $(LOADER_OBJECTS) $(TEST_BENCHMARK_OBJECTS)
|
||||||
$(CC) $(CFLAGS) -o $@ $^ $(LDFLAGS)
|
$(CC) $(CFLAGS) -o $@ $^ $(LDFLAGS)
|
||||||
|
|
||||||
benchmark: test_benchmark
|
benchmark: test_benchmark
|
||||||
@ -242,17 +302,17 @@ benchmark: test_benchmark
|
|||||||
@python3 examples/benchmark.py
|
@python3 examples/benchmark.py
|
||||||
@echo ""
|
@echo ""
|
||||||
|
|
||||||
test_nanbox: tests/test_nanbox.c runtime/nanbox.h
|
test_nanbox: tests/test_nanbox.c runtime/nanbox.h $(UNITTEST_OBJECTS)
|
||||||
$(CC) $(CFLAGS) -o $@ tests/test_nanbox.c $(LDFLAGS)
|
$(CC) $(CFLAGS) -o $@ tests/test_nanbox.c $(UNITTEST_OBJECTS) $(LDFLAGS)
|
||||||
|
|
||||||
test_fastframe: tests/test_fastframe.c runtime/fastframe.c runtime/nanbox.h runtime/fastframe.h
|
test_fastframe: tests/test_fastframe.c runtime/fastframe.c runtime/nanbox.h runtime/fastframe.h $(UNITTEST_OBJECTS)
|
||||||
$(CC) $(CFLAGS) -o $@ tests/test_fastframe.c runtime/fastframe.c $(LDFLAGS)
|
$(CC) $(CFLAGS) -o $@ tests/test_fastframe.c runtime/fastframe.c $(UNITTEST_OBJECTS) $(LDFLAGS)
|
||||||
|
|
||||||
test_labeltable: tests/test_labeltable.c runtime/labeltable.c $(IR_OBJECTS) $(TYPES_OBJECTS) $(SEMANTIC_OBJECTS)
|
test_labeltable: tests/test_labeltable.c runtime/labeltable.c $(IR_OBJECTS) $(TYPES_OBJECTS) $(SEMANTIC_OBJECTS) $(UNITTEST_OBJECTS)
|
||||||
$(CC) $(CFLAGS) -o $@ tests/test_labeltable.c runtime/labeltable.c $(IR_OBJECTS) $(TYPES_OBJECTS) $(SEMANTIC_OBJECTS) $(LDFLAGS)
|
$(CC) $(CFLAGS) -o $@ tests/test_labeltable.c runtime/labeltable.c $(IR_OBJECTS) $(TYPES_OBJECTS) $(SEMANTIC_OBJECTS) $(UNITTEST_OBJECTS) $(LDFLAGS)
|
||||||
|
|
||||||
test_methodcache: tests/test_methodcache.c runtime/methodcache.c runtime/methodcache.h
|
test_methodcache: tests/test_methodcache.c runtime/methodcache.c runtime/methodcache.h $(UNITTEST_OBJECTS)
|
||||||
$(CC) $(CFLAGS) -o $@ tests/test_methodcache.c runtime/methodcache.c $(LDFLAGS)
|
$(CC) $(CFLAGS) -o $@ tests/test_methodcache.c runtime/methodcache.c $(UNITTEST_OBJECTS) $(LDFLAGS)
|
||||||
|
|
||||||
test_phase0: test_nanbox test_fastframe test_labeltable test_methodcache
|
test_phase0: test_nanbox test_fastframe test_labeltable test_methodcache
|
||||||
@echo "=== Running Phase 0 Tests ==="
|
@echo "=== Running Phase 0 Tests ==="
|
||||||
@ -281,12 +341,12 @@ pgo: test_benchmark_pgo
|
|||||||
./test_benchmark_pgo
|
./test_benchmark_pgo
|
||||||
|
|
||||||
clean:
|
clean:
|
||||||
rm -f $(LEXER_OBJECTS) $(PARSER_OBJECTS) $(TYPES_OBJECTS) $(SEMANTIC_OBJECTS) $(IR_OBJECTS) $(RUNTIME_OBJECTS) \
|
rm -f $(LEXER_OBJECTS) $(PARSER_OBJECTS) $(TYPES_OBJECTS) $(SEMANTIC_OBJECTS) $(IR_OBJECTS) $(RUNTIME_OBJECTS) $(LOADER_OBJECTS) \
|
||||||
$(PHASE0_OBJECTS) $(UNITTEST_OBJECTS) $(TEST_UNITTEST_DEMO_OBJECTS) \
|
$(PHASE0_OBJECTS) $(UNITTEST_OBJECTS) $(TEST_UNITTEST_DEMO_OBJECTS) \
|
||||||
$(TEST_LEXER_OBJECTS) $(TEST_PARSER_OBJECTS) $(TEST_SEMANTIC_OBJECTS) $(TEST_IR_OBJECTS) $(TEST_RUNTIME_OBJECTS) \
|
$(TEST_LEXER_OBJECTS) $(TEST_PARSER_OBJECTS) $(TEST_SEMANTIC_OBJECTS) $(TEST_IR_OBJECTS) $(TEST_RUNTIME_OBJECTS) \
|
||||||
$(TEST_STRINGS_OBJECTS) $(TEST_ARRAYS_OBJECTS) $(TEST_OBJECTS_OBJECTS) $(TEST_INSTANCE_OBJECTS) $(TEST_FILEIO_OBJECTS) \
|
$(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_BENCHMARK_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_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_benchmark \
|
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_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 *.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
|
||||||
@ -300,4 +360,6 @@ test: all
|
|||||||
./test_bitwise && ./test_enhanced_for && ./test_array_init && ./test_instanceof && \
|
./test_bitwise && ./test_enhanced_for && ./test_array_init && ./test_instanceof && \
|
||||||
./test_shortcircuit && ./test_multidim_arrays && ./test_static_init && ./test_negative && \
|
./test_shortcircuit && ./test_multidim_arrays && ./test_static_init && ./test_negative && \
|
||||||
./test_enums && ./test_collections && ./test_super && ./test_inheritance && ./test_break && \
|
./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 && \
|
||||||
echo "" && echo "=== All Tests Passed ==="
|
echo "" && echo "=== All Tests Passed ==="
|
||||||
|
|||||||
14
ir/ir.c
14
ir/ir.c
@ -280,6 +280,20 @@ static const char* _rava_opcode_name(RavaOpCode_e opcode) {
|
|||||||
case RAVA_OP_HASHMAP_SIZE: return "HASHMAP_SIZE";
|
case RAVA_OP_HASHMAP_SIZE: return "HASHMAP_SIZE";
|
||||||
case RAVA_OP_HASHMAP_CONTAINSKEY: return "HASHMAP_CONTAINSKEY";
|
case RAVA_OP_HASHMAP_CONTAINSKEY: return "HASHMAP_CONTAINSKEY";
|
||||||
case RAVA_OP_HASHMAP_CLEAR: return "HASHMAP_CLEAR";
|
case RAVA_OP_HASHMAP_CLEAR: return "HASHMAP_CLEAR";
|
||||||
|
case RAVA_OP_SOCKET_NEW: return "SOCKET_NEW";
|
||||||
|
case RAVA_OP_SOCKET_CONNECT: return "SOCKET_CONNECT";
|
||||||
|
case RAVA_OP_SOCKET_READ: return "SOCKET_READ";
|
||||||
|
case RAVA_OP_SOCKET_WRITE: return "SOCKET_WRITE";
|
||||||
|
case RAVA_OP_SOCKET_CLOSE: return "SOCKET_CLOSE";
|
||||||
|
case RAVA_OP_SERVER_SOCKET_NEW: return "SERVER_SOCKET_NEW";
|
||||||
|
case RAVA_OP_SERVER_SOCKET_ACCEPT: return "SERVER_SOCKET_ACCEPT";
|
||||||
|
case RAVA_OP_SOCKET_GET_INPUT_STREAM: return "SOCKET_GET_INPUT_STREAM";
|
||||||
|
case RAVA_OP_SOCKET_GET_OUTPUT_STREAM: return "SOCKET_GET_OUTPUT_STREAM";
|
||||||
|
case RAVA_OP_INPUT_STREAM_READ: return "INPUT_STREAM_READ";
|
||||||
|
case RAVA_OP_OUTPUT_STREAM_WRITE: return "OUTPUT_STREAM_WRITE";
|
||||||
|
case RAVA_OP_STREAM_CLOSE: return "STREAM_CLOSE";
|
||||||
|
case RAVA_OP_METHOD_REF: return "METHOD_REF";
|
||||||
|
case RAVA_OP_METHOD_REF_INVOKE: return "METHOD_REF_INVOKE";
|
||||||
default: return "UNKNOWN";
|
default: return "UNKNOWN";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
24
ir/ir.h
24
ir/ir.h
@ -144,7 +144,23 @@ typedef enum {
|
|||||||
RAVA_OP_HASHMAP_REMOVE,
|
RAVA_OP_HASHMAP_REMOVE,
|
||||||
RAVA_OP_HASHMAP_SIZE,
|
RAVA_OP_HASHMAP_SIZE,
|
||||||
RAVA_OP_HASHMAP_CONTAINSKEY,
|
RAVA_OP_HASHMAP_CONTAINSKEY,
|
||||||
RAVA_OP_HASHMAP_CLEAR
|
RAVA_OP_HASHMAP_CLEAR,
|
||||||
|
|
||||||
|
RAVA_OP_SOCKET_NEW,
|
||||||
|
RAVA_OP_SOCKET_CONNECT,
|
||||||
|
RAVA_OP_SOCKET_READ,
|
||||||
|
RAVA_OP_SOCKET_WRITE,
|
||||||
|
RAVA_OP_SOCKET_CLOSE,
|
||||||
|
RAVA_OP_SERVER_SOCKET_NEW,
|
||||||
|
RAVA_OP_SERVER_SOCKET_ACCEPT,
|
||||||
|
RAVA_OP_SOCKET_GET_INPUT_STREAM,
|
||||||
|
RAVA_OP_SOCKET_GET_OUTPUT_STREAM,
|
||||||
|
RAVA_OP_INPUT_STREAM_READ,
|
||||||
|
RAVA_OP_OUTPUT_STREAM_WRITE,
|
||||||
|
RAVA_OP_STREAM_CLOSE,
|
||||||
|
|
||||||
|
RAVA_OP_METHOD_REF,
|
||||||
|
RAVA_OP_METHOD_REF_INVOKE
|
||||||
} RavaOpCode_e;
|
} RavaOpCode_e;
|
||||||
|
|
||||||
typedef union {
|
typedef union {
|
||||||
@ -190,6 +206,12 @@ typedef union {
|
|||||||
int end_label;
|
int end_label;
|
||||||
int exception_local;
|
int exception_local;
|
||||||
} try_handler;
|
} try_handler;
|
||||||
|
struct {
|
||||||
|
char *class_name;
|
||||||
|
char *method_name;
|
||||||
|
bool is_constructor;
|
||||||
|
bool is_static;
|
||||||
|
} method_ref;
|
||||||
} RavaOperand_u;
|
} RavaOperand_u;
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
|
|||||||
98
ir/ir_gen.c
98
ir/ir_gen.c
@ -433,6 +433,19 @@ static void _rava_ir_gen_expression(RavaIRGenerator_t *gen, RavaASTNode_t *expr)
|
|||||||
} else if (strcmp(type_name, "HashMap") == 0) {
|
} else if (strcmp(type_name, "HashMap") == 0) {
|
||||||
instr.opcode = RAVA_OP_HASHMAP_NEW;
|
instr.opcode = RAVA_OP_HASHMAP_NEW;
|
||||||
_rava_ir_emit(gen, instr);
|
_rava_ir_emit(gen, instr);
|
||||||
|
} else if (strcmp(type_name, "Socket") == 0) {
|
||||||
|
if (expr->data.new_expr.arguments_count == 2) {
|
||||||
|
_rava_ir_gen_expression(gen, expr->data.new_expr.arguments[0]);
|
||||||
|
_rava_ir_gen_expression(gen, expr->data.new_expr.arguments[1]);
|
||||||
|
}
|
||||||
|
instr.opcode = RAVA_OP_SOCKET_NEW;
|
||||||
|
_rava_ir_emit(gen, instr);
|
||||||
|
} else if (strcmp(type_name, "ServerSocket") == 0) {
|
||||||
|
if (expr->data.new_expr.arguments_count >= 1) {
|
||||||
|
_rava_ir_gen_expression(gen, expr->data.new_expr.arguments[0]);
|
||||||
|
}
|
||||||
|
instr.opcode = RAVA_OP_SERVER_SOCKET_NEW;
|
||||||
|
_rava_ir_emit(gen, instr);
|
||||||
} else {
|
} else {
|
||||||
instr.opcode = RAVA_OP_NEW;
|
instr.opcode = RAVA_OP_NEW;
|
||||||
instr.operand.call.class_name = strdup(type_name);
|
instr.operand.call.class_name = strdup(type_name);
|
||||||
@ -494,8 +507,16 @@ static void _rava_ir_gen_expression(RavaIRGenerator_t *gen, RavaASTNode_t *expr)
|
|||||||
bool is_arraylist_isempty = false;
|
bool is_arraylist_isempty = false;
|
||||||
bool is_hashmap_put = false;
|
bool is_hashmap_put = false;
|
||||||
bool is_hashmap_containskey = false;
|
bool is_hashmap_containskey = false;
|
||||||
|
bool is_socket_connect = false;
|
||||||
|
bool is_socket_close = false;
|
||||||
|
bool is_socket_get_input_stream = false;
|
||||||
|
bool is_socket_get_output_stream = false;
|
||||||
|
bool is_server_socket_accept = false;
|
||||||
|
bool is_input_stream_read = false;
|
||||||
|
bool is_output_stream_write = false;
|
||||||
RavaASTNode_t *string_object = NULL;
|
RavaASTNode_t *string_object = NULL;
|
||||||
RavaASTNode_t *collection_object = NULL;
|
RavaASTNode_t *collection_object = NULL;
|
||||||
|
RavaASTNode_t *socket_object = NULL;
|
||||||
|
|
||||||
if (expr->data.call.callee->type == RAVA_AST_MEMBER_ACCESS_EXPR) {
|
if (expr->data.call.callee->type == RAVA_AST_MEMBER_ACCESS_EXPR) {
|
||||||
RavaASTNode_t *member = expr->data.call.callee;
|
RavaASTNode_t *member = expr->data.call.callee;
|
||||||
@ -627,6 +648,27 @@ static void _rava_ir_gen_expression(RavaIRGenerator_t *gen, RavaASTNode_t *expr)
|
|||||||
} else if (strcmp(member->data.member_access.member, "containsKey") == 0 && expr->data.call.arguments_count == 1) {
|
} else if (strcmp(member->data.member_access.member, "containsKey") == 0 && expr->data.call.arguments_count == 1) {
|
||||||
is_hashmap_containskey = true;
|
is_hashmap_containskey = true;
|
||||||
collection_object = member->data.member_access.object;
|
collection_object = member->data.member_access.object;
|
||||||
|
} else if (strcmp(member->data.member_access.member, "connect") == 0 && expr->data.call.arguments_count == 2) {
|
||||||
|
is_socket_connect = true;
|
||||||
|
socket_object = member->data.member_access.object;
|
||||||
|
} else if (strcmp(member->data.member_access.member, "getInputStream") == 0 && expr->data.call.arguments_count == 0) {
|
||||||
|
is_socket_get_input_stream = true;
|
||||||
|
socket_object = member->data.member_access.object;
|
||||||
|
} else if (strcmp(member->data.member_access.member, "getOutputStream") == 0 && expr->data.call.arguments_count == 0) {
|
||||||
|
is_socket_get_output_stream = true;
|
||||||
|
socket_object = member->data.member_access.object;
|
||||||
|
} else if (strcmp(member->data.member_access.member, "accept") == 0 && expr->data.call.arguments_count == 0) {
|
||||||
|
is_server_socket_accept = true;
|
||||||
|
socket_object = member->data.member_access.object;
|
||||||
|
} else if (strcmp(member->data.member_access.member, "read") == 0) {
|
||||||
|
is_input_stream_read = true;
|
||||||
|
socket_object = member->data.member_access.object;
|
||||||
|
} else if (strcmp(member->data.member_access.member, "write") == 0) {
|
||||||
|
is_output_stream_write = true;
|
||||||
|
socket_object = member->data.member_access.object;
|
||||||
|
} else if (strcmp(member->data.member_access.member, "close") == 0 && expr->data.call.arguments_count == 0) {
|
||||||
|
is_socket_close = true;
|
||||||
|
socket_object = member->data.member_access.object;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -812,6 +854,40 @@ static void _rava_ir_gen_expression(RavaIRGenerator_t *gen, RavaASTNode_t *expr)
|
|||||||
_rava_ir_gen_expression(gen, expr->data.call.arguments[0]);
|
_rava_ir_gen_expression(gen, expr->data.call.arguments[0]);
|
||||||
instr.opcode = RAVA_OP_HASHMAP_CONTAINSKEY;
|
instr.opcode = RAVA_OP_HASHMAP_CONTAINSKEY;
|
||||||
_rava_ir_emit(gen, instr);
|
_rava_ir_emit(gen, instr);
|
||||||
|
} else if (is_socket_connect) {
|
||||||
|
_rava_ir_gen_expression(gen, socket_object);
|
||||||
|
_rava_ir_gen_expression(gen, expr->data.call.arguments[0]);
|
||||||
|
_rava_ir_gen_expression(gen, expr->data.call.arguments[1]);
|
||||||
|
instr.opcode = RAVA_OP_SOCKET_CONNECT;
|
||||||
|
_rava_ir_emit(gen, instr);
|
||||||
|
} else if (is_socket_get_input_stream) {
|
||||||
|
_rava_ir_gen_expression(gen, socket_object);
|
||||||
|
instr.opcode = RAVA_OP_SOCKET_GET_INPUT_STREAM;
|
||||||
|
_rava_ir_emit(gen, instr);
|
||||||
|
} else if (is_socket_get_output_stream) {
|
||||||
|
_rava_ir_gen_expression(gen, socket_object);
|
||||||
|
instr.opcode = RAVA_OP_SOCKET_GET_OUTPUT_STREAM;
|
||||||
|
_rava_ir_emit(gen, instr);
|
||||||
|
} else if (is_server_socket_accept) {
|
||||||
|
_rava_ir_gen_expression(gen, socket_object);
|
||||||
|
instr.opcode = RAVA_OP_SERVER_SOCKET_ACCEPT;
|
||||||
|
_rava_ir_emit(gen, instr);
|
||||||
|
} else if (is_input_stream_read) {
|
||||||
|
_rava_ir_gen_expression(gen, socket_object);
|
||||||
|
instr.opcode = RAVA_OP_INPUT_STREAM_READ;
|
||||||
|
_rava_ir_emit(gen, instr);
|
||||||
|
} else if (is_output_stream_write) {
|
||||||
|
_rava_ir_gen_expression(gen, socket_object);
|
||||||
|
for (size_t i = 0; i < expr->data.call.arguments_count; i++) {
|
||||||
|
_rava_ir_gen_expression(gen, expr->data.call.arguments[i]);
|
||||||
|
}
|
||||||
|
instr.opcode = RAVA_OP_OUTPUT_STREAM_WRITE;
|
||||||
|
instr.operand.int_value = expr->data.call.arguments_count;
|
||||||
|
_rava_ir_emit(gen, instr);
|
||||||
|
} else if (is_socket_close) {
|
||||||
|
_rava_ir_gen_expression(gen, socket_object);
|
||||||
|
instr.opcode = RAVA_OP_SOCKET_CLOSE;
|
||||||
|
_rava_ir_emit(gen, instr);
|
||||||
} else if (is_println || is_print) {
|
} else if (is_println || is_print) {
|
||||||
for (size_t i = 0; i < expr->data.call.arguments_count; i++) {
|
for (size_t i = 0; i < expr->data.call.arguments_count; i++) {
|
||||||
_rava_ir_gen_expression(gen, expr->data.call.arguments[i]);
|
_rava_ir_gen_expression(gen, expr->data.call.arguments[i]);
|
||||||
@ -950,6 +1026,28 @@ static void _rava_ir_gen_expression(RavaIRGenerator_t *gen, RavaASTNode_t *expr)
|
|||||||
_rava_ir_emit(gen, instr);
|
_rava_ir_emit(gen, instr);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
case RAVA_AST_METHOD_REF_EXPR: {
|
||||||
|
RavaASTNode_t *target = expr->data.method_ref.target;
|
||||||
|
bool is_static = false;
|
||||||
|
char *class_name = NULL;
|
||||||
|
|
||||||
|
if (target && target->type == RAVA_AST_IDENTIFIER_EXPR) {
|
||||||
|
class_name = strdup(target->data.identifier.name);
|
||||||
|
is_static = true;
|
||||||
|
} else if (target) {
|
||||||
|
_rava_ir_gen_expression(gen, target);
|
||||||
|
class_name = strdup("");
|
||||||
|
}
|
||||||
|
|
||||||
|
instr.opcode = RAVA_OP_METHOD_REF;
|
||||||
|
instr.operand.method_ref.class_name = class_name;
|
||||||
|
instr.operand.method_ref.method_name = strdup(expr->data.method_ref.method_name);
|
||||||
|
instr.operand.method_ref.is_constructor = expr->data.method_ref.is_constructor;
|
||||||
|
instr.operand.method_ref.is_static = is_static;
|
||||||
|
_rava_ir_emit(gen, instr);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
default:
|
default:
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|||||||
216
loader/loader.c
Normal file
216
loader/loader.c
Normal file
@ -0,0 +1,216 @@
|
|||||||
|
#include "loader.h"
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <dlfcn.h>
|
||||||
|
|
||||||
|
RavaNativeRegistry_t* rava_native_registry_create(void) {
|
||||||
|
RavaNativeRegistry_t *registry = calloc(1, sizeof(RavaNativeRegistry_t));
|
||||||
|
if (!registry) return NULL;
|
||||||
|
registry->library_count = 0;
|
||||||
|
registry->cache_count = 0;
|
||||||
|
return registry;
|
||||||
|
}
|
||||||
|
|
||||||
|
void rava_native_registry_destroy(RavaNativeRegistry_t *registry) {
|
||||||
|
if (!registry) return;
|
||||||
|
for (size_t i = 0; i < registry->library_count; i++) {
|
||||||
|
rava_native_library_unload(registry, registry->libraries[i]);
|
||||||
|
}
|
||||||
|
free(registry);
|
||||||
|
}
|
||||||
|
|
||||||
|
static uint32_t _hash_method_name(const char *class_name, const char *method_name) {
|
||||||
|
uint32_t hash = 5381;
|
||||||
|
for (const char *p = class_name; *p; p++) {
|
||||||
|
hash = ((hash << 5) + hash) + (uint32_t)*p;
|
||||||
|
}
|
||||||
|
hash = ((hash << 5) + hash) + '.';
|
||||||
|
for (const char *p = method_name; *p; p++) {
|
||||||
|
hash = ((hash << 5) + hash) + (uint32_t)*p;
|
||||||
|
}
|
||||||
|
return hash % RAVA_MAX_NATIVE_METHODS;
|
||||||
|
}
|
||||||
|
|
||||||
|
RavaNativeLibrary_t* rava_native_library_load(RavaNativeRegistry_t *registry, const char *path) {
|
||||||
|
if (!registry || !path) return NULL;
|
||||||
|
if (registry->library_count >= RAVA_MAX_NATIVE_LIBRARIES) return NULL;
|
||||||
|
|
||||||
|
void *handle = dlopen(path, RTLD_NOW | RTLD_LOCAL);
|
||||||
|
if (!handle) {
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
RavaNativeLibrary_t *lib = calloc(1, sizeof(RavaNativeLibrary_t));
|
||||||
|
if (!lib) {
|
||||||
|
dlclose(handle);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
lib->path = strdup(path);
|
||||||
|
lib->handle = handle;
|
||||||
|
lib->method_count = 0;
|
||||||
|
lib->method_capacity = 16;
|
||||||
|
lib->methods = calloc(lib->method_capacity, sizeof(RavaNativeMethod_t));
|
||||||
|
|
||||||
|
const char *name_start = strrchr(path, '/');
|
||||||
|
if (name_start) {
|
||||||
|
name_start++;
|
||||||
|
} else {
|
||||||
|
name_start = path;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (strncmp(name_start, "lib", 3) == 0) {
|
||||||
|
name_start += 3;
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t name_len = strlen(name_start);
|
||||||
|
if (name_len > 3 && strcmp(name_start + name_len - 3, ".so") == 0) {
|
||||||
|
lib->name = strndup(name_start, name_len - 3);
|
||||||
|
} else {
|
||||||
|
lib->name = strdup(name_start);
|
||||||
|
}
|
||||||
|
|
||||||
|
RavaLibraryRegisterFn register_fn = (RavaLibraryRegisterFn)dlsym(handle, RAVA_LIBRARY_REGISTER_SYMBOL);
|
||||||
|
if (register_fn) {
|
||||||
|
register_fn(registry);
|
||||||
|
}
|
||||||
|
|
||||||
|
registry->libraries[registry->library_count++] = lib;
|
||||||
|
return lib;
|
||||||
|
}
|
||||||
|
|
||||||
|
void rava_native_library_unload(RavaNativeRegistry_t *registry, RavaNativeLibrary_t *lib) {
|
||||||
|
if (!registry || !lib) return;
|
||||||
|
|
||||||
|
for (size_t i = 0; i < lib->method_count; i++) {
|
||||||
|
free(lib->methods[i].class_name);
|
||||||
|
free(lib->methods[i].method_name);
|
||||||
|
}
|
||||||
|
free(lib->methods);
|
||||||
|
|
||||||
|
if (lib->handle) {
|
||||||
|
dlclose(lib->handle);
|
||||||
|
}
|
||||||
|
|
||||||
|
free(lib->name);
|
||||||
|
free(lib->path);
|
||||||
|
free(lib);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool rava_native_register_method(RavaNativeRegistry_t *registry,
|
||||||
|
const char *class_name,
|
||||||
|
const char *method_name,
|
||||||
|
RavaNativeType_e return_type,
|
||||||
|
RavaNativeType_e *param_types,
|
||||||
|
size_t param_count,
|
||||||
|
RavaNativeFunction_fn function,
|
||||||
|
void *user_data) {
|
||||||
|
if (!registry || !class_name || !method_name || !function) return false;
|
||||||
|
if (param_count > RAVA_MAX_METHOD_PARAMS) return false;
|
||||||
|
if (registry->cache_count >= RAVA_MAX_NATIVE_METHODS) return false;
|
||||||
|
|
||||||
|
RavaNativeMethod_t *method = calloc(1, sizeof(RavaNativeMethod_t));
|
||||||
|
if (!method) return false;
|
||||||
|
|
||||||
|
method->class_name = strdup(class_name);
|
||||||
|
method->method_name = strdup(method_name);
|
||||||
|
method->return_type = return_type;
|
||||||
|
method->param_count = param_count;
|
||||||
|
method->function = function;
|
||||||
|
method->user_data = user_data;
|
||||||
|
|
||||||
|
for (size_t i = 0; i < param_count; i++) {
|
||||||
|
method->param_types[i] = param_types[i];
|
||||||
|
}
|
||||||
|
|
||||||
|
uint32_t hash = _hash_method_name(class_name, method_name);
|
||||||
|
|
||||||
|
while (registry->method_cache[hash] != NULL) {
|
||||||
|
hash = (hash + 1) % RAVA_MAX_NATIVE_METHODS;
|
||||||
|
}
|
||||||
|
|
||||||
|
registry->method_cache[hash] = method;
|
||||||
|
registry->cache_count++;
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
RavaNativeMethod_t* rava_native_find_method(RavaNativeRegistry_t *registry,
|
||||||
|
const char *class_name,
|
||||||
|
const char *method_name) {
|
||||||
|
if (!registry || !class_name || !method_name) return NULL;
|
||||||
|
|
||||||
|
uint32_t hash = _hash_method_name(class_name, method_name);
|
||||||
|
uint32_t start = hash;
|
||||||
|
|
||||||
|
do {
|
||||||
|
RavaNativeMethod_t *method = registry->method_cache[hash];
|
||||||
|
if (!method) return NULL;
|
||||||
|
|
||||||
|
if (strcmp(method->class_name, class_name) == 0 &&
|
||||||
|
strcmp(method->method_name, method_name) == 0) {
|
||||||
|
return method;
|
||||||
|
}
|
||||||
|
|
||||||
|
hash = (hash + 1) % RAVA_MAX_NATIVE_METHODS;
|
||||||
|
} while (hash != start);
|
||||||
|
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
RavaNativeValue_t rava_native_invoke(RavaNativeMethod_t *method,
|
||||||
|
RavaNativeValue_t *args,
|
||||||
|
size_t arg_count) {
|
||||||
|
if (!method || !method->function) {
|
||||||
|
return rava_native_void();
|
||||||
|
}
|
||||||
|
return method->function(args, arg_count, method->user_data);
|
||||||
|
}
|
||||||
|
|
||||||
|
RavaNativeValue_t rava_native_int(int32_t val) {
|
||||||
|
RavaNativeValue_t native;
|
||||||
|
native.type = RAVA_NATIVE_INT;
|
||||||
|
native.data.int_val = val;
|
||||||
|
return native;
|
||||||
|
}
|
||||||
|
|
||||||
|
RavaNativeValue_t rava_native_long(int64_t val) {
|
||||||
|
RavaNativeValue_t native;
|
||||||
|
native.type = RAVA_NATIVE_LONG;
|
||||||
|
native.data.long_val = val;
|
||||||
|
return native;
|
||||||
|
}
|
||||||
|
|
||||||
|
RavaNativeValue_t rava_native_double(double val) {
|
||||||
|
RavaNativeValue_t native;
|
||||||
|
native.type = RAVA_NATIVE_DOUBLE;
|
||||||
|
native.data.double_val = val;
|
||||||
|
return native;
|
||||||
|
}
|
||||||
|
|
||||||
|
RavaNativeValue_t rava_native_boolean(bool val) {
|
||||||
|
RavaNativeValue_t native;
|
||||||
|
native.type = RAVA_NATIVE_BOOLEAN;
|
||||||
|
native.data.bool_val = val;
|
||||||
|
return native;
|
||||||
|
}
|
||||||
|
|
||||||
|
RavaNativeValue_t rava_native_string(const char *val) {
|
||||||
|
RavaNativeValue_t native;
|
||||||
|
native.type = RAVA_NATIVE_STRING;
|
||||||
|
native.data.string_val = val ? strdup(val) : NULL;
|
||||||
|
return native;
|
||||||
|
}
|
||||||
|
|
||||||
|
RavaNativeValue_t rava_native_void(void) {
|
||||||
|
RavaNativeValue_t native;
|
||||||
|
native.type = RAVA_NATIVE_VOID;
|
||||||
|
return native;
|
||||||
|
}
|
||||||
|
|
||||||
|
RavaNativeValue_t rava_native_null(void) {
|
||||||
|
RavaNativeValue_t native;
|
||||||
|
native.type = RAVA_NATIVE_OBJECT;
|
||||||
|
native.data.object_val = NULL;
|
||||||
|
return native;
|
||||||
|
}
|
||||||
99
loader/loader.h
Normal file
99
loader/loader.h
Normal file
@ -0,0 +1,99 @@
|
|||||||
|
#ifndef RAVA_LOADER_H
|
||||||
|
#define RAVA_LOADER_H
|
||||||
|
|
||||||
|
#include <stddef.h>
|
||||||
|
#include <stdbool.h>
|
||||||
|
#include <stdint.h>
|
||||||
|
|
||||||
|
#define RAVA_MAX_NATIVE_METHODS 256
|
||||||
|
#define RAVA_MAX_NATIVE_LIBRARIES 32
|
||||||
|
#define RAVA_MAX_METHOD_PARAMS 16
|
||||||
|
|
||||||
|
typedef enum {
|
||||||
|
RAVA_NATIVE_VOID,
|
||||||
|
RAVA_NATIVE_INT,
|
||||||
|
RAVA_NATIVE_LONG,
|
||||||
|
RAVA_NATIVE_DOUBLE,
|
||||||
|
RAVA_NATIVE_BOOLEAN,
|
||||||
|
RAVA_NATIVE_STRING,
|
||||||
|
RAVA_NATIVE_OBJECT,
|
||||||
|
RAVA_NATIVE_ARRAY
|
||||||
|
} RavaNativeType_e;
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
RavaNativeType_e type;
|
||||||
|
union {
|
||||||
|
int32_t int_val;
|
||||||
|
int64_t long_val;
|
||||||
|
double double_val;
|
||||||
|
bool bool_val;
|
||||||
|
char *string_val;
|
||||||
|
void *object_val;
|
||||||
|
void *array_val;
|
||||||
|
} data;
|
||||||
|
} RavaNativeValue_t;
|
||||||
|
|
||||||
|
typedef RavaNativeValue_t (*RavaNativeFunction_fn)(RavaNativeValue_t *args, size_t arg_count, void *user_data);
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
char *class_name;
|
||||||
|
char *method_name;
|
||||||
|
RavaNativeType_e return_type;
|
||||||
|
RavaNativeType_e param_types[RAVA_MAX_METHOD_PARAMS];
|
||||||
|
size_t param_count;
|
||||||
|
RavaNativeFunction_fn function;
|
||||||
|
void *user_data;
|
||||||
|
} RavaNativeMethod_t;
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
char *name;
|
||||||
|
char *path;
|
||||||
|
void *handle;
|
||||||
|
RavaNativeMethod_t *methods;
|
||||||
|
size_t method_count;
|
||||||
|
size_t method_capacity;
|
||||||
|
} RavaNativeLibrary_t;
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
RavaNativeLibrary_t *libraries[RAVA_MAX_NATIVE_LIBRARIES];
|
||||||
|
size_t library_count;
|
||||||
|
RavaNativeMethod_t *method_cache[RAVA_MAX_NATIVE_METHODS];
|
||||||
|
size_t cache_count;
|
||||||
|
} RavaNativeRegistry_t;
|
||||||
|
|
||||||
|
RavaNativeRegistry_t* rava_native_registry_create(void);
|
||||||
|
void rava_native_registry_destroy(RavaNativeRegistry_t *registry);
|
||||||
|
|
||||||
|
RavaNativeLibrary_t* rava_native_library_load(RavaNativeRegistry_t *registry, const char *path);
|
||||||
|
void rava_native_library_unload(RavaNativeRegistry_t *registry, RavaNativeLibrary_t *lib);
|
||||||
|
|
||||||
|
bool rava_native_register_method(RavaNativeRegistry_t *registry,
|
||||||
|
const char *class_name,
|
||||||
|
const char *method_name,
|
||||||
|
RavaNativeType_e return_type,
|
||||||
|
RavaNativeType_e *param_types,
|
||||||
|
size_t param_count,
|
||||||
|
RavaNativeFunction_fn function,
|
||||||
|
void *user_data);
|
||||||
|
|
||||||
|
RavaNativeMethod_t* rava_native_find_method(RavaNativeRegistry_t *registry,
|
||||||
|
const char *class_name,
|
||||||
|
const char *method_name);
|
||||||
|
|
||||||
|
RavaNativeValue_t rava_native_invoke(RavaNativeMethod_t *method,
|
||||||
|
RavaNativeValue_t *args,
|
||||||
|
size_t arg_count);
|
||||||
|
|
||||||
|
|
||||||
|
RavaNativeValue_t rava_native_int(int32_t val);
|
||||||
|
RavaNativeValue_t rava_native_long(int64_t val);
|
||||||
|
RavaNativeValue_t rava_native_double(double val);
|
||||||
|
RavaNativeValue_t rava_native_boolean(bool val);
|
||||||
|
RavaNativeValue_t rava_native_string(const char *val);
|
||||||
|
RavaNativeValue_t rava_native_void(void);
|
||||||
|
RavaNativeValue_t rava_native_null(void);
|
||||||
|
|
||||||
|
typedef void (*RavaLibraryRegisterFn)(RavaNativeRegistry_t *registry);
|
||||||
|
#define RAVA_LIBRARY_REGISTER_SYMBOL "rava_library_register"
|
||||||
|
|
||||||
|
#endif
|
||||||
@ -58,6 +58,7 @@ typedef enum {
|
|||||||
RAVA_AST_SUPER_EXPR,
|
RAVA_AST_SUPER_EXPR,
|
||||||
RAVA_AST_CLASS_LITERAL_EXPR,
|
RAVA_AST_CLASS_LITERAL_EXPR,
|
||||||
RAVA_AST_ARRAY_INIT_EXPR,
|
RAVA_AST_ARRAY_INIT_EXPR,
|
||||||
|
RAVA_AST_METHOD_REF_EXPR,
|
||||||
|
|
||||||
RAVA_AST_TYPE,
|
RAVA_AST_TYPE,
|
||||||
RAVA_AST_TYPE_PARAM,
|
RAVA_AST_TYPE_PARAM,
|
||||||
@ -296,6 +297,12 @@ struct RavaASTNode_t {
|
|||||||
RavaASTNode_t *expression;
|
RavaASTNode_t *expression;
|
||||||
char *type_name;
|
char *type_name;
|
||||||
} instanceof_expr;
|
} instanceof_expr;
|
||||||
|
|
||||||
|
struct {
|
||||||
|
RavaASTNode_t *target;
|
||||||
|
char *method_name;
|
||||||
|
bool is_constructor;
|
||||||
|
} method_ref;
|
||||||
} data;
|
} data;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@ -239,6 +239,24 @@ static RavaASTNode_t* _rava_parser_parse_postfix(RavaParser_t *parser) {
|
|||||||
unary->data.unary.op = RAVA_UNOP_POSTDEC;
|
unary->data.unary.op = RAVA_UNOP_POSTDEC;
|
||||||
unary->data.unary.operand = expr;
|
unary->data.unary.operand = expr;
|
||||||
expr = unary;
|
expr = unary;
|
||||||
|
} else if (_rava_parser_match(parser, RAVA_TOKEN_COLONCOLON)) {
|
||||||
|
RavaASTNode_t *method_ref = rava_ast_node_create(RAVA_AST_METHOD_REF_EXPR,
|
||||||
|
parser->current_token->line,
|
||||||
|
parser->current_token->column);
|
||||||
|
method_ref->data.method_ref.target = expr;
|
||||||
|
if (_rava_parser_match(parser, RAVA_TOKEN_KEYWORD_NEW)) {
|
||||||
|
method_ref->data.method_ref.method_name = strdup("new");
|
||||||
|
method_ref->data.method_ref.is_constructor = true;
|
||||||
|
} else if (_rava_parser_check(parser, RAVA_TOKEN_IDENTIFIER)) {
|
||||||
|
method_ref->data.method_ref.method_name = strdup(parser->current_token->lexeme);
|
||||||
|
method_ref->data.method_ref.is_constructor = false;
|
||||||
|
_rava_parser_advance(parser);
|
||||||
|
} else {
|
||||||
|
parser->had_error = true;
|
||||||
|
parser->error_message = strdup("Expected method name or 'new' after '::'");
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
expr = method_ref;
|
||||||
} else {
|
} else {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|||||||
139
runtime/gc/gc.c
Normal file
139
runtime/gc/gc.c
Normal file
@ -0,0 +1,139 @@
|
|||||||
|
#include "gc.h"
|
||||||
|
#include "gc_heap.h"
|
||||||
|
#include "gc_mark.h"
|
||||||
|
#include "gc_sweep.h"
|
||||||
|
#include "gc_roots.h"
|
||||||
|
#include "../runtime.h"
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
|
static RavaVM_t *g_current_vm = NULL;
|
||||||
|
static RavaGCStats_t g_stats;
|
||||||
|
|
||||||
|
void rava_gc_init(void) {
|
||||||
|
rava_gc_heap_init();
|
||||||
|
rava_gc_mark_init();
|
||||||
|
memset(&g_stats, 0, sizeof(g_stats));
|
||||||
|
g_current_vm = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
void rava_gc_shutdown(void) {
|
||||||
|
RavaGCHeap_t *heap = rava_gc_get_heap();
|
||||||
|
RavaGCHeader_t *obj = heap->all_objects;
|
||||||
|
while (obj) {
|
||||||
|
RavaGCHeader_t *next = obj->gc_next;
|
||||||
|
rava_gc_finalize_object(obj);
|
||||||
|
obj = next;
|
||||||
|
}
|
||||||
|
heap->all_objects = NULL;
|
||||||
|
|
||||||
|
rava_gc_heap_shutdown();
|
||||||
|
}
|
||||||
|
|
||||||
|
void rava_gc_set_vm(RavaVM_t *vm) {
|
||||||
|
g_current_vm = vm;
|
||||||
|
}
|
||||||
|
|
||||||
|
void* rava_gc_alloc(size_t size, uint8_t type) {
|
||||||
|
RavaGCState_t *state = rava_gc_get_state();
|
||||||
|
|
||||||
|
if (state->gc_enabled && !state->gc_active) {
|
||||||
|
rava_gc_collect_if_needed();
|
||||||
|
}
|
||||||
|
|
||||||
|
void *ptr = rava_gc_heap_alloc(size, type);
|
||||||
|
if (ptr) {
|
||||||
|
g_stats.objects_allocated++;
|
||||||
|
g_stats.bytes_allocated += size;
|
||||||
|
g_stats.current_live_objects++;
|
||||||
|
g_stats.current_live_bytes += size;
|
||||||
|
if (g_stats.current_live_bytes > g_stats.peak_live_bytes) {
|
||||||
|
g_stats.peak_live_bytes = g_stats.current_live_bytes;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return ptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
void rava_gc_free(void *ptr) {
|
||||||
|
(void)ptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
void rava_gc_collect(void) {
|
||||||
|
RavaGCState_t *state = rava_gc_get_state();
|
||||||
|
|
||||||
|
if (state->gc_active) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
state->gc_active = true;
|
||||||
|
state->objects_marked = 0;
|
||||||
|
state->bytes_marked = 0;
|
||||||
|
state->gray_count = 0;
|
||||||
|
|
||||||
|
rava_gc_scan_roots(g_current_vm);
|
||||||
|
|
||||||
|
rava_gc_process_gray_stack();
|
||||||
|
|
||||||
|
size_t live_before = g_stats.current_live_objects;
|
||||||
|
rava_gc_sweep();
|
||||||
|
|
||||||
|
rava_gc_recycle_blocks();
|
||||||
|
|
||||||
|
size_t freed = live_before - state->objects_marked;
|
||||||
|
g_stats.objects_freed += freed;
|
||||||
|
g_stats.current_live_objects = state->objects_marked;
|
||||||
|
g_stats.current_live_bytes = state->bytes_marked;
|
||||||
|
g_stats.total_collections++;
|
||||||
|
|
||||||
|
state->gc_active = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
void rava_gc_collect_if_needed(void) {
|
||||||
|
RavaGCHeap_t *heap = rava_gc_get_heap();
|
||||||
|
|
||||||
|
if (heap->total_allocated > heap->gc_threshold) {
|
||||||
|
rava_gc_collect();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void rava_gc_enable(void) {
|
||||||
|
RavaGCState_t *state = rava_gc_get_state();
|
||||||
|
state->gc_enabled = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void rava_gc_disable(void) {
|
||||||
|
RavaGCState_t *state = rava_gc_get_state();
|
||||||
|
state->gc_enabled = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool rava_gc_is_enabled(void) {
|
||||||
|
RavaGCState_t *state = rava_gc_get_state();
|
||||||
|
return state->gc_enabled;
|
||||||
|
}
|
||||||
|
|
||||||
|
void rava_gc_pin(void *ptr) {
|
||||||
|
if (!ptr) return;
|
||||||
|
RavaGCHeader_t *header = (RavaGCHeader_t*)ptr;
|
||||||
|
header->gc_flags |= RAVA_GC_FLAG_PINNED;
|
||||||
|
}
|
||||||
|
|
||||||
|
void rava_gc_unpin(void *ptr) {
|
||||||
|
if (!ptr) return;
|
||||||
|
RavaGCHeader_t *header = (RavaGCHeader_t*)ptr;
|
||||||
|
header->gc_flags &= ~RAVA_GC_FLAG_PINNED;
|
||||||
|
}
|
||||||
|
|
||||||
|
RavaGCStats_t rava_gc_get_stats(void) {
|
||||||
|
return g_stats;
|
||||||
|
}
|
||||||
|
|
||||||
|
void rava_gc_print_stats(void) {
|
||||||
|
printf("GC Statistics:\n");
|
||||||
|
printf(" Total collections: %zu\n", g_stats.total_collections);
|
||||||
|
printf(" Objects allocated: %zu\n", g_stats.objects_allocated);
|
||||||
|
printf(" Objects freed: %zu\n", g_stats.objects_freed);
|
||||||
|
printf(" Current live objects: %zu\n", g_stats.current_live_objects);
|
||||||
|
printf(" Current live bytes: %zu\n", g_stats.current_live_bytes);
|
||||||
|
printf(" Peak live bytes: %zu\n", g_stats.peak_live_bytes);
|
||||||
|
}
|
||||||
85
runtime/gc/gc.h
Normal file
85
runtime/gc/gc.h
Normal file
@ -0,0 +1,85 @@
|
|||||||
|
#ifndef RAVA_GC_H
|
||||||
|
#define RAVA_GC_H
|
||||||
|
|
||||||
|
#include <stdint.h>
|
||||||
|
#include <stddef.h>
|
||||||
|
#include <stdbool.h>
|
||||||
|
|
||||||
|
#define RAVA_GC_BLOCK_SIZE (32 * 1024)
|
||||||
|
#define RAVA_GC_LINE_SIZE 128
|
||||||
|
#define RAVA_GC_LINES_PER_BLOCK (RAVA_GC_BLOCK_SIZE / RAVA_GC_LINE_SIZE)
|
||||||
|
|
||||||
|
#define RAVA_GC_GRAY_STACK_SIZE 4096
|
||||||
|
|
||||||
|
#define RAVA_GC_INITIAL_THRESHOLD (1024 * 1024)
|
||||||
|
|
||||||
|
#define RAVA_ALIGN(size, align) (((size) + (align) - 1) & ~((align) - 1))
|
||||||
|
|
||||||
|
struct RavaGCHeader;
|
||||||
|
typedef struct RavaGCHeader RavaGCHeader_t;
|
||||||
|
|
||||||
|
typedef struct RavaGCBlock {
|
||||||
|
uint8_t line_marks[RAVA_GC_LINES_PER_BLOCK];
|
||||||
|
uint8_t flags;
|
||||||
|
uint16_t free_lines;
|
||||||
|
struct RavaGCBlock *next;
|
||||||
|
struct RavaGCBlock *prev;
|
||||||
|
uint8_t data[RAVA_GC_BLOCK_SIZE];
|
||||||
|
} RavaGCBlock_t;
|
||||||
|
|
||||||
|
#define RAVA_GC_BLOCK_FLAG_EVACUATE 0x01
|
||||||
|
#define RAVA_GC_BLOCK_FLAG_FULL 0x02
|
||||||
|
|
||||||
|
typedef struct RavaGCHeap {
|
||||||
|
RavaGCBlock_t *all_blocks;
|
||||||
|
RavaGCBlock_t *current_block;
|
||||||
|
uint8_t *bump_ptr;
|
||||||
|
uint8_t *block_limit;
|
||||||
|
RavaGCBlock_t *free_blocks;
|
||||||
|
RavaGCBlock_t *recyclable_blocks;
|
||||||
|
size_t total_allocated;
|
||||||
|
size_t live_bytes;
|
||||||
|
size_t gc_threshold;
|
||||||
|
RavaGCHeader_t *all_objects;
|
||||||
|
} RavaGCHeap_t;
|
||||||
|
|
||||||
|
typedef struct RavaGCStats {
|
||||||
|
size_t total_collections;
|
||||||
|
size_t objects_allocated;
|
||||||
|
size_t objects_freed;
|
||||||
|
size_t bytes_allocated;
|
||||||
|
size_t bytes_freed;
|
||||||
|
size_t current_live_objects;
|
||||||
|
size_t current_live_bytes;
|
||||||
|
size_t peak_live_bytes;
|
||||||
|
} RavaGCStats_t;
|
||||||
|
|
||||||
|
typedef struct RavaGCState {
|
||||||
|
RavaGCHeader_t *gray_stack[RAVA_GC_GRAY_STACK_SIZE];
|
||||||
|
size_t gray_count;
|
||||||
|
bool gc_active;
|
||||||
|
bool gc_enabled;
|
||||||
|
size_t objects_marked;
|
||||||
|
size_t bytes_marked;
|
||||||
|
} RavaGCState_t;
|
||||||
|
|
||||||
|
void rava_gc_init(void);
|
||||||
|
void rava_gc_shutdown(void);
|
||||||
|
|
||||||
|
void* rava_gc_alloc(size_t size, uint8_t type);
|
||||||
|
void rava_gc_free(void *ptr);
|
||||||
|
|
||||||
|
void rava_gc_collect(void);
|
||||||
|
void rava_gc_collect_if_needed(void);
|
||||||
|
|
||||||
|
void rava_gc_enable(void);
|
||||||
|
void rava_gc_disable(void);
|
||||||
|
bool rava_gc_is_enabled(void);
|
||||||
|
|
||||||
|
void rava_gc_pin(void *ptr);
|
||||||
|
void rava_gc_unpin(void *ptr);
|
||||||
|
|
||||||
|
RavaGCStats_t rava_gc_get_stats(void);
|
||||||
|
void rava_gc_print_stats(void);
|
||||||
|
|
||||||
|
#endif
|
||||||
188
runtime/gc/gc_heap.c
Normal file
188
runtime/gc/gc_heap.c
Normal file
@ -0,0 +1,188 @@
|
|||||||
|
#include "gc_heap.h"
|
||||||
|
#include "../runtime.h"
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
|
static RavaGCHeap_t g_heap;
|
||||||
|
|
||||||
|
void rava_gc_heap_init(void) {
|
||||||
|
memset(&g_heap, 0, sizeof(g_heap));
|
||||||
|
g_heap.gc_threshold = RAVA_GC_INITIAL_THRESHOLD;
|
||||||
|
g_heap.all_blocks = NULL;
|
||||||
|
g_heap.current_block = NULL;
|
||||||
|
g_heap.free_blocks = NULL;
|
||||||
|
g_heap.recyclable_blocks = NULL;
|
||||||
|
g_heap.all_objects = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
void rava_gc_heap_shutdown(void) {
|
||||||
|
RavaGCBlock_t *block = g_heap.all_blocks;
|
||||||
|
while (block) {
|
||||||
|
RavaGCBlock_t *next = block->next;
|
||||||
|
free(block);
|
||||||
|
block = next;
|
||||||
|
}
|
||||||
|
|
||||||
|
block = g_heap.free_blocks;
|
||||||
|
while (block) {
|
||||||
|
RavaGCBlock_t *next = block->next;
|
||||||
|
free(block);
|
||||||
|
block = next;
|
||||||
|
}
|
||||||
|
|
||||||
|
memset(&g_heap, 0, sizeof(g_heap));
|
||||||
|
}
|
||||||
|
|
||||||
|
static RavaGCBlock_t* _rava_gc_create_block(void) {
|
||||||
|
RavaGCBlock_t *block = calloc(1, sizeof(RavaGCBlock_t));
|
||||||
|
if (!block) return NULL;
|
||||||
|
|
||||||
|
block->flags = 0;
|
||||||
|
block->free_lines = RAVA_GC_LINES_PER_BLOCK;
|
||||||
|
memset(block->line_marks, 0, sizeof(block->line_marks));
|
||||||
|
|
||||||
|
return block;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool rava_gc_request_block(void) {
|
||||||
|
if (g_heap.free_blocks) {
|
||||||
|
RavaGCBlock_t *block = g_heap.free_blocks;
|
||||||
|
g_heap.free_blocks = block->next;
|
||||||
|
|
||||||
|
block->next = g_heap.all_blocks;
|
||||||
|
block->prev = NULL;
|
||||||
|
if (g_heap.all_blocks) {
|
||||||
|
g_heap.all_blocks->prev = block;
|
||||||
|
}
|
||||||
|
g_heap.all_blocks = block;
|
||||||
|
|
||||||
|
g_heap.current_block = block;
|
||||||
|
g_heap.bump_ptr = block->data;
|
||||||
|
g_heap.block_limit = block->data + RAVA_GC_BLOCK_SIZE;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (g_heap.recyclable_blocks) {
|
||||||
|
RavaGCBlock_t *block = g_heap.recyclable_blocks;
|
||||||
|
g_heap.recyclable_blocks = block->next;
|
||||||
|
|
||||||
|
block->next = g_heap.all_blocks;
|
||||||
|
block->prev = NULL;
|
||||||
|
if (g_heap.all_blocks) {
|
||||||
|
g_heap.all_blocks->prev = block;
|
||||||
|
}
|
||||||
|
g_heap.all_blocks = block;
|
||||||
|
|
||||||
|
g_heap.current_block = block;
|
||||||
|
g_heap.bump_ptr = block->data;
|
||||||
|
g_heap.block_limit = block->data + RAVA_GC_BLOCK_SIZE;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
RavaGCBlock_t *block = _rava_gc_create_block();
|
||||||
|
if (!block) return false;
|
||||||
|
|
||||||
|
block->next = g_heap.all_blocks;
|
||||||
|
block->prev = NULL;
|
||||||
|
if (g_heap.all_blocks) {
|
||||||
|
g_heap.all_blocks->prev = block;
|
||||||
|
}
|
||||||
|
g_heap.all_blocks = block;
|
||||||
|
|
||||||
|
g_heap.current_block = block;
|
||||||
|
g_heap.bump_ptr = block->data;
|
||||||
|
g_heap.block_limit = block->data + RAVA_GC_BLOCK_SIZE;
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void* rava_gc_heap_alloc(size_t size, uint8_t type) {
|
||||||
|
size = RAVA_ALIGN(size, 8);
|
||||||
|
|
||||||
|
if (size > RAVA_GC_BLOCK_SIZE) {
|
||||||
|
RavaGCHeader_t *obj = calloc(1, size);
|
||||||
|
if (!obj) return NULL;
|
||||||
|
|
||||||
|
obj->gc_type = type;
|
||||||
|
obj->gc_mark = RAVA_GC_WHITE;
|
||||||
|
obj->gc_age = 0;
|
||||||
|
obj->gc_flags = RAVA_GC_FLAG_PINNED;
|
||||||
|
obj->gc_size = (uint32_t)size;
|
||||||
|
|
||||||
|
obj->gc_next = g_heap.all_objects;
|
||||||
|
g_heap.all_objects = obj;
|
||||||
|
|
||||||
|
g_heap.total_allocated += size;
|
||||||
|
return obj;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!g_heap.current_block || g_heap.bump_ptr + size > g_heap.block_limit) {
|
||||||
|
if (!rava_gc_request_block()) {
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
RavaGCHeader_t *obj = (RavaGCHeader_t*)g_heap.bump_ptr;
|
||||||
|
g_heap.bump_ptr += size;
|
||||||
|
g_heap.total_allocated += size;
|
||||||
|
|
||||||
|
obj->gc_type = type;
|
||||||
|
obj->gc_mark = RAVA_GC_WHITE;
|
||||||
|
obj->gc_age = 0;
|
||||||
|
obj->gc_flags = 0;
|
||||||
|
obj->gc_size = (uint32_t)size;
|
||||||
|
|
||||||
|
obj->gc_next = g_heap.all_objects;
|
||||||
|
g_heap.all_objects = obj;
|
||||||
|
|
||||||
|
return obj;
|
||||||
|
}
|
||||||
|
|
||||||
|
void rava_gc_heap_free(void *ptr, size_t size) {
|
||||||
|
(void)ptr;
|
||||||
|
(void)size;
|
||||||
|
}
|
||||||
|
|
||||||
|
void rava_gc_recycle_blocks(void) {
|
||||||
|
RavaGCBlock_t *block = g_heap.all_blocks;
|
||||||
|
RavaGCBlock_t *prev = NULL;
|
||||||
|
|
||||||
|
while (block) {
|
||||||
|
RavaGCBlock_t *next = block->next;
|
||||||
|
|
||||||
|
bool has_live = false;
|
||||||
|
for (size_t i = 0; i < RAVA_GC_LINES_PER_BLOCK; i++) {
|
||||||
|
if (block->line_marks[i]) {
|
||||||
|
has_live = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!has_live && block != g_heap.current_block) {
|
||||||
|
if (prev) {
|
||||||
|
prev->next = next;
|
||||||
|
} else {
|
||||||
|
g_heap.all_blocks = next;
|
||||||
|
}
|
||||||
|
if (next) {
|
||||||
|
next->prev = prev;
|
||||||
|
}
|
||||||
|
|
||||||
|
block->next = g_heap.free_blocks;
|
||||||
|
block->prev = NULL;
|
||||||
|
g_heap.free_blocks = block;
|
||||||
|
|
||||||
|
memset(block->line_marks, 0, sizeof(block->line_marks));
|
||||||
|
block->flags = 0;
|
||||||
|
block->free_lines = RAVA_GC_LINES_PER_BLOCK;
|
||||||
|
} else {
|
||||||
|
prev = block;
|
||||||
|
}
|
||||||
|
|
||||||
|
block = next;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
RavaGCHeap_t* rava_gc_get_heap(void) {
|
||||||
|
return &g_heap;
|
||||||
|
}
|
||||||
17
runtime/gc/gc_heap.h
Normal file
17
runtime/gc/gc_heap.h
Normal file
@ -0,0 +1,17 @@
|
|||||||
|
#ifndef RAVA_GC_HEAP_H
|
||||||
|
#define RAVA_GC_HEAP_H
|
||||||
|
|
||||||
|
#include "gc.h"
|
||||||
|
|
||||||
|
void rava_gc_heap_init(void);
|
||||||
|
void rava_gc_heap_shutdown(void);
|
||||||
|
|
||||||
|
void* rava_gc_heap_alloc(size_t size, uint8_t type);
|
||||||
|
void rava_gc_heap_free(void *ptr, size_t size);
|
||||||
|
|
||||||
|
bool rava_gc_request_block(void);
|
||||||
|
void rava_gc_recycle_blocks(void);
|
||||||
|
|
||||||
|
RavaGCHeap_t* rava_gc_get_heap(void);
|
||||||
|
|
||||||
|
#endif
|
||||||
108
runtime/gc/gc_mark.c
Normal file
108
runtime/gc/gc_mark.c
Normal file
@ -0,0 +1,108 @@
|
|||||||
|
#include "gc_mark.h"
|
||||||
|
#include "gc_roots.h"
|
||||||
|
#include "../runtime.h"
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
|
static RavaGCState_t g_gc_state;
|
||||||
|
|
||||||
|
void rava_gc_mark_init(void) {
|
||||||
|
memset(&g_gc_state, 0, sizeof(g_gc_state));
|
||||||
|
g_gc_state.gc_enabled = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
RavaGCState_t* rava_gc_get_state(void) {
|
||||||
|
return &g_gc_state;
|
||||||
|
}
|
||||||
|
|
||||||
|
void rava_gc_mark_object(RavaGCHeader_t *obj) {
|
||||||
|
if (!obj || obj->gc_mark != RAVA_GC_WHITE) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
obj->gc_mark = RAVA_GC_GRAY;
|
||||||
|
|
||||||
|
if (g_gc_state.gray_count < RAVA_GC_GRAY_STACK_SIZE) {
|
||||||
|
g_gc_state.gray_stack[g_gc_state.gray_count++] = obj;
|
||||||
|
} else {
|
||||||
|
rava_gc_process_object(obj);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void _rava_gc_trace_object(RavaObject_t *obj) {
|
||||||
|
for (size_t i = 0; i < obj->field_count; i++) {
|
||||||
|
rava_gc_mark_value(obj->field_values[i]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void _rava_gc_trace_array(RavaArray_t *arr) {
|
||||||
|
if (arr->element_type == RAVA_VAL_OBJECT ||
|
||||||
|
arr->element_type == RAVA_VAL_ARRAY) {
|
||||||
|
RavaValue_t *values = (RavaValue_t*)arr->data;
|
||||||
|
for (size_t i = 0; i < arr->length; i++) {
|
||||||
|
rava_gc_mark_value(values[i]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void _rava_gc_trace_arraylist(RavaArrayList_t *list) {
|
||||||
|
for (size_t i = 0; i < list->size; i++) {
|
||||||
|
rava_gc_mark_value(list->data[i]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void _rava_gc_trace_hashmap(RavaHashMap_t *map) {
|
||||||
|
for (size_t i = 0; i < map->bucket_count; i++) {
|
||||||
|
if (map->buckets[i].occupied) {
|
||||||
|
rava_gc_mark_value(map->buckets[i].value);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void _rava_gc_trace_methodref(RavaMethodRef_t *ref) {
|
||||||
|
if (ref->has_target) {
|
||||||
|
rava_gc_mark_value(ref->target);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void rava_gc_process_object(RavaGCHeader_t *obj) {
|
||||||
|
obj->gc_mark = RAVA_GC_BLACK;
|
||||||
|
g_gc_state.objects_marked++;
|
||||||
|
g_gc_state.bytes_marked += obj->gc_size;
|
||||||
|
|
||||||
|
switch (obj->gc_type) {
|
||||||
|
case RAVA_GC_TYPE_OBJECT: {
|
||||||
|
RavaObject_t *o = (RavaObject_t*)obj;
|
||||||
|
_rava_gc_trace_object(o);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case RAVA_GC_TYPE_ARRAY: {
|
||||||
|
RavaArray_t *a = (RavaArray_t*)obj;
|
||||||
|
_rava_gc_trace_array(a);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case RAVA_GC_TYPE_ARRAYLIST: {
|
||||||
|
RavaArrayList_t *l = (RavaArrayList_t*)obj;
|
||||||
|
_rava_gc_trace_arraylist(l);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case RAVA_GC_TYPE_HASHMAP: {
|
||||||
|
RavaHashMap_t *m = (RavaHashMap_t*)obj;
|
||||||
|
_rava_gc_trace_hashmap(m);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case RAVA_GC_TYPE_METHODREF: {
|
||||||
|
RavaMethodRef_t *r = (RavaMethodRef_t*)obj;
|
||||||
|
_rava_gc_trace_methodref(r);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void rava_gc_process_gray_stack(void) {
|
||||||
|
while (g_gc_state.gray_count > 0) {
|
||||||
|
RavaGCHeader_t *obj = g_gc_state.gray_stack[--g_gc_state.gray_count];
|
||||||
|
rava_gc_process_object(obj);
|
||||||
|
}
|
||||||
|
}
|
||||||
13
runtime/gc/gc_mark.h
Normal file
13
runtime/gc/gc_mark.h
Normal file
@ -0,0 +1,13 @@
|
|||||||
|
#ifndef RAVA_GC_MARK_H
|
||||||
|
#define RAVA_GC_MARK_H
|
||||||
|
|
||||||
|
#include "gc.h"
|
||||||
|
|
||||||
|
void rava_gc_mark_init(void);
|
||||||
|
void rava_gc_mark_object(RavaGCHeader_t *obj);
|
||||||
|
void rava_gc_process_gray_stack(void);
|
||||||
|
void rava_gc_process_object(RavaGCHeader_t *obj);
|
||||||
|
|
||||||
|
RavaGCState_t* rava_gc_get_state(void);
|
||||||
|
|
||||||
|
#endif
|
||||||
126
runtime/gc/gc_roots.c
Normal file
126
runtime/gc/gc_roots.c
Normal file
@ -0,0 +1,126 @@
|
|||||||
|
#include "gc_roots.h"
|
||||||
|
#include "gc_mark.h"
|
||||||
|
#include "../runtime.h"
|
||||||
|
#include "../fastframe.h"
|
||||||
|
#include "../nanbox.h"
|
||||||
|
|
||||||
|
void rava_gc_mark_value(RavaValue_t value) {
|
||||||
|
switch (value.type) {
|
||||||
|
case RAVA_VAL_OBJECT:
|
||||||
|
if (value.data.object_val) {
|
||||||
|
rava_gc_mark_object(&value.data.object_val->gc);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case RAVA_VAL_ARRAY:
|
||||||
|
if (value.data.array_val) {
|
||||||
|
rava_gc_mark_object(&value.data.array_val->gc);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case RAVA_VAL_ARRAYLIST:
|
||||||
|
if (value.data.arraylist_val) {
|
||||||
|
rava_gc_mark_object(&value.data.arraylist_val->gc);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case RAVA_VAL_HASHMAP:
|
||||||
|
if (value.data.hashmap_val) {
|
||||||
|
rava_gc_mark_object(&value.data.hashmap_val->gc);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case RAVA_VAL_SOCKET:
|
||||||
|
if (value.data.socket_val) {
|
||||||
|
rava_gc_mark_object(&value.data.socket_val->gc);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case RAVA_VAL_STREAM:
|
||||||
|
if (value.data.stream_val) {
|
||||||
|
rava_gc_mark_object(&value.data.stream_val->gc);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case RAVA_VAL_METHOD_REF:
|
||||||
|
if (value.data.method_ref_val) {
|
||||||
|
rava_gc_mark_object(&value.data.method_ref_val->gc);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void rava_gc_mark_nanbox(uint64_t v) {
|
||||||
|
if (rava_nanbox_is_object(v)) {
|
||||||
|
void *ptr = rava_nanbox_as_object(v);
|
||||||
|
if (ptr) {
|
||||||
|
RavaObject_t *obj = (RavaObject_t*)ptr;
|
||||||
|
rava_gc_mark_object(&obj->gc);
|
||||||
|
}
|
||||||
|
} else if (rava_nanbox_is_array(v)) {
|
||||||
|
void *ptr = rava_nanbox_as_array(v);
|
||||||
|
if (ptr) {
|
||||||
|
RavaArray_t *arr = (RavaArray_t*)ptr;
|
||||||
|
rava_gc_mark_object(&arr->gc);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void rava_gc_mark_string(const char *str) {
|
||||||
|
(void)str;
|
||||||
|
}
|
||||||
|
|
||||||
|
void rava_gc_scan_roots(RavaVM_t *vm) {
|
||||||
|
if (!vm) return;
|
||||||
|
|
||||||
|
if (vm->call_stack) {
|
||||||
|
for (size_t i = 0; i < vm->call_stack->count; i++) {
|
||||||
|
RavaCallFrame_t *frame = vm->call_stack->frames[i];
|
||||||
|
if (!frame) continue;
|
||||||
|
|
||||||
|
for (size_t j = 0; j < frame->local_count; j++) {
|
||||||
|
rava_gc_mark_value(frame->locals[j]);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (frame->operand_stack) {
|
||||||
|
for (size_t j = 0; j < frame->operand_stack->top; j++) {
|
||||||
|
rava_gc_mark_value(frame->operand_stack->values[j]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (frame->has_this) {
|
||||||
|
rava_gc_mark_value(frame->this_ref);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
extern size_t rava_frame_depth;
|
||||||
|
extern FastFrame_t rava_frame_pool[];
|
||||||
|
for (size_t i = 0; i < rava_frame_depth; i++) {
|
||||||
|
FastFrame_t *frame = &rava_frame_pool[i];
|
||||||
|
|
||||||
|
for (size_t j = 0; j < RAVA_MAX_LOCALS_FIXED; j++) {
|
||||||
|
rava_gc_mark_nanbox(frame->locals[j]);
|
||||||
|
}
|
||||||
|
|
||||||
|
for (size_t j = 0; j < frame->stack_top; j++) {
|
||||||
|
rava_gc_mark_nanbox(frame->stack[j]);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (frame->has_this) {
|
||||||
|
rava_gc_mark_nanbox(frame->this_ref);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (vm->static_fields) {
|
||||||
|
for (size_t i = 0; i < vm->static_fields->count; i++) {
|
||||||
|
rava_gc_mark_value(vm->static_fields->fields[i].value);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for (size_t i = 0; i < RAVA_INTERN_TABLE_SIZE; i++) {
|
||||||
|
if (vm->intern_table.strings[i]) {
|
||||||
|
rava_gc_mark_string(vm->intern_table.strings[i]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (vm->has_exception) {
|
||||||
|
rava_gc_mark_value(vm->exception_value);
|
||||||
|
}
|
||||||
|
}
|
||||||
12
runtime/gc/gc_roots.h
Normal file
12
runtime/gc/gc_roots.h
Normal file
@ -0,0 +1,12 @@
|
|||||||
|
#ifndef RAVA_GC_ROOTS_H
|
||||||
|
#define RAVA_GC_ROOTS_H
|
||||||
|
|
||||||
|
#include "gc.h"
|
||||||
|
#include "../runtime.h"
|
||||||
|
|
||||||
|
void rava_gc_scan_roots(RavaVM_t *vm);
|
||||||
|
void rava_gc_mark_value(RavaValue_t value);
|
||||||
|
void rava_gc_mark_nanbox(uint64_t v);
|
||||||
|
void rava_gc_mark_string(const char *str);
|
||||||
|
|
||||||
|
#endif
|
||||||
114
runtime/gc/gc_sweep.c
Normal file
114
runtime/gc/gc_sweep.c
Normal file
@ -0,0 +1,114 @@
|
|||||||
|
#include "gc_sweep.h"
|
||||||
|
#include "gc_heap.h"
|
||||||
|
#include "../runtime.h"
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
|
||||||
|
static void _rava_gc_finalize_object_data(RavaObject_t *o) {
|
||||||
|
free(o->class_name);
|
||||||
|
for (size_t i = 0; i < o->field_count; i++) {
|
||||||
|
free(o->field_names[i]);
|
||||||
|
}
|
||||||
|
free(o->field_names);
|
||||||
|
free(o->field_values);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void _rava_gc_finalize_array_data(RavaArray_t *a) {
|
||||||
|
free(a->data);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void _rava_gc_finalize_arraylist_data(RavaArrayList_t *l) {
|
||||||
|
free(l->data);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void _rava_gc_finalize_hashmap_data(RavaHashMap_t *m) {
|
||||||
|
for (size_t i = 0; i < m->bucket_count; i++) {
|
||||||
|
if (m->buckets[i].occupied) {
|
||||||
|
free(m->buckets[i].key);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
free(m->buckets);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void _rava_gc_finalize_socket_data(RavaSocket_t *s) {
|
||||||
|
if (!s->closed && s->fd >= 0) {
|
||||||
|
close(s->fd);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void _rava_gc_finalize_methodref_data(RavaMethodRef_t *r) {
|
||||||
|
free(r->class_name);
|
||||||
|
free(r->method_name);
|
||||||
|
}
|
||||||
|
|
||||||
|
void rava_gc_finalize_object(RavaGCHeader_t *obj) {
|
||||||
|
switch (obj->gc_type) {
|
||||||
|
case RAVA_GC_TYPE_OBJECT: {
|
||||||
|
RavaObject_t *o = (RavaObject_t*)obj;
|
||||||
|
_rava_gc_finalize_object_data(o);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case RAVA_GC_TYPE_ARRAY: {
|
||||||
|
RavaArray_t *a = (RavaArray_t*)obj;
|
||||||
|
_rava_gc_finalize_array_data(a);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case RAVA_GC_TYPE_ARRAYLIST: {
|
||||||
|
RavaArrayList_t *l = (RavaArrayList_t*)obj;
|
||||||
|
_rava_gc_finalize_arraylist_data(l);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case RAVA_GC_TYPE_HASHMAP: {
|
||||||
|
RavaHashMap_t *m = (RavaHashMap_t*)obj;
|
||||||
|
_rava_gc_finalize_hashmap_data(m);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case RAVA_GC_TYPE_SOCKET: {
|
||||||
|
RavaSocket_t *s = (RavaSocket_t*)obj;
|
||||||
|
_rava_gc_finalize_socket_data(s);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case RAVA_GC_TYPE_METHODREF: {
|
||||||
|
RavaMethodRef_t *r = (RavaMethodRef_t*)obj;
|
||||||
|
_rava_gc_finalize_methodref_data(r);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (obj->gc_flags & RAVA_GC_FLAG_PINNED) {
|
||||||
|
free(obj);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void rava_gc_sweep(void) {
|
||||||
|
RavaGCHeap_t *heap = rava_gc_get_heap();
|
||||||
|
RavaGCHeader_t **ptr = &heap->all_objects;
|
||||||
|
size_t freed_count = 0;
|
||||||
|
size_t freed_bytes = 0;
|
||||||
|
|
||||||
|
while (*ptr) {
|
||||||
|
RavaGCHeader_t *obj = *ptr;
|
||||||
|
|
||||||
|
if (obj->gc_mark == RAVA_GC_WHITE) {
|
||||||
|
*ptr = obj->gc_next;
|
||||||
|
freed_bytes += obj->gc_size;
|
||||||
|
freed_count++;
|
||||||
|
rava_gc_finalize_object(obj);
|
||||||
|
} else {
|
||||||
|
obj->gc_mark = RAVA_GC_WHITE;
|
||||||
|
obj->gc_age++;
|
||||||
|
ptr = &obj->gc_next;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
heap->live_bytes = heap->total_allocated - freed_bytes;
|
||||||
|
heap->total_allocated = heap->live_bytes;
|
||||||
|
|
||||||
|
if (heap->live_bytes > 0) {
|
||||||
|
heap->gc_threshold = heap->live_bytes * 2;
|
||||||
|
} else {
|
||||||
|
heap->gc_threshold = RAVA_GC_INITIAL_THRESHOLD;
|
||||||
|
}
|
||||||
|
}
|
||||||
9
runtime/gc/gc_sweep.h
Normal file
9
runtime/gc/gc_sweep.h
Normal file
@ -0,0 +1,9 @@
|
|||||||
|
#ifndef RAVA_GC_SWEEP_H
|
||||||
|
#define RAVA_GC_SWEEP_H
|
||||||
|
|
||||||
|
#include "gc.h"
|
||||||
|
|
||||||
|
void rava_gc_sweep(void);
|
||||||
|
void rava_gc_finalize_object(RavaGCHeader_t *obj);
|
||||||
|
|
||||||
|
#endif
|
||||||
@ -496,7 +496,14 @@ static inline uint32_t _rava_class_hash(const char *name) {
|
|||||||
return hash & (RAVA_CLASS_HASH_SIZE - 1);
|
return hash & (RAVA_CLASS_HASH_SIZE - 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static bool g_gc_initialized = false;
|
||||||
|
|
||||||
RavaVM_t* rava_vm_create(RavaProgram_t *program) {
|
RavaVM_t* rava_vm_create(RavaProgram_t *program) {
|
||||||
|
if (!g_gc_initialized) {
|
||||||
|
rava_gc_init();
|
||||||
|
g_gc_initialized = true;
|
||||||
|
}
|
||||||
|
|
||||||
RavaVM_t *vm = calloc(1, sizeof(RavaVM_t));
|
RavaVM_t *vm = calloc(1, sizeof(RavaVM_t));
|
||||||
if (!vm) return NULL;
|
if (!vm) return NULL;
|
||||||
vm->program = program;
|
vm->program = program;
|
||||||
@ -504,7 +511,8 @@ RavaVM_t* rava_vm_create(RavaProgram_t *program) {
|
|||||||
vm->static_fields = rava_static_field_table_create();
|
vm->static_fields = rava_static_field_table_create();
|
||||||
vm->method_cache = rava_methodcache_create();
|
vm->method_cache = rava_methodcache_create();
|
||||||
vm->exception_stack = rava_exception_stack_create();
|
vm->exception_stack = rava_exception_stack_create();
|
||||||
if (!vm->call_stack || !vm->static_fields || !vm->method_cache || !vm->exception_stack) {
|
vm->native_registry = rava_native_registry_create();
|
||||||
|
if (!vm->call_stack || !vm->static_fields || !vm->method_cache || !vm->exception_stack || !vm->native_registry) {
|
||||||
rava_vm_destroy(vm);
|
rava_vm_destroy(vm);
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
@ -521,6 +529,8 @@ RavaVM_t* rava_vm_create(RavaProgram_t *program) {
|
|||||||
vm->class_hash[h] = (int)i;
|
vm->class_hash[h] = (int)i;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
rava_gc_set_vm(vm);
|
||||||
|
|
||||||
return vm;
|
return vm;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -532,6 +542,7 @@ void rava_vm_destroy(RavaVM_t *vm) {
|
|||||||
rava_methodcache_destroy((MethodCache_t*)vm->method_cache);
|
rava_methodcache_destroy((MethodCache_t*)vm->method_cache);
|
||||||
}
|
}
|
||||||
rava_exception_stack_destroy(vm->exception_stack);
|
rava_exception_stack_destroy(vm->exception_stack);
|
||||||
|
rava_native_registry_destroy(vm->native_registry);
|
||||||
for (size_t i = 0; i < RAVA_INTERN_TABLE_SIZE; i++) {
|
for (size_t i = 0; i < RAVA_INTERN_TABLE_SIZE; i++) {
|
||||||
free(vm->intern_table.strings[i]);
|
free(vm->intern_table.strings[i]);
|
||||||
}
|
}
|
||||||
@ -951,6 +962,25 @@ static bool _rava_vm_execute_instruction(RavaVM_t *vm, RavaCallFrame_t *frame, R
|
|||||||
if (strcmp(instr->operand.call.method_name, "<init>") == 0 && instr->operand.call.arg_count == 0) {
|
if (strcmp(instr->operand.call.method_name, "<init>") == 0 && instr->operand.call.arg_count == 0) {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
const char *mname = instr->operand.call.method_name;
|
||||||
|
if (strcmp(mname, "hashCode") == 0 && instr->operand.call.arg_count == 0) {
|
||||||
|
rava_stack_push(stack, rava_value_int(rava_object_hashcode(obj_val)));
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if (strcmp(mname, "equals") == 0 && instr->operand.call.arg_count == 1) {
|
||||||
|
rava_stack_push(stack, rava_value_boolean(rava_object_equals(obj_val, args[0])));
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if (strcmp(mname, "toString") == 0 && instr->operand.call.arg_count == 0) {
|
||||||
|
char *str = rava_object_tostring(obj_val);
|
||||||
|
rava_stack_push(stack, rava_value_string(str));
|
||||||
|
free(str);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if (strcmp(mname, "getClass") == 0 && instr->operand.call.arg_count == 0) {
|
||||||
|
rava_stack_push(stack, rava_value_string(rava_object_getclass(obj_val)));
|
||||||
|
break;
|
||||||
|
}
|
||||||
vm->had_error = true;
|
vm->had_error = true;
|
||||||
vm->error_message = malloc(RAVA_ERROR_BUFFER_SIZE);
|
vm->error_message = malloc(RAVA_ERROR_BUFFER_SIZE);
|
||||||
snprintf(vm->error_message, RAVA_ERROR_BUFFER_SIZE, "Method not found: %s.%s",
|
snprintf(vm->error_message, RAVA_ERROR_BUFFER_SIZE, "Method not found: %s.%s",
|
||||||
@ -1524,6 +1554,162 @@ static bool _rava_vm_execute_instruction(RavaVM_t *vm, RavaCallFrame_t *frame, R
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
case RAVA_OP_SOCKET_NEW: {
|
||||||
|
RavaValue_t port_val = rava_stack_pop(stack);
|
||||||
|
RavaValue_t host_val = rava_stack_pop(stack);
|
||||||
|
const char *host = (host_val.type == RAVA_VAL_STRING) ? host_val.data.string_val : "localhost";
|
||||||
|
int port = rava_value_as_int(port_val);
|
||||||
|
RavaSocket_t *sock = rava_socket_create_connected(host, port);
|
||||||
|
rava_stack_push(stack, rava_value_socket(sock));
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
case RAVA_OP_SERVER_SOCKET_NEW: {
|
||||||
|
RavaValue_t port_val = rava_stack_pop(stack);
|
||||||
|
int port = rava_value_as_int(port_val);
|
||||||
|
RavaSocket_t *sock = rava_server_socket_create(port);
|
||||||
|
rava_stack_push(stack, rava_value_socket(sock));
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
case RAVA_OP_SOCKET_CONNECT: {
|
||||||
|
RavaValue_t port_val = rava_stack_pop(stack);
|
||||||
|
RavaValue_t host_val = rava_stack_pop(stack);
|
||||||
|
RavaValue_t sock_val = rava_stack_pop(stack);
|
||||||
|
if (sock_val.type == RAVA_VAL_SOCKET && sock_val.data.socket_val) {
|
||||||
|
const char *host = (host_val.type == RAVA_VAL_STRING) ? host_val.data.string_val : "localhost";
|
||||||
|
int port = rava_value_as_int(port_val);
|
||||||
|
bool result = rava_socket_connect(sock_val.data.socket_val, host, port);
|
||||||
|
rava_stack_push(stack, rava_value_boolean(result));
|
||||||
|
} else {
|
||||||
|
rava_stack_push(stack, rava_value_boolean(false));
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
case RAVA_OP_SERVER_SOCKET_ACCEPT: {
|
||||||
|
RavaValue_t sock_val = rava_stack_pop(stack);
|
||||||
|
if (sock_val.type == RAVA_VAL_SOCKET && sock_val.data.socket_val) {
|
||||||
|
RavaSocket_t *client = rava_server_socket_accept(sock_val.data.socket_val);
|
||||||
|
if (client) {
|
||||||
|
rava_stack_push(stack, rava_value_socket(client));
|
||||||
|
} else {
|
||||||
|
rava_stack_push(stack, rava_value_null());
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
rava_stack_push(stack, rava_value_null());
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
case RAVA_OP_SOCKET_GET_INPUT_STREAM: {
|
||||||
|
RavaValue_t sock_val = rava_stack_pop(stack);
|
||||||
|
if (sock_val.type == RAVA_VAL_SOCKET && sock_val.data.socket_val) {
|
||||||
|
RavaStream_t *stream = rava_socket_get_input_stream(sock_val.data.socket_val);
|
||||||
|
rava_stack_push(stack, rava_value_stream(stream));
|
||||||
|
} else {
|
||||||
|
rava_stack_push(stack, rava_value_null());
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
case RAVA_OP_SOCKET_GET_OUTPUT_STREAM: {
|
||||||
|
RavaValue_t sock_val = rava_stack_pop(stack);
|
||||||
|
if (sock_val.type == RAVA_VAL_SOCKET && sock_val.data.socket_val) {
|
||||||
|
RavaStream_t *stream = rava_socket_get_output_stream(sock_val.data.socket_val);
|
||||||
|
rava_stack_push(stack, rava_value_stream(stream));
|
||||||
|
} else {
|
||||||
|
rava_stack_push(stack, rava_value_null());
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
case RAVA_OP_INPUT_STREAM_READ: {
|
||||||
|
RavaValue_t stream_val = rava_stack_pop(stack);
|
||||||
|
if (stream_val.type == RAVA_VAL_STREAM && stream_val.data.stream_val) {
|
||||||
|
char *data = rava_stream_read(stream_val.data.stream_val);
|
||||||
|
if (data) {
|
||||||
|
rava_stack_push(stack, rava_value_string(data));
|
||||||
|
free(data);
|
||||||
|
} else {
|
||||||
|
rava_stack_push(stack, rava_value_null());
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
rava_stack_push(stack, rava_value_null());
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
case RAVA_OP_OUTPUT_STREAM_WRITE: {
|
||||||
|
int arg_count = instr->operand.int_value;
|
||||||
|
if (arg_count >= 1) {
|
||||||
|
RavaValue_t data_val = rava_stack_pop(stack);
|
||||||
|
RavaValue_t stream_val = rava_stack_pop(stack);
|
||||||
|
if (stream_val.type == RAVA_VAL_STREAM && stream_val.data.stream_val) {
|
||||||
|
if (data_val.type == RAVA_VAL_STRING && data_val.data.string_val) {
|
||||||
|
rava_stream_write(stream_val.data.stream_val, data_val.data.string_val);
|
||||||
|
} else if (data_val.type == RAVA_VAL_INT) {
|
||||||
|
rava_stream_write_byte(stream_val.data.stream_val, data_val.data.int_val);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
case RAVA_OP_SOCKET_CLOSE: {
|
||||||
|
RavaValue_t val = rava_stack_pop(stack);
|
||||||
|
if (val.type == RAVA_VAL_SOCKET && val.data.socket_val) {
|
||||||
|
rava_socket_close(val.data.socket_val);
|
||||||
|
} else if (val.type == RAVA_VAL_STREAM && val.data.stream_val) {
|
||||||
|
rava_stream_close(val.data.stream_val);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
case RAVA_OP_STREAM_CLOSE: {
|
||||||
|
RavaValue_t val = rava_stack_pop(stack);
|
||||||
|
if (val.type == RAVA_VAL_STREAM && val.data.stream_val) {
|
||||||
|
rava_stream_close(val.data.stream_val);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
case RAVA_OP_METHOD_REF: {
|
||||||
|
RavaMethodRef_t *ref = rava_method_ref_create(
|
||||||
|
instr->operand.method_ref.class_name,
|
||||||
|
instr->operand.method_ref.method_name,
|
||||||
|
instr->operand.method_ref.is_constructor,
|
||||||
|
instr->operand.method_ref.is_static
|
||||||
|
);
|
||||||
|
if (!instr->operand.method_ref.is_static && stack->top > 0) {
|
||||||
|
ref->target = rava_stack_pop(stack);
|
||||||
|
ref->has_target = true;
|
||||||
|
}
|
||||||
|
rava_stack_push(stack, rava_value_method_ref(ref));
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
case RAVA_OP_METHOD_REF_INVOKE: {
|
||||||
|
RavaValue_t ref_val = rava_stack_pop(stack);
|
||||||
|
if (ref_val.type != RAVA_VAL_METHOD_REF) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
RavaMethodRef_t *ref = ref_val.data.method_ref_val;
|
||||||
|
if (ref->is_static) {
|
||||||
|
RavaMethod_t *method = rava_vm_find_method(vm, ref->class_name, ref->method_name);
|
||||||
|
if (method) {
|
||||||
|
_rava_vm_call_method(vm, method, instr->operand.call.arg_count, false, NULL);
|
||||||
|
}
|
||||||
|
} else if (ref->has_target) {
|
||||||
|
RavaMethod_t *method = rava_vm_find_method(vm, ref->class_name, ref->method_name);
|
||||||
|
if (method) {
|
||||||
|
rava_stack_push(stack, ref->target);
|
||||||
|
_rava_vm_call_method(vm, method, instr->operand.call.arg_count, true, NULL);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
case RAVA_OP_CURRENT_TIME_MILLIS: {
|
case RAVA_OP_CURRENT_TIME_MILLIS: {
|
||||||
struct timespec ts;
|
struct timespec ts;
|
||||||
clock_gettime(CLOCK_REALTIME, &ts);
|
clock_gettime(CLOCK_REALTIME, &ts);
|
||||||
@ -3244,7 +3430,12 @@ static bool _rava_vm_execute_ultrafast(RavaVM_t *vm, RavaMethod_t *entry_method)
|
|||||||
&&uf_arraylist_new, &&uf_arraylist_add, &&uf_arraylist_get, &&uf_arraylist_set,
|
&&uf_arraylist_new, &&uf_arraylist_add, &&uf_arraylist_get, &&uf_arraylist_set,
|
||||||
&&uf_arraylist_size, &&uf_arraylist_remove, &&uf_arraylist_clear, &&uf_arraylist_isempty,
|
&&uf_arraylist_size, &&uf_arraylist_remove, &&uf_arraylist_clear, &&uf_arraylist_isempty,
|
||||||
&&uf_hashmap_new, &&uf_hashmap_put, &&uf_hashmap_get, &&uf_hashmap_remove,
|
&&uf_hashmap_new, &&uf_hashmap_put, &&uf_hashmap_get, &&uf_hashmap_remove,
|
||||||
&&uf_hashmap_size, &&uf_hashmap_containskey, &&uf_hashmap_clear
|
&&uf_hashmap_size, &&uf_hashmap_containskey, &&uf_hashmap_clear,
|
||||||
|
&&uf_socket_new, &&uf_socket_connect, &&uf_socket_read, &&uf_socket_write,
|
||||||
|
&&uf_socket_close, &&uf_server_socket_new, &&uf_server_socket_accept,
|
||||||
|
&&uf_socket_get_input_stream, &&uf_socket_get_output_stream,
|
||||||
|
&&uf_input_stream_read, &&uf_output_stream_write, &&uf_stream_close,
|
||||||
|
&&uf_method_ref, &&uf_method_ref_invoke
|
||||||
};
|
};
|
||||||
|
|
||||||
rava_fastframe_reset();
|
rava_fastframe_reset();
|
||||||
@ -3628,11 +3819,54 @@ uf_call_virtual: {
|
|||||||
vm->had_error = true;
|
vm->had_error = true;
|
||||||
goto uf_done;
|
goto uf_done;
|
||||||
}
|
}
|
||||||
|
const char *mname = instr->operand.call.method_name;
|
||||||
|
if (!rava_nanbox_is_object(obj_val)) {
|
||||||
|
RavaValue_t val = rava_nanbox_to_value(obj_val);
|
||||||
|
if (strcmp(mname, "hashCode") == 0 && arg_count == 0) {
|
||||||
|
UF_PUSH(rava_nanbox_int(rava_object_hashcode(val)));
|
||||||
|
UF_DISPATCH();
|
||||||
|
}
|
||||||
|
if (strcmp(mname, "equals") == 0 && arg_count == 1) {
|
||||||
|
RavaValue_t other = rava_nanbox_to_value(args[0]);
|
||||||
|
UF_PUSH(rava_nanbox_bool(rava_object_equals(val, other)));
|
||||||
|
UF_DISPATCH();
|
||||||
|
}
|
||||||
|
if (strcmp(mname, "toString") == 0 && arg_count == 0) {
|
||||||
|
char *str = rava_object_tostring(val);
|
||||||
|
UF_PUSH(rava_nanbox_string(str));
|
||||||
|
UF_DISPATCH();
|
||||||
|
}
|
||||||
|
if (strcmp(mname, "getClass") == 0 && arg_count == 0) {
|
||||||
|
UF_PUSH(rava_nanbox_string(rava_object_getclass(val)));
|
||||||
|
UF_DISPATCH();
|
||||||
|
}
|
||||||
|
vm->had_error = true;
|
||||||
|
goto uf_done;
|
||||||
|
}
|
||||||
RavaObject_t *obj = rava_nanbox_as_object(obj_val);
|
RavaObject_t *obj = rava_nanbox_as_object(obj_val);
|
||||||
const char *class_name = obj->class_name;
|
const char *class_name = obj->class_name;
|
||||||
RavaMethod_t *target = _rava_vm_find_method_cached(vm, class_name, instr->operand.call.method_name);
|
RavaMethod_t *target = _rava_vm_find_method_cached(vm, class_name, instr->operand.call.method_name);
|
||||||
if (!target) {
|
if (!target) {
|
||||||
if (strcmp(instr->operand.call.method_name, "<init>") == 0 && arg_count == 0) {
|
if (strcmp(mname, "<init>") == 0 && arg_count == 0) {
|
||||||
|
UF_DISPATCH();
|
||||||
|
}
|
||||||
|
RavaValue_t val = rava_nanbox_to_value(obj_val);
|
||||||
|
if (strcmp(mname, "hashCode") == 0 && arg_count == 0) {
|
||||||
|
UF_PUSH(rava_nanbox_int(rava_object_hashcode(val)));
|
||||||
|
UF_DISPATCH();
|
||||||
|
}
|
||||||
|
if (strcmp(mname, "equals") == 0 && arg_count == 1) {
|
||||||
|
RavaValue_t other = rava_nanbox_to_value(args[0]);
|
||||||
|
UF_PUSH(rava_nanbox_bool(rava_object_equals(val, other)));
|
||||||
|
UF_DISPATCH();
|
||||||
|
}
|
||||||
|
if (strcmp(mname, "toString") == 0 && arg_count == 0) {
|
||||||
|
char *str = rava_object_tostring(val);
|
||||||
|
UF_PUSH(rava_nanbox_string(str));
|
||||||
|
UF_DISPATCH();
|
||||||
|
}
|
||||||
|
if (strcmp(mname, "getClass") == 0 && arg_count == 0) {
|
||||||
|
UF_PUSH(rava_nanbox_string(rava_object_getclass(val)));
|
||||||
UF_DISPATCH();
|
UF_DISPATCH();
|
||||||
}
|
}
|
||||||
vm->had_error = true;
|
vm->had_error = true;
|
||||||
@ -4487,10 +4721,10 @@ uf_arraylist_size: {
|
|||||||
RavaNanboxValue_t coll_nb = UF_POP();
|
RavaNanboxValue_t coll_nb = UF_POP();
|
||||||
void *ptr = rava_nanbox_as_object(coll_nb);
|
void *ptr = rava_nanbox_as_object(coll_nb);
|
||||||
if (ptr) {
|
if (ptr) {
|
||||||
int type = *(int*)ptr;
|
uint8_t gc_type = ((RavaGCHeader_t*)ptr)->gc_type;
|
||||||
if (type == RAVA_COLLECTION_ARRAYLIST) {
|
if (gc_type == RAVA_GC_TYPE_ARRAYLIST) {
|
||||||
UF_PUSH(rava_nanbox_int((int32_t)rava_arraylist_size((RavaArrayList_t*)ptr)));
|
UF_PUSH(rava_nanbox_int((int32_t)rava_arraylist_size((RavaArrayList_t*)ptr)));
|
||||||
} else if (type == RAVA_COLLECTION_HASHMAP) {
|
} else if (gc_type == RAVA_GC_TYPE_HASHMAP) {
|
||||||
UF_PUSH(rava_nanbox_int((int32_t)rava_hashmap_size((RavaHashMap_t*)ptr)));
|
UF_PUSH(rava_nanbox_int((int32_t)rava_hashmap_size((RavaHashMap_t*)ptr)));
|
||||||
} else {
|
} else {
|
||||||
UF_PUSH(rava_nanbox_int(0));
|
UF_PUSH(rava_nanbox_int(0));
|
||||||
@ -4506,15 +4740,15 @@ uf_arraylist_remove: {
|
|||||||
RavaNanboxValue_t coll_nb = UF_POP();
|
RavaNanboxValue_t coll_nb = UF_POP();
|
||||||
void *ptr = rava_nanbox_as_object(coll_nb);
|
void *ptr = rava_nanbox_as_object(coll_nb);
|
||||||
if (ptr) {
|
if (ptr) {
|
||||||
int type = *(int*)ptr;
|
uint8_t gc_type = ((RavaGCHeader_t*)ptr)->gc_type;
|
||||||
if (type == RAVA_COLLECTION_ARRAYLIST && rava_nanbox_is_int(idx_or_key)) {
|
if (gc_type == RAVA_GC_TYPE_ARRAYLIST && rava_nanbox_is_int(idx_or_key)) {
|
||||||
RavaValue_t v = rava_arraylist_remove((RavaArrayList_t*)ptr, (size_t)rava_nanbox_to_int(idx_or_key));
|
RavaValue_t v = rava_arraylist_remove((RavaArrayList_t*)ptr, (size_t)rava_nanbox_to_int(idx_or_key));
|
||||||
if (v.type == RAVA_VAL_INT) {
|
if (v.type == RAVA_VAL_INT) {
|
||||||
UF_PUSH(rava_nanbox_int(v.data.int_val));
|
UF_PUSH(rava_nanbox_int(v.data.int_val));
|
||||||
} else {
|
} else {
|
||||||
UF_PUSH(rava_nanbox_null());
|
UF_PUSH(rava_nanbox_null());
|
||||||
}
|
}
|
||||||
} else if (type == RAVA_COLLECTION_HASHMAP && rava_nanbox_is_string(idx_or_key)) {
|
} else if (gc_type == RAVA_GC_TYPE_HASHMAP && rava_nanbox_is_string(idx_or_key)) {
|
||||||
RavaValue_t v = rava_hashmap_remove((RavaHashMap_t*)ptr, rava_nanbox_as_string(idx_or_key));
|
RavaValue_t v = rava_hashmap_remove((RavaHashMap_t*)ptr, rava_nanbox_as_string(idx_or_key));
|
||||||
if (v.type == RAVA_VAL_INT) {
|
if (v.type == RAVA_VAL_INT) {
|
||||||
UF_PUSH(rava_nanbox_int(v.data.int_val));
|
UF_PUSH(rava_nanbox_int(v.data.int_val));
|
||||||
@ -4534,10 +4768,10 @@ uf_arraylist_clear: {
|
|||||||
RavaNanboxValue_t coll_nb = UF_POP();
|
RavaNanboxValue_t coll_nb = UF_POP();
|
||||||
void *ptr = rava_nanbox_as_object(coll_nb);
|
void *ptr = rava_nanbox_as_object(coll_nb);
|
||||||
if (ptr) {
|
if (ptr) {
|
||||||
int type = *(int*)ptr;
|
uint8_t gc_type = ((RavaGCHeader_t*)ptr)->gc_type;
|
||||||
if (type == RAVA_COLLECTION_ARRAYLIST) {
|
if (gc_type == RAVA_GC_TYPE_ARRAYLIST) {
|
||||||
rava_arraylist_clear((RavaArrayList_t*)ptr);
|
rava_arraylist_clear((RavaArrayList_t*)ptr);
|
||||||
} else if (type == RAVA_COLLECTION_HASHMAP) {
|
} else if (gc_type == RAVA_GC_TYPE_HASHMAP) {
|
||||||
rava_hashmap_clear((RavaHashMap_t*)ptr);
|
rava_hashmap_clear((RavaHashMap_t*)ptr);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -4648,6 +4882,132 @@ uf_hashmap_clear: {
|
|||||||
UF_DISPATCH();
|
UF_DISPATCH();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
uf_socket_new: {
|
||||||
|
RavaNanboxValue_t port_nb = UF_POP();
|
||||||
|
RavaNanboxValue_t host_nb = UF_POP();
|
||||||
|
const char *host = rava_nanbox_is_string(host_nb) ? rava_nanbox_as_string(host_nb) : "localhost";
|
||||||
|
int port = rava_nanbox_as_int(port_nb);
|
||||||
|
RavaSocket_t *sock = rava_socket_create_connected(host, port);
|
||||||
|
UF_PUSH(rava_nanbox_object((void*)sock));
|
||||||
|
UF_DISPATCH();
|
||||||
|
}
|
||||||
|
|
||||||
|
uf_server_socket_new: {
|
||||||
|
RavaNanboxValue_t port_nb = UF_POP();
|
||||||
|
int port = rava_nanbox_as_int(port_nb);
|
||||||
|
RavaSocket_t *sock = rava_server_socket_create(port);
|
||||||
|
UF_PUSH(rava_nanbox_object((void*)sock));
|
||||||
|
UF_DISPATCH();
|
||||||
|
}
|
||||||
|
|
||||||
|
uf_socket_connect: {
|
||||||
|
RavaNanboxValue_t port_nb = UF_POP();
|
||||||
|
RavaNanboxValue_t host_nb = UF_POP();
|
||||||
|
RavaNanboxValue_t sock_nb = UF_POP();
|
||||||
|
RavaSocket_t *sock = (RavaSocket_t*)rava_nanbox_as_object(sock_nb);
|
||||||
|
if (sock) {
|
||||||
|
const char *host = rava_nanbox_is_string(host_nb) ? rava_nanbox_as_string(host_nb) : "localhost";
|
||||||
|
int port = rava_nanbox_as_int(port_nb);
|
||||||
|
bool result = rava_socket_connect(sock, host, port);
|
||||||
|
UF_PUSH(rava_nanbox_int(result ? 1 : 0));
|
||||||
|
} else {
|
||||||
|
UF_PUSH(rava_nanbox_int(0));
|
||||||
|
}
|
||||||
|
UF_DISPATCH();
|
||||||
|
}
|
||||||
|
|
||||||
|
uf_server_socket_accept: {
|
||||||
|
RavaNanboxValue_t sock_nb = UF_POP();
|
||||||
|
RavaSocket_t *server = (RavaSocket_t*)rava_nanbox_as_object(sock_nb);
|
||||||
|
if (server) {
|
||||||
|
RavaSocket_t *client = rava_server_socket_accept(server);
|
||||||
|
if (client) {
|
||||||
|
UF_PUSH(rava_nanbox_object((void*)client));
|
||||||
|
} else {
|
||||||
|
UF_PUSH(rava_nanbox_null());
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
UF_PUSH(rava_nanbox_null());
|
||||||
|
}
|
||||||
|
UF_DISPATCH();
|
||||||
|
}
|
||||||
|
|
||||||
|
uf_socket_get_input_stream: {
|
||||||
|
RavaNanboxValue_t sock_nb = UF_POP();
|
||||||
|
RavaSocket_t *sock = (RavaSocket_t*)rava_nanbox_as_object(sock_nb);
|
||||||
|
if (sock) {
|
||||||
|
RavaStream_t *stream = rava_socket_get_input_stream(sock);
|
||||||
|
UF_PUSH(rava_nanbox_object((void*)stream));
|
||||||
|
} else {
|
||||||
|
UF_PUSH(rava_nanbox_null());
|
||||||
|
}
|
||||||
|
UF_DISPATCH();
|
||||||
|
}
|
||||||
|
|
||||||
|
uf_socket_get_output_stream: {
|
||||||
|
RavaNanboxValue_t sock_nb = UF_POP();
|
||||||
|
RavaSocket_t *sock = (RavaSocket_t*)rava_nanbox_as_object(sock_nb);
|
||||||
|
if (sock) {
|
||||||
|
RavaStream_t *stream = rava_socket_get_output_stream(sock);
|
||||||
|
UF_PUSH(rava_nanbox_object((void*)stream));
|
||||||
|
} else {
|
||||||
|
UF_PUSH(rava_nanbox_null());
|
||||||
|
}
|
||||||
|
UF_DISPATCH();
|
||||||
|
}
|
||||||
|
|
||||||
|
uf_input_stream_read: {
|
||||||
|
RavaNanboxValue_t stream_nb = UF_POP();
|
||||||
|
RavaStream_t *stream = (RavaStream_t*)rava_nanbox_as_object(stream_nb);
|
||||||
|
if (stream) {
|
||||||
|
char *data = rava_stream_read(stream);
|
||||||
|
if (data) {
|
||||||
|
UF_PUSH(rava_nanbox_string(data));
|
||||||
|
free(data);
|
||||||
|
} else {
|
||||||
|
UF_PUSH(rava_nanbox_null());
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
UF_PUSH(rava_nanbox_null());
|
||||||
|
}
|
||||||
|
UF_DISPATCH();
|
||||||
|
}
|
||||||
|
|
||||||
|
uf_output_stream_write: {
|
||||||
|
int arg_count = instr->operand.int_value;
|
||||||
|
if (arg_count >= 1) {
|
||||||
|
RavaNanboxValue_t data_nb = UF_POP();
|
||||||
|
RavaNanboxValue_t stream_nb = UF_POP();
|
||||||
|
RavaStream_t *stream = (RavaStream_t*)rava_nanbox_as_object(stream_nb);
|
||||||
|
if (stream) {
|
||||||
|
if (rava_nanbox_is_string(data_nb)) {
|
||||||
|
rava_stream_write(stream, rava_nanbox_as_string(data_nb));
|
||||||
|
} else if (rava_nanbox_is_int(data_nb)) {
|
||||||
|
rava_stream_write_byte(stream, rava_nanbox_as_int(data_nb));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
UF_DISPATCH();
|
||||||
|
}
|
||||||
|
|
||||||
|
uf_socket_close: {
|
||||||
|
RavaNanboxValue_t val = UF_POP();
|
||||||
|
void *ptr = rava_nanbox_as_object(val);
|
||||||
|
if (ptr) {
|
||||||
|
rava_socket_close((RavaSocket_t*)ptr);
|
||||||
|
}
|
||||||
|
UF_DISPATCH();
|
||||||
|
}
|
||||||
|
|
||||||
|
uf_socket_read:
|
||||||
|
uf_socket_write:
|
||||||
|
uf_stream_close:
|
||||||
|
UF_DISPATCH();
|
||||||
|
|
||||||
|
uf_method_ref:
|
||||||
|
uf_method_ref_invoke:
|
||||||
|
UF_DISPATCH();
|
||||||
|
|
||||||
uf_done:
|
uf_done:
|
||||||
rava_fastframe_reset();
|
rava_fastframe_reset();
|
||||||
return !vm->had_error;
|
return !vm->had_error;
|
||||||
@ -4734,3 +5094,111 @@ RavaValue_t rava_vm_get_result(RavaVM_t *vm) {
|
|||||||
}
|
}
|
||||||
return rava_value_int(0);
|
return rava_value_int(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
RavaNativeValue_t rava_value_to_native(RavaValue_t value) {
|
||||||
|
RavaNativeValue_t native;
|
||||||
|
switch (value.type) {
|
||||||
|
case RAVA_VAL_INT:
|
||||||
|
native.type = RAVA_NATIVE_INT;
|
||||||
|
native.data.int_val = value.data.int_val;
|
||||||
|
break;
|
||||||
|
case RAVA_VAL_LONG:
|
||||||
|
native.type = RAVA_NATIVE_LONG;
|
||||||
|
native.data.long_val = value.data.long_val;
|
||||||
|
break;
|
||||||
|
case RAVA_VAL_FLOAT:
|
||||||
|
case RAVA_VAL_DOUBLE:
|
||||||
|
native.type = RAVA_NATIVE_DOUBLE;
|
||||||
|
native.data.double_val = (value.type == RAVA_VAL_FLOAT) ?
|
||||||
|
(double)value.data.float_val : value.data.double_val;
|
||||||
|
break;
|
||||||
|
case RAVA_VAL_BOOLEAN:
|
||||||
|
native.type = RAVA_NATIVE_BOOLEAN;
|
||||||
|
native.data.bool_val = value.data.bool_val;
|
||||||
|
break;
|
||||||
|
case RAVA_VAL_STRING:
|
||||||
|
native.type = RAVA_NATIVE_STRING;
|
||||||
|
native.data.string_val = value.data.string_val;
|
||||||
|
break;
|
||||||
|
case RAVA_VAL_OBJECT:
|
||||||
|
native.type = RAVA_NATIVE_OBJECT;
|
||||||
|
native.data.object_val = value.data.object_val;
|
||||||
|
break;
|
||||||
|
case RAVA_VAL_ARRAY:
|
||||||
|
native.type = RAVA_NATIVE_ARRAY;
|
||||||
|
native.data.array_val = value.data.array_val;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
native.type = RAVA_NATIVE_VOID;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
return native;
|
||||||
|
}
|
||||||
|
|
||||||
|
RavaValue_t rava_native_to_value(RavaNativeValue_t native) {
|
||||||
|
RavaValue_t value;
|
||||||
|
switch (native.type) {
|
||||||
|
case RAVA_NATIVE_INT:
|
||||||
|
value = rava_value_int(native.data.int_val);
|
||||||
|
break;
|
||||||
|
case RAVA_NATIVE_LONG:
|
||||||
|
value = rava_value_long(native.data.long_val);
|
||||||
|
break;
|
||||||
|
case RAVA_NATIVE_DOUBLE:
|
||||||
|
value = rava_value_double(native.data.double_val);
|
||||||
|
break;
|
||||||
|
case RAVA_NATIVE_BOOLEAN:
|
||||||
|
value = rava_value_boolean(native.data.bool_val);
|
||||||
|
break;
|
||||||
|
case RAVA_NATIVE_STRING:
|
||||||
|
value = rava_value_string(native.data.string_val);
|
||||||
|
break;
|
||||||
|
case RAVA_NATIVE_OBJECT:
|
||||||
|
value.type = RAVA_VAL_OBJECT;
|
||||||
|
value.data.object_val = native.data.object_val;
|
||||||
|
break;
|
||||||
|
case RAVA_NATIVE_ARRAY:
|
||||||
|
value.type = RAVA_VAL_ARRAY;
|
||||||
|
value.data.array_val = native.data.array_val;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
value = rava_value_null();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool rava_vm_load_native_library(RavaVM_t *vm, const char *path) {
|
||||||
|
if (!vm || !vm->native_registry || !path) return false;
|
||||||
|
RavaNativeLibrary_t *lib = rava_native_library_load(vm->native_registry, path);
|
||||||
|
return lib != NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool rava_vm_register_native(RavaVM_t *vm, const char *class_name, const char *method_name,
|
||||||
|
RavaNativeType_e return_type, RavaNativeType_e *param_types,
|
||||||
|
size_t param_count, RavaNativeFunction_fn function, void *user_data) {
|
||||||
|
if (!vm || !vm->native_registry) return false;
|
||||||
|
return rava_native_register_method(vm->native_registry, class_name, method_name,
|
||||||
|
return_type, param_types, param_count, function, user_data);
|
||||||
|
}
|
||||||
|
|
||||||
|
RavaValue_t rava_vm_call_native(RavaVM_t *vm, const char *class_name, const char *method_name,
|
||||||
|
RavaValue_t *args, size_t arg_count) {
|
||||||
|
if (!vm || !vm->native_registry) return rava_value_null();
|
||||||
|
|
||||||
|
RavaNativeMethod_t *method = rava_native_find_method(vm->native_registry, class_name, method_name);
|
||||||
|
if (!method) {
|
||||||
|
vm->had_error = true;
|
||||||
|
vm->error_message = malloc(256);
|
||||||
|
snprintf(vm->error_message, 256, "Native method not found: %s.%s", class_name, method_name);
|
||||||
|
return rava_value_null();
|
||||||
|
}
|
||||||
|
|
||||||
|
RavaNativeValue_t native_args[RAVA_MAX_METHOD_PARAMS];
|
||||||
|
for (size_t i = 0; i < arg_count && i < RAVA_MAX_METHOD_PARAMS; i++) {
|
||||||
|
native_args[i] = rava_value_to_native(args[i]);
|
||||||
|
}
|
||||||
|
|
||||||
|
RavaNativeValue_t result = rava_native_invoke(method, native_args, arg_count);
|
||||||
|
return rava_native_to_value(result);
|
||||||
|
}
|
||||||
|
|||||||
@ -3,10 +3,20 @@
|
|||||||
|
|
||||||
#include "../ir/ir.h"
|
#include "../ir/ir.h"
|
||||||
#include "../types/types.h"
|
#include "../types/types.h"
|
||||||
|
#include "../loader/loader.h"
|
||||||
#include <stddef.h>
|
#include <stddef.h>
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
#include <stdbool.h>
|
#include <stdbool.h>
|
||||||
|
|
||||||
|
typedef struct RavaGCHeader {
|
||||||
|
uint8_t gc_type;
|
||||||
|
uint8_t gc_mark;
|
||||||
|
uint8_t gc_age;
|
||||||
|
uint8_t gc_flags;
|
||||||
|
uint32_t gc_size;
|
||||||
|
struct RavaGCHeader *gc_next;
|
||||||
|
} RavaGCHeader_t;
|
||||||
|
|
||||||
typedef enum {
|
typedef enum {
|
||||||
RAVA_VAL_INT,
|
RAVA_VAL_INT,
|
||||||
RAVA_VAL_LONG,
|
RAVA_VAL_LONG,
|
||||||
@ -19,10 +29,14 @@ typedef enum {
|
|||||||
RAVA_VAL_ARRAY,
|
RAVA_VAL_ARRAY,
|
||||||
RAVA_VAL_STRING,
|
RAVA_VAL_STRING,
|
||||||
RAVA_VAL_ARRAYLIST,
|
RAVA_VAL_ARRAYLIST,
|
||||||
RAVA_VAL_HASHMAP
|
RAVA_VAL_HASHMAP,
|
||||||
|
RAVA_VAL_SOCKET,
|
||||||
|
RAVA_VAL_STREAM,
|
||||||
|
RAVA_VAL_METHOD_REF
|
||||||
} RavaValueType_e;
|
} RavaValueType_e;
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
|
RavaGCHeader_t gc;
|
||||||
RavaValueType_e element_type;
|
RavaValueType_e element_type;
|
||||||
size_t length;
|
size_t length;
|
||||||
void *data;
|
void *data;
|
||||||
@ -32,10 +46,14 @@ typedef struct RavaObject_t RavaObject_t;
|
|||||||
typedef struct RavaValue_t RavaValue_t;
|
typedef struct RavaValue_t RavaValue_t;
|
||||||
typedef struct RavaArrayList_t RavaArrayList_t;
|
typedef struct RavaArrayList_t RavaArrayList_t;
|
||||||
typedef struct RavaHashMap_t RavaHashMap_t;
|
typedef struct RavaHashMap_t RavaHashMap_t;
|
||||||
|
typedef struct RavaSocket_t RavaSocket_t;
|
||||||
|
typedef struct RavaStream_t RavaStream_t;
|
||||||
|
typedef struct RavaMethodRef_t RavaMethodRef_t;
|
||||||
|
|
||||||
#define RAVA_OBJECT_HASH_SIZE 32
|
#define RAVA_OBJECT_HASH_SIZE 32
|
||||||
|
|
||||||
struct RavaObject_t {
|
struct RavaObject_t {
|
||||||
|
RavaGCHeader_t gc;
|
||||||
char *class_name;
|
char *class_name;
|
||||||
char **field_names;
|
char **field_names;
|
||||||
RavaValue_t *field_values;
|
RavaValue_t *field_values;
|
||||||
@ -58,6 +76,9 @@ struct RavaValue_t {
|
|||||||
char *string_val;
|
char *string_val;
|
||||||
RavaArrayList_t *arraylist_val;
|
RavaArrayList_t *arraylist_val;
|
||||||
RavaHashMap_t *hashmap_val;
|
RavaHashMap_t *hashmap_val;
|
||||||
|
RavaSocket_t *socket_val;
|
||||||
|
RavaStream_t *stream_val;
|
||||||
|
RavaMethodRef_t *method_ref_val;
|
||||||
} data;
|
} data;
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -65,6 +86,7 @@ struct RavaValue_t {
|
|||||||
#define RAVA_COLLECTION_HASHMAP 2
|
#define RAVA_COLLECTION_HASHMAP 2
|
||||||
|
|
||||||
struct RavaArrayList_t {
|
struct RavaArrayList_t {
|
||||||
|
RavaGCHeader_t gc;
|
||||||
int collection_type;
|
int collection_type;
|
||||||
RavaValue_t *data;
|
RavaValue_t *data;
|
||||||
size_t size;
|
size_t size;
|
||||||
@ -80,12 +102,44 @@ typedef struct {
|
|||||||
} RavaHashMapEntry_t;
|
} RavaHashMapEntry_t;
|
||||||
|
|
||||||
struct RavaHashMap_t {
|
struct RavaHashMap_t {
|
||||||
|
RavaGCHeader_t gc;
|
||||||
int collection_type;
|
int collection_type;
|
||||||
RavaHashMapEntry_t *buckets;
|
RavaHashMapEntry_t *buckets;
|
||||||
size_t bucket_count;
|
size_t bucket_count;
|
||||||
size_t size;
|
size_t size;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
#define RAVA_SOCKET_TYPE_CLIENT 1
|
||||||
|
#define RAVA_SOCKET_TYPE_SERVER 2
|
||||||
|
|
||||||
|
struct RavaSocket_t {
|
||||||
|
RavaGCHeader_t gc;
|
||||||
|
int socket_type;
|
||||||
|
int fd;
|
||||||
|
bool connected;
|
||||||
|
bool closed;
|
||||||
|
};
|
||||||
|
|
||||||
|
#define RAVA_STREAM_TYPE_INPUT 1
|
||||||
|
#define RAVA_STREAM_TYPE_OUTPUT 2
|
||||||
|
|
||||||
|
struct RavaStream_t {
|
||||||
|
RavaGCHeader_t gc;
|
||||||
|
int stream_type;
|
||||||
|
int fd;
|
||||||
|
bool closed;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct RavaMethodRef_t {
|
||||||
|
RavaGCHeader_t gc;
|
||||||
|
char *class_name;
|
||||||
|
char *method_name;
|
||||||
|
bool is_constructor;
|
||||||
|
bool is_static;
|
||||||
|
RavaValue_t target;
|
||||||
|
bool has_target;
|
||||||
|
};
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
RavaValue_t *values;
|
RavaValue_t *values;
|
||||||
size_t capacity;
|
size_t capacity;
|
||||||
@ -162,6 +216,7 @@ typedef struct {
|
|||||||
RavaCallStack_t *call_stack;
|
RavaCallStack_t *call_stack;
|
||||||
RavaStaticFieldTable_t *static_fields;
|
RavaStaticFieldTable_t *static_fields;
|
||||||
struct MethodCache_s *method_cache;
|
struct MethodCache_s *method_cache;
|
||||||
|
RavaNativeRegistry_t *native_registry;
|
||||||
char *error_message;
|
char *error_message;
|
||||||
bool had_error;
|
bool had_error;
|
||||||
bool has_exception;
|
bool has_exception;
|
||||||
@ -270,6 +325,11 @@ int rava_object_get_field_index(RavaObject_t *obj, const char *name);
|
|||||||
RavaValue_t rava_object_get_field_by_index(RavaObject_t *obj, int index);
|
RavaValue_t rava_object_get_field_by_index(RavaObject_t *obj, int index);
|
||||||
void rava_object_set_field_by_index(RavaObject_t *obj, int index, RavaValue_t value);
|
void rava_object_set_field_by_index(RavaObject_t *obj, int index, RavaValue_t value);
|
||||||
|
|
||||||
|
int32_t rava_object_hashcode(RavaValue_t value);
|
||||||
|
bool rava_object_equals(RavaValue_t a, RavaValue_t b);
|
||||||
|
char* rava_object_tostring(RavaValue_t value);
|
||||||
|
const char* rava_object_getclass(RavaValue_t value);
|
||||||
|
|
||||||
RavaArrayList_t* rava_arraylist_create(void);
|
RavaArrayList_t* rava_arraylist_create(void);
|
||||||
void rava_arraylist_destroy(RavaArrayList_t *list);
|
void rava_arraylist_destroy(RavaArrayList_t *list);
|
||||||
void rava_arraylist_add(RavaArrayList_t *list, RavaValue_t value);
|
void rava_arraylist_add(RavaArrayList_t *list, RavaValue_t value);
|
||||||
@ -289,6 +349,47 @@ size_t rava_hashmap_size(RavaHashMap_t *map);
|
|||||||
bool rava_hashmap_containskey(RavaHashMap_t *map, const char *key);
|
bool rava_hashmap_containskey(RavaHashMap_t *map, const char *key);
|
||||||
void rava_hashmap_clear(RavaHashMap_t *map);
|
void rava_hashmap_clear(RavaHashMap_t *map);
|
||||||
|
|
||||||
|
RavaSocket_t* rava_socket_create(void);
|
||||||
|
RavaSocket_t* rava_socket_create_connected(const char *host, int port);
|
||||||
|
RavaSocket_t* rava_server_socket_create(int port);
|
||||||
|
void rava_socket_destroy(RavaSocket_t *socket);
|
||||||
|
bool rava_socket_connect(RavaSocket_t *socket, const char *host, int port);
|
||||||
|
RavaSocket_t* rava_server_socket_accept(RavaSocket_t *server);
|
||||||
|
RavaStream_t* rava_socket_get_input_stream(RavaSocket_t *socket);
|
||||||
|
RavaStream_t* rava_socket_get_output_stream(RavaSocket_t *socket);
|
||||||
|
void rava_socket_close(RavaSocket_t *socket);
|
||||||
|
RavaStream_t* rava_stream_create(int fd, int stream_type);
|
||||||
|
void rava_stream_destroy(RavaStream_t *stream);
|
||||||
|
char* rava_stream_read(RavaStream_t *stream);
|
||||||
|
int rava_stream_read_byte(RavaStream_t *stream);
|
||||||
|
void rava_stream_write(RavaStream_t *stream, const char *data);
|
||||||
|
void rava_stream_write_byte(RavaStream_t *stream, int byte);
|
||||||
|
void rava_stream_close(RavaStream_t *stream);
|
||||||
|
|
||||||
|
static inline RavaValue_t rava_value_socket(RavaSocket_t *socket) {
|
||||||
|
RavaValue_t val;
|
||||||
|
val.type = RAVA_VAL_SOCKET;
|
||||||
|
val.data.socket_val = socket;
|
||||||
|
return val;
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline RavaValue_t rava_value_stream(RavaStream_t *stream) {
|
||||||
|
RavaValue_t val;
|
||||||
|
val.type = RAVA_VAL_STREAM;
|
||||||
|
val.data.stream_val = stream;
|
||||||
|
return val;
|
||||||
|
}
|
||||||
|
|
||||||
|
RavaMethodRef_t* rava_method_ref_create(const char *class_name, const char *method_name, bool is_constructor, bool is_static);
|
||||||
|
void rava_method_ref_destroy(RavaMethodRef_t *ref);
|
||||||
|
|
||||||
|
static inline RavaValue_t rava_value_method_ref(RavaMethodRef_t *ref) {
|
||||||
|
RavaValue_t val;
|
||||||
|
val.type = RAVA_VAL_METHOD_REF;
|
||||||
|
val.data.method_ref_val = ref;
|
||||||
|
return val;
|
||||||
|
}
|
||||||
|
|
||||||
RavaStack_t* rava_stack_create(size_t capacity);
|
RavaStack_t* rava_stack_create(size_t capacity);
|
||||||
void rava_stack_destroy(RavaStack_t *stack);
|
void rava_stack_destroy(RavaStack_t *stack);
|
||||||
void rava_stack_push(RavaStack_t *stack, RavaValue_t value);
|
void rava_stack_push(RavaStack_t *stack, RavaValue_t value);
|
||||||
@ -311,4 +412,39 @@ void rava_vm_destroy(RavaVM_t *vm);
|
|||||||
bool rava_vm_execute(RavaVM_t *vm, const char *class_name, const char *method_name);
|
bool rava_vm_execute(RavaVM_t *vm, const char *class_name, const char *method_name);
|
||||||
RavaValue_t rava_vm_get_result(RavaVM_t *vm);
|
RavaValue_t rava_vm_get_result(RavaVM_t *vm);
|
||||||
|
|
||||||
|
bool rava_vm_load_native_library(RavaVM_t *vm, const char *path);
|
||||||
|
bool rava_vm_register_native(RavaVM_t *vm, const char *class_name, const char *method_name,
|
||||||
|
RavaNativeType_e return_type, RavaNativeType_e *param_types,
|
||||||
|
size_t param_count, RavaNativeFunction_fn function, void *user_data);
|
||||||
|
RavaValue_t rava_vm_call_native(RavaVM_t *vm, const char *class_name, const char *method_name,
|
||||||
|
RavaValue_t *args, size_t arg_count);
|
||||||
|
|
||||||
|
RavaNativeValue_t rava_value_to_native(RavaValue_t value);
|
||||||
|
RavaValue_t rava_native_to_value(RavaNativeValue_t native);
|
||||||
|
|
||||||
|
#define RAVA_GC_WHITE 0
|
||||||
|
#define RAVA_GC_GRAY 1
|
||||||
|
#define RAVA_GC_BLACK 2
|
||||||
|
|
||||||
|
#define RAVA_GC_FLAG_PINNED 0x01
|
||||||
|
#define RAVA_GC_FLAG_FINALIZER 0x02
|
||||||
|
|
||||||
|
#define RAVA_GC_TYPE_OBJECT 1
|
||||||
|
#define RAVA_GC_TYPE_ARRAY 2
|
||||||
|
#define RAVA_GC_TYPE_ARRAYLIST 3
|
||||||
|
#define RAVA_GC_TYPE_HASHMAP 4
|
||||||
|
#define RAVA_GC_TYPE_STRING 5
|
||||||
|
#define RAVA_GC_TYPE_SOCKET 6
|
||||||
|
#define RAVA_GC_TYPE_STREAM 7
|
||||||
|
#define RAVA_GC_TYPE_METHODREF 8
|
||||||
|
|
||||||
|
void rava_gc_init(void);
|
||||||
|
void rava_gc_shutdown(void);
|
||||||
|
void rava_gc_set_vm(RavaVM_t *vm);
|
||||||
|
void* rava_gc_alloc(size_t size, uint8_t type);
|
||||||
|
void rava_gc_collect(void);
|
||||||
|
void rava_gc_collect_if_needed(void);
|
||||||
|
void rava_gc_enable(void);
|
||||||
|
void rava_gc_disable(void);
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
@ -1,7 +1,9 @@
|
|||||||
#define _POSIX_C_SOURCE 200809L
|
#define _POSIX_C_SOURCE 200809L
|
||||||
#include "runtime.h"
|
#include "runtime.h"
|
||||||
|
#include "gc/gc.h"
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
#define RAVA_MAX_ARRAY_LENGTH 1000000
|
#define RAVA_MAX_ARRAY_LENGTH 1000000
|
||||||
|
|
||||||
@ -12,9 +14,11 @@ RavaArray_t* rava_array_create(RavaValueType_e element_type, size_t length) {
|
|||||||
length = RAVA_MAX_ARRAY_LENGTH;
|
length = RAVA_MAX_ARRAY_LENGTH;
|
||||||
}
|
}
|
||||||
|
|
||||||
RavaArray_t *array = malloc(sizeof(RavaArray_t));
|
RavaArray_t *array = rava_gc_alloc(sizeof(RavaArray_t), RAVA_GC_TYPE_ARRAY);
|
||||||
if (!array) return NULL;
|
if (!array) return NULL;
|
||||||
|
|
||||||
|
memset((char*)array + sizeof(RavaGCHeader_t), 0, sizeof(RavaArray_t) - sizeof(RavaGCHeader_t));
|
||||||
|
|
||||||
array->element_type = element_type;
|
array->element_type = element_type;
|
||||||
array->length = length;
|
array->length = length;
|
||||||
array->data = NULL;
|
array->data = NULL;
|
||||||
@ -42,7 +46,6 @@ RavaArray_t* rava_array_create(RavaValueType_e element_type, size_t length) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (!array->data && length > 0) {
|
if (!array->data && length > 0) {
|
||||||
free(array);
|
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -52,7 +55,6 @@ RavaArray_t* rava_array_create(RavaValueType_e element_type, size_t length) {
|
|||||||
void rava_array_destroy(RavaArray_t *array) {
|
void rava_array_destroy(RavaArray_t *array) {
|
||||||
if (!array) return;
|
if (!array) return;
|
||||||
free(array->data);
|
free(array->data);
|
||||||
free(array);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void rava_array_set_int(RavaArray_t *array, size_t index, int32_t value) {
|
void rava_array_set_int(RavaArray_t *array, size_t index, int32_t value) {
|
||||||
|
|||||||
@ -1,12 +1,17 @@
|
|||||||
#define _POSIX_C_SOURCE 200809L
|
#define _POSIX_C_SOURCE 200809L
|
||||||
#include "runtime.h"
|
#include "runtime.h"
|
||||||
|
#include "gc/gc.h"
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
|
|
||||||
#define ARRAYLIST_INITIAL_CAPACITY 16
|
#define ARRAYLIST_INITIAL_CAPACITY 16
|
||||||
|
|
||||||
RavaArrayList_t* rava_arraylist_create(void) {
|
RavaArrayList_t* rava_arraylist_create(void) {
|
||||||
RavaArrayList_t *list = calloc(1, sizeof(RavaArrayList_t));
|
RavaArrayList_t *list = rava_gc_alloc(sizeof(RavaArrayList_t), RAVA_GC_TYPE_ARRAYLIST);
|
||||||
|
if (!list) return NULL;
|
||||||
|
|
||||||
|
memset((char*)list + sizeof(RavaGCHeader_t), 0, sizeof(RavaArrayList_t) - sizeof(RavaGCHeader_t));
|
||||||
|
|
||||||
list->collection_type = RAVA_COLLECTION_ARRAYLIST;
|
list->collection_type = RAVA_COLLECTION_ARRAYLIST;
|
||||||
list->data = calloc(ARRAYLIST_INITIAL_CAPACITY, sizeof(RavaValue_t));
|
list->data = calloc(ARRAYLIST_INITIAL_CAPACITY, sizeof(RavaValue_t));
|
||||||
list->size = 0;
|
list->size = 0;
|
||||||
@ -17,7 +22,6 @@ RavaArrayList_t* rava_arraylist_create(void) {
|
|||||||
void rava_arraylist_destroy(RavaArrayList_t *list) {
|
void rava_arraylist_destroy(RavaArrayList_t *list) {
|
||||||
if (!list) return;
|
if (!list) return;
|
||||||
free(list->data);
|
free(list->data);
|
||||||
free(list);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void rava_arraylist_add(RavaArrayList_t *list, RavaValue_t value) {
|
void rava_arraylist_add(RavaArrayList_t *list, RavaValue_t value) {
|
||||||
@ -75,7 +79,11 @@ static unsigned int _rava_hash_string(const char *str) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
RavaHashMap_t* rava_hashmap_create(void) {
|
RavaHashMap_t* rava_hashmap_create(void) {
|
||||||
RavaHashMap_t *map = calloc(1, sizeof(RavaHashMap_t));
|
RavaHashMap_t *map = rava_gc_alloc(sizeof(RavaHashMap_t), RAVA_GC_TYPE_HASHMAP);
|
||||||
|
if (!map) return NULL;
|
||||||
|
|
||||||
|
memset((char*)map + sizeof(RavaGCHeader_t), 0, sizeof(RavaHashMap_t) - sizeof(RavaGCHeader_t));
|
||||||
|
|
||||||
map->collection_type = RAVA_COLLECTION_HASHMAP;
|
map->collection_type = RAVA_COLLECTION_HASHMAP;
|
||||||
map->bucket_count = RAVA_HASHMAP_BUCKET_SIZE;
|
map->bucket_count = RAVA_HASHMAP_BUCKET_SIZE;
|
||||||
map->buckets = calloc(map->bucket_count, sizeof(RavaHashMapEntry_t));
|
map->buckets = calloc(map->bucket_count, sizeof(RavaHashMapEntry_t));
|
||||||
@ -91,7 +99,6 @@ void rava_hashmap_destroy(RavaHashMap_t *map) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
free(map->buckets);
|
free(map->buckets);
|
||||||
free(map);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void _rava_hashmap_resize(RavaHashMap_t *map) {
|
static void _rava_hashmap_resize(RavaHashMap_t *map) {
|
||||||
|
|||||||
25
runtime/runtime_method_ref.c
Normal file
25
runtime/runtime_method_ref.c
Normal file
@ -0,0 +1,25 @@
|
|||||||
|
#include "runtime.h"
|
||||||
|
#include "gc/gc.h"
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
|
RavaMethodRef_t* rava_method_ref_create(const char *class_name, const char *method_name, bool is_constructor, bool is_static) {
|
||||||
|
RavaMethodRef_t *ref = rava_gc_alloc(sizeof(RavaMethodRef_t), RAVA_GC_TYPE_METHODREF);
|
||||||
|
if (!ref) return NULL;
|
||||||
|
|
||||||
|
memset((char*)ref + sizeof(RavaGCHeader_t), 0, sizeof(RavaMethodRef_t) - sizeof(RavaGCHeader_t));
|
||||||
|
|
||||||
|
ref->class_name = class_name ? strdup(class_name) : NULL;
|
||||||
|
ref->method_name = method_name ? strdup(method_name) : NULL;
|
||||||
|
ref->is_constructor = is_constructor;
|
||||||
|
ref->is_static = is_static;
|
||||||
|
ref->has_target = false;
|
||||||
|
|
||||||
|
return ref;
|
||||||
|
}
|
||||||
|
|
||||||
|
void rava_method_ref_destroy(RavaMethodRef_t *ref) {
|
||||||
|
if (!ref) return;
|
||||||
|
free(ref->class_name);
|
||||||
|
free(ref->method_name);
|
||||||
|
}
|
||||||
@ -1,8 +1,12 @@
|
|||||||
#define _POSIX_C_SOURCE 200809L
|
#define _POSIX_C_SOURCE 200809L
|
||||||
#include "runtime.h"
|
#include "runtime.h"
|
||||||
|
#include "gc/gc.h"
|
||||||
|
#include "gc/gc_heap.h"
|
||||||
#include "../utils/safe_alloc.h"
|
#include "../utils/safe_alloc.h"
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <stdint.h>
|
||||||
|
|
||||||
static inline uint32_t _rava_field_hash(const char *name) {
|
static inline uint32_t _rava_field_hash(const char *name) {
|
||||||
uint32_t hash = 5381;
|
uint32_t hash = 5381;
|
||||||
@ -13,8 +17,11 @@ static inline uint32_t _rava_field_hash(const char *name) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
RavaObject_t* rava_object_create(const char *class_name) {
|
RavaObject_t* rava_object_create(const char *class_name) {
|
||||||
RavaObject_t *obj = calloc(1, sizeof(RavaObject_t));
|
RavaObject_t *obj = rava_gc_alloc(sizeof(RavaObject_t), RAVA_GC_TYPE_OBJECT);
|
||||||
if (!obj) return NULL;
|
if (!obj) return NULL;
|
||||||
|
|
||||||
|
memset((char*)obj + sizeof(RavaGCHeader_t), 0, sizeof(RavaObject_t) - sizeof(RavaGCHeader_t));
|
||||||
|
|
||||||
obj->class_name = strdup(class_name);
|
obj->class_name = strdup(class_name);
|
||||||
obj->field_capacity = 8;
|
obj->field_capacity = 8;
|
||||||
obj->field_names = calloc(obj->field_capacity, sizeof(char*));
|
obj->field_names = calloc(obj->field_capacity, sizeof(char*));
|
||||||
@ -23,7 +30,6 @@ RavaObject_t* rava_object_create(const char *class_name) {
|
|||||||
free(obj->field_names);
|
free(obj->field_names);
|
||||||
free(obj->field_values);
|
free(obj->field_values);
|
||||||
free(obj->class_name);
|
free(obj->class_name);
|
||||||
free(obj);
|
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
obj->field_count = 0;
|
obj->field_count = 0;
|
||||||
@ -41,7 +47,6 @@ void rava_object_destroy(RavaObject_t *obj) {
|
|||||||
}
|
}
|
||||||
free(obj->field_names);
|
free(obj->field_names);
|
||||||
free(obj->field_values);
|
free(obj->field_values);
|
||||||
free(obj);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void rava_object_set_field(RavaObject_t *obj, const char *name, RavaValue_t value) {
|
void rava_object_set_field(RavaObject_t *obj, const char *name, RavaValue_t value) {
|
||||||
@ -131,3 +136,205 @@ void rava_object_set_field_by_index(RavaObject_t *obj, int index, RavaValue_t va
|
|||||||
if (!obj || index < 0 || (size_t)index >= obj->field_count) return;
|
if (!obj || index < 0 || (size_t)index >= obj->field_count) return;
|
||||||
obj->field_values[index] = value;
|
obj->field_values[index] = value;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int32_t rava_object_hashcode(RavaValue_t value) {
|
||||||
|
switch (value.type) {
|
||||||
|
case RAVA_VAL_NULL:
|
||||||
|
return 0;
|
||||||
|
case RAVA_VAL_INT:
|
||||||
|
return value.data.int_val;
|
||||||
|
case RAVA_VAL_LONG: {
|
||||||
|
int64_t v = value.data.long_val;
|
||||||
|
return (int32_t)(v ^ (v >> 32));
|
||||||
|
}
|
||||||
|
case RAVA_VAL_FLOAT: {
|
||||||
|
union { float f; int32_t i; } u;
|
||||||
|
u.f = value.data.float_val;
|
||||||
|
return u.i;
|
||||||
|
}
|
||||||
|
case RAVA_VAL_DOUBLE: {
|
||||||
|
union { double d; int64_t l; } u;
|
||||||
|
u.d = value.data.double_val;
|
||||||
|
return (int32_t)(u.l ^ (u.l >> 32));
|
||||||
|
}
|
||||||
|
case RAVA_VAL_BOOLEAN:
|
||||||
|
return value.data.bool_val ? 1231 : 1237;
|
||||||
|
case RAVA_VAL_CHAR:
|
||||||
|
return (int32_t)value.data.char_val;
|
||||||
|
case RAVA_VAL_STRING: {
|
||||||
|
if (!value.data.string_val) return 0;
|
||||||
|
int32_t hash = 0;
|
||||||
|
for (const char *p = value.data.string_val; *p; p++) {
|
||||||
|
hash = 31 * hash + (int32_t)(unsigned char)*p;
|
||||||
|
}
|
||||||
|
return hash;
|
||||||
|
}
|
||||||
|
case RAVA_VAL_OBJECT:
|
||||||
|
case RAVA_VAL_ARRAY:
|
||||||
|
case RAVA_VAL_ARRAYLIST:
|
||||||
|
case RAVA_VAL_HASHMAP:
|
||||||
|
return (int32_t)((uintptr_t)value.data.object_val >> 3);
|
||||||
|
case RAVA_VAL_SOCKET:
|
||||||
|
return (int32_t)((uintptr_t)value.data.socket_val >> 3);
|
||||||
|
case RAVA_VAL_STREAM:
|
||||||
|
return (int32_t)((uintptr_t)value.data.stream_val >> 3);
|
||||||
|
case RAVA_VAL_METHOD_REF:
|
||||||
|
return (int32_t)((uintptr_t)value.data.method_ref_val >> 3);
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool rava_object_equals(RavaValue_t a, RavaValue_t b) {
|
||||||
|
if (a.type == RAVA_VAL_NULL && b.type == RAVA_VAL_NULL) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
if (a.type == RAVA_VAL_NULL || b.type == RAVA_VAL_NULL) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (a.type == RAVA_VAL_STRING && b.type == RAVA_VAL_STRING) {
|
||||||
|
if (!a.data.string_val && !b.data.string_val) return true;
|
||||||
|
if (!a.data.string_val || !b.data.string_val) return false;
|
||||||
|
return strcmp(a.data.string_val, b.data.string_val) == 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (a.type != b.type) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
switch (a.type) {
|
||||||
|
case RAVA_VAL_INT:
|
||||||
|
return a.data.int_val == b.data.int_val;
|
||||||
|
case RAVA_VAL_LONG:
|
||||||
|
return a.data.long_val == b.data.long_val;
|
||||||
|
case RAVA_VAL_FLOAT:
|
||||||
|
return a.data.float_val == b.data.float_val;
|
||||||
|
case RAVA_VAL_DOUBLE:
|
||||||
|
return a.data.double_val == b.data.double_val;
|
||||||
|
case RAVA_VAL_BOOLEAN:
|
||||||
|
return a.data.bool_val == b.data.bool_val;
|
||||||
|
case RAVA_VAL_CHAR:
|
||||||
|
return a.data.char_val == b.data.char_val;
|
||||||
|
case RAVA_VAL_OBJECT:
|
||||||
|
case RAVA_VAL_ARRAY:
|
||||||
|
case RAVA_VAL_ARRAYLIST:
|
||||||
|
case RAVA_VAL_HASHMAP:
|
||||||
|
return a.data.object_val == b.data.object_val;
|
||||||
|
default:
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
char* rava_object_tostring(RavaValue_t value) {
|
||||||
|
char *buffer = malloc(128);
|
||||||
|
if (!buffer) return NULL;
|
||||||
|
|
||||||
|
switch (value.type) {
|
||||||
|
case RAVA_VAL_NULL:
|
||||||
|
strcpy(buffer, "null");
|
||||||
|
break;
|
||||||
|
case RAVA_VAL_INT:
|
||||||
|
snprintf(buffer, 128, "%d", value.data.int_val);
|
||||||
|
break;
|
||||||
|
case RAVA_VAL_LONG:
|
||||||
|
snprintf(buffer, 128, "%ld", value.data.long_val);
|
||||||
|
break;
|
||||||
|
case RAVA_VAL_FLOAT:
|
||||||
|
snprintf(buffer, 128, "%g", (double)value.data.float_val);
|
||||||
|
break;
|
||||||
|
case RAVA_VAL_DOUBLE:
|
||||||
|
snprintf(buffer, 128, "%g", value.data.double_val);
|
||||||
|
break;
|
||||||
|
case RAVA_VAL_BOOLEAN:
|
||||||
|
strcpy(buffer, value.data.bool_val ? "true" : "false");
|
||||||
|
break;
|
||||||
|
case RAVA_VAL_CHAR:
|
||||||
|
snprintf(buffer, 128, "%c", value.data.char_val);
|
||||||
|
break;
|
||||||
|
case RAVA_VAL_STRING:
|
||||||
|
free(buffer);
|
||||||
|
return value.data.string_val ? strdup(value.data.string_val) : strdup("null");
|
||||||
|
case RAVA_VAL_OBJECT:
|
||||||
|
if (!value.data.object_val) {
|
||||||
|
strcpy(buffer, "null");
|
||||||
|
} else {
|
||||||
|
snprintf(buffer, 128, "%s@%x",
|
||||||
|
value.data.object_val->class_name,
|
||||||
|
(unsigned int)((uintptr_t)value.data.object_val >> 3));
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case RAVA_VAL_ARRAY:
|
||||||
|
if (!value.data.array_val) {
|
||||||
|
strcpy(buffer, "null");
|
||||||
|
} else {
|
||||||
|
snprintf(buffer, 128, "[array@%x]",
|
||||||
|
(unsigned int)((uintptr_t)value.data.array_val >> 3));
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case RAVA_VAL_ARRAYLIST:
|
||||||
|
snprintf(buffer, 128, "ArrayList@%x",
|
||||||
|
(unsigned int)((uintptr_t)value.data.arraylist_val >> 3));
|
||||||
|
break;
|
||||||
|
case RAVA_VAL_HASHMAP:
|
||||||
|
snprintf(buffer, 128, "HashMap@%x",
|
||||||
|
(unsigned int)((uintptr_t)value.data.hashmap_val >> 3));
|
||||||
|
break;
|
||||||
|
case RAVA_VAL_SOCKET:
|
||||||
|
snprintf(buffer, 128, "Socket@%x",
|
||||||
|
(unsigned int)((uintptr_t)value.data.socket_val >> 3));
|
||||||
|
break;
|
||||||
|
case RAVA_VAL_STREAM:
|
||||||
|
snprintf(buffer, 128, "Stream@%x",
|
||||||
|
(unsigned int)((uintptr_t)value.data.stream_val >> 3));
|
||||||
|
break;
|
||||||
|
case RAVA_VAL_METHOD_REF:
|
||||||
|
if (value.data.method_ref_val) {
|
||||||
|
snprintf(buffer, 128, "%s::%s",
|
||||||
|
value.data.method_ref_val->class_name ? value.data.method_ref_val->class_name : "",
|
||||||
|
value.data.method_ref_val->method_name ? value.data.method_ref_val->method_name : "");
|
||||||
|
} else {
|
||||||
|
strcpy(buffer, "null");
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
return buffer;
|
||||||
|
}
|
||||||
|
|
||||||
|
const char* rava_object_getclass(RavaValue_t value) {
|
||||||
|
switch (value.type) {
|
||||||
|
case RAVA_VAL_NULL:
|
||||||
|
return "null";
|
||||||
|
case RAVA_VAL_INT:
|
||||||
|
return "Integer";
|
||||||
|
case RAVA_VAL_LONG:
|
||||||
|
return "Long";
|
||||||
|
case RAVA_VAL_FLOAT:
|
||||||
|
return "Float";
|
||||||
|
case RAVA_VAL_DOUBLE:
|
||||||
|
return "Double";
|
||||||
|
case RAVA_VAL_BOOLEAN:
|
||||||
|
return "Boolean";
|
||||||
|
case RAVA_VAL_CHAR:
|
||||||
|
return "Character";
|
||||||
|
case RAVA_VAL_STRING:
|
||||||
|
return "String";
|
||||||
|
case RAVA_VAL_OBJECT:
|
||||||
|
if (value.data.object_val) {
|
||||||
|
return value.data.object_val->class_name;
|
||||||
|
}
|
||||||
|
return "null";
|
||||||
|
case RAVA_VAL_ARRAY:
|
||||||
|
return "Array";
|
||||||
|
case RAVA_VAL_ARRAYLIST:
|
||||||
|
return "ArrayList";
|
||||||
|
case RAVA_VAL_HASHMAP:
|
||||||
|
return "HashMap";
|
||||||
|
case RAVA_VAL_SOCKET:
|
||||||
|
return "Socket";
|
||||||
|
case RAVA_VAL_STREAM:
|
||||||
|
return "Stream";
|
||||||
|
case RAVA_VAL_METHOD_REF:
|
||||||
|
return "MethodReference";
|
||||||
|
}
|
||||||
|
return "Object";
|
||||||
|
}
|
||||||
|
|||||||
206
runtime/runtime_socket.c
Normal file
206
runtime/runtime_socket.c
Normal file
@ -0,0 +1,206 @@
|
|||||||
|
#define _POSIX_C_SOURCE 200809L
|
||||||
|
#include "runtime.h"
|
||||||
|
#include "gc/gc.h"
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
#include <sys/socket.h>
|
||||||
|
#include <netinet/in.h>
|
||||||
|
#include <arpa/inet.h>
|
||||||
|
#include <netdb.h>
|
||||||
|
#include <errno.h>
|
||||||
|
|
||||||
|
RavaSocket_t* rava_socket_create(void) {
|
||||||
|
RavaSocket_t *sock = rava_gc_alloc(sizeof(RavaSocket_t), RAVA_GC_TYPE_SOCKET);
|
||||||
|
if (!sock) return NULL;
|
||||||
|
|
||||||
|
memset((char*)sock + sizeof(RavaGCHeader_t), 0, sizeof(RavaSocket_t) - sizeof(RavaGCHeader_t));
|
||||||
|
|
||||||
|
sock->socket_type = RAVA_SOCKET_TYPE_CLIENT;
|
||||||
|
sock->fd = socket(AF_INET, SOCK_STREAM, 0);
|
||||||
|
sock->connected = false;
|
||||||
|
sock->closed = false;
|
||||||
|
return sock;
|
||||||
|
}
|
||||||
|
|
||||||
|
RavaSocket_t* rava_socket_create_connected(const char *host, int port) {
|
||||||
|
RavaSocket_t *sock = rava_socket_create();
|
||||||
|
if (!sock) return NULL;
|
||||||
|
if (sock->fd < 0) return sock;
|
||||||
|
|
||||||
|
if (rava_socket_connect(sock, host, port)) {
|
||||||
|
sock->connected = true;
|
||||||
|
}
|
||||||
|
return sock;
|
||||||
|
}
|
||||||
|
|
||||||
|
RavaSocket_t* rava_server_socket_create(int port) {
|
||||||
|
RavaSocket_t *sock = rava_gc_alloc(sizeof(RavaSocket_t), RAVA_GC_TYPE_SOCKET);
|
||||||
|
if (!sock) return NULL;
|
||||||
|
|
||||||
|
memset((char*)sock + sizeof(RavaGCHeader_t), 0, sizeof(RavaSocket_t) - sizeof(RavaGCHeader_t));
|
||||||
|
|
||||||
|
sock->socket_type = RAVA_SOCKET_TYPE_SERVER;
|
||||||
|
sock->fd = socket(AF_INET, SOCK_STREAM, 0);
|
||||||
|
sock->connected = false;
|
||||||
|
sock->closed = false;
|
||||||
|
|
||||||
|
if (sock->fd < 0) return sock;
|
||||||
|
|
||||||
|
int opt = 1;
|
||||||
|
setsockopt(sock->fd, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(opt));
|
||||||
|
|
||||||
|
struct sockaddr_in addr;
|
||||||
|
memset(&addr, 0, sizeof(addr));
|
||||||
|
addr.sin_family = AF_INET;
|
||||||
|
addr.sin_addr.s_addr = INADDR_ANY;
|
||||||
|
addr.sin_port = htons(port);
|
||||||
|
|
||||||
|
if (bind(sock->fd, (struct sockaddr*)&addr, sizeof(addr)) < 0) {
|
||||||
|
close(sock->fd);
|
||||||
|
sock->fd = -1;
|
||||||
|
return sock;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (listen(sock->fd, 10) < 0) {
|
||||||
|
close(sock->fd);
|
||||||
|
sock->fd = -1;
|
||||||
|
return sock;
|
||||||
|
}
|
||||||
|
|
||||||
|
return sock;
|
||||||
|
}
|
||||||
|
|
||||||
|
void rava_socket_destroy(RavaSocket_t *socket) {
|
||||||
|
if (!socket) return;
|
||||||
|
if (!socket->closed && socket->fd >= 0) {
|
||||||
|
close(socket->fd);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bool rava_socket_connect(RavaSocket_t *socket, const char *host, int port) {
|
||||||
|
if (!socket || socket->fd < 0) return false;
|
||||||
|
|
||||||
|
struct hostent *server = gethostbyname(host);
|
||||||
|
if (!server) return false;
|
||||||
|
|
||||||
|
struct sockaddr_in addr;
|
||||||
|
memset(&addr, 0, sizeof(addr));
|
||||||
|
addr.sin_family = AF_INET;
|
||||||
|
memcpy(&addr.sin_addr.s_addr, server->h_addr_list[0], server->h_length);
|
||||||
|
addr.sin_port = htons(port);
|
||||||
|
|
||||||
|
if (connect(socket->fd, (struct sockaddr*)&addr, sizeof(addr)) < 0) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
socket->connected = true;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
RavaSocket_t* rava_server_socket_accept(RavaSocket_t *server) {
|
||||||
|
if (!server || server->fd < 0 || server->socket_type != RAVA_SOCKET_TYPE_SERVER) {
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
struct sockaddr_in client_addr;
|
||||||
|
socklen_t client_len = sizeof(client_addr);
|
||||||
|
|
||||||
|
int client_fd = accept(server->fd, (struct sockaddr*)&client_addr, &client_len);
|
||||||
|
if (client_fd < 0) return NULL;
|
||||||
|
|
||||||
|
RavaSocket_t *client = rava_gc_alloc(sizeof(RavaSocket_t), RAVA_GC_TYPE_SOCKET);
|
||||||
|
if (!client) {
|
||||||
|
close(client_fd);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
memset((char*)client + sizeof(RavaGCHeader_t), 0, sizeof(RavaSocket_t) - sizeof(RavaGCHeader_t));
|
||||||
|
|
||||||
|
client->socket_type = RAVA_SOCKET_TYPE_CLIENT;
|
||||||
|
client->fd = client_fd;
|
||||||
|
client->connected = true;
|
||||||
|
client->closed = false;
|
||||||
|
|
||||||
|
return client;
|
||||||
|
}
|
||||||
|
|
||||||
|
RavaStream_t* rava_socket_get_input_stream(RavaSocket_t *socket) {
|
||||||
|
if (!socket || socket->fd < 0) return NULL;
|
||||||
|
return rava_stream_create(socket->fd, RAVA_STREAM_TYPE_INPUT);
|
||||||
|
}
|
||||||
|
|
||||||
|
RavaStream_t* rava_socket_get_output_stream(RavaSocket_t *socket) {
|
||||||
|
if (!socket || socket->fd < 0) return NULL;
|
||||||
|
return rava_stream_create(socket->fd, RAVA_STREAM_TYPE_OUTPUT);
|
||||||
|
}
|
||||||
|
|
||||||
|
void rava_socket_close(RavaSocket_t *socket) {
|
||||||
|
if (!socket || socket->closed) return;
|
||||||
|
if (socket->fd >= 0) {
|
||||||
|
close(socket->fd);
|
||||||
|
}
|
||||||
|
socket->closed = true;
|
||||||
|
socket->connected = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
RavaStream_t* rava_stream_create(int fd, int stream_type) {
|
||||||
|
RavaStream_t *stream = rava_gc_alloc(sizeof(RavaStream_t), RAVA_GC_TYPE_STREAM);
|
||||||
|
if (!stream) return NULL;
|
||||||
|
|
||||||
|
memset((char*)stream + sizeof(RavaGCHeader_t), 0, sizeof(RavaStream_t) - sizeof(RavaGCHeader_t));
|
||||||
|
|
||||||
|
stream->stream_type = stream_type;
|
||||||
|
stream->fd = fd;
|
||||||
|
stream->closed = false;
|
||||||
|
return stream;
|
||||||
|
}
|
||||||
|
|
||||||
|
void rava_stream_destroy(RavaStream_t *stream) {
|
||||||
|
(void)stream;
|
||||||
|
}
|
||||||
|
|
||||||
|
char* rava_stream_read(RavaStream_t *stream) {
|
||||||
|
if (!stream || stream->closed || stream->fd < 0) return NULL;
|
||||||
|
if (stream->stream_type != RAVA_STREAM_TYPE_INPUT) return NULL;
|
||||||
|
|
||||||
|
char buffer[4096];
|
||||||
|
ssize_t bytes = read(stream->fd, buffer, sizeof(buffer) - 1);
|
||||||
|
if (bytes <= 0) return NULL;
|
||||||
|
|
||||||
|
buffer[bytes] = '\0';
|
||||||
|
return strdup(buffer);
|
||||||
|
}
|
||||||
|
|
||||||
|
int rava_stream_read_byte(RavaStream_t *stream) {
|
||||||
|
if (!stream || stream->closed || stream->fd < 0) return -1;
|
||||||
|
if (stream->stream_type != RAVA_STREAM_TYPE_INPUT) return -1;
|
||||||
|
|
||||||
|
unsigned char byte;
|
||||||
|
ssize_t bytes = read(stream->fd, &byte, 1);
|
||||||
|
if (bytes <= 0) return -1;
|
||||||
|
|
||||||
|
return (int)byte;
|
||||||
|
}
|
||||||
|
|
||||||
|
void rava_stream_write(RavaStream_t *stream, const char *data) {
|
||||||
|
if (!stream || stream->closed || stream->fd < 0 || !data) return;
|
||||||
|
if (stream->stream_type != RAVA_STREAM_TYPE_OUTPUT) return;
|
||||||
|
|
||||||
|
ssize_t result = write(stream->fd, data, strlen(data));
|
||||||
|
(void)result;
|
||||||
|
}
|
||||||
|
|
||||||
|
void rava_stream_write_byte(RavaStream_t *stream, int byte) {
|
||||||
|
if (!stream || stream->closed || stream->fd < 0) return;
|
||||||
|
if (stream->stream_type != RAVA_STREAM_TYPE_OUTPUT) return;
|
||||||
|
|
||||||
|
unsigned char b = (unsigned char)byte;
|
||||||
|
ssize_t result = write(stream->fd, &b, 1);
|
||||||
|
(void)result;
|
||||||
|
}
|
||||||
|
|
||||||
|
void rava_stream_close(RavaStream_t *stream) {
|
||||||
|
if (!stream) return;
|
||||||
|
stream->closed = true;
|
||||||
|
}
|
||||||
Binary file not shown.
Binary file not shown.
91
tests/test_autobox.c
Normal file
91
tests/test_autobox.c
Normal file
@ -0,0 +1,91 @@
|
|||||||
|
#include "test_utils.h"
|
||||||
|
|
||||||
|
UnittestTestResult_t* test_autobox_int_to_integer(void) {
|
||||||
|
UNITTEST_BEGIN_TEST("TestAutobox", "test_autobox_int_to_integer");
|
||||||
|
|
||||||
|
RAVA_TEST_RUN(_unittest_result,
|
||||||
|
"public class Test {\n"
|
||||||
|
" public static int main() {\n"
|
||||||
|
" Integer x = 42;\n"
|
||||||
|
" return x.hashCode();\n"
|
||||||
|
" }\n"
|
||||||
|
"}\n",
|
||||||
|
"Test", "main", 42, "int should autobox to Integer");
|
||||||
|
|
||||||
|
UNITTEST_END_TEST();
|
||||||
|
}
|
||||||
|
|
||||||
|
UnittestTestResult_t* test_unbox_integer_to_int(void) {
|
||||||
|
UNITTEST_BEGIN_TEST("TestAutobox", "test_unbox_integer_to_int");
|
||||||
|
|
||||||
|
RAVA_TEST_RUN(_unittest_result,
|
||||||
|
"public class Test {\n"
|
||||||
|
" public static int main() {\n"
|
||||||
|
" Integer x = 10;\n"
|
||||||
|
" int y = x;\n"
|
||||||
|
" return y + 5;\n"
|
||||||
|
" }\n"
|
||||||
|
"}\n",
|
||||||
|
"Test", "main", 15, "Integer should unbox to int");
|
||||||
|
|
||||||
|
UNITTEST_END_TEST();
|
||||||
|
}
|
||||||
|
|
||||||
|
UnittestTestResult_t* test_autobox_long(void) {
|
||||||
|
UNITTEST_BEGIN_TEST("TestAutobox", "test_autobox_long");
|
||||||
|
|
||||||
|
RAVA_TEST_RUN(_unittest_result,
|
||||||
|
"public class Test {\n"
|
||||||
|
" public static int main() {\n"
|
||||||
|
" Long x = 100L;\n"
|
||||||
|
" long y = x;\n"
|
||||||
|
" return (int)y;\n"
|
||||||
|
" }\n"
|
||||||
|
"}\n",
|
||||||
|
"Test", "main", 100, "long should autobox/unbox with Long");
|
||||||
|
|
||||||
|
UNITTEST_END_TEST();
|
||||||
|
}
|
||||||
|
|
||||||
|
UnittestTestResult_t* test_autobox_double(void) {
|
||||||
|
UNITTEST_BEGIN_TEST("TestAutobox", "test_autobox_double");
|
||||||
|
|
||||||
|
RAVA_TEST_RUN(_unittest_result,
|
||||||
|
"public class Test {\n"
|
||||||
|
" public static int main() {\n"
|
||||||
|
" Double x = 3.0;\n"
|
||||||
|
" double y = x;\n"
|
||||||
|
" return (int)(y + 2.0);\n"
|
||||||
|
" }\n"
|
||||||
|
"}\n",
|
||||||
|
"Test", "main", 5, "double should autobox/unbox with Double");
|
||||||
|
|
||||||
|
UNITTEST_END_TEST();
|
||||||
|
}
|
||||||
|
|
||||||
|
int main(int argc, char **argv) {
|
||||||
|
UnittestConfig_t *config = unittest_config_create();
|
||||||
|
config->verbosity = 2;
|
||||||
|
|
||||||
|
if (argc > 1 && strcmp(argv[1], "--json") == 0) {
|
||||||
|
config->output_format = UNITTEST_FORMAT_JSON;
|
||||||
|
config->use_colors = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
UnittestTestSuite_t *suite = unittest_test_suite_create("Autoboxing Tests");
|
||||||
|
|
||||||
|
UnittestTestCase_t *tc = unittest_test_case_create("TestAutobox");
|
||||||
|
unittest_test_case_add_result(tc, test_autobox_int_to_integer());
|
||||||
|
unittest_test_case_add_result(tc, test_unbox_integer_to_int());
|
||||||
|
unittest_test_case_add_result(tc, test_autobox_long());
|
||||||
|
unittest_test_case_add_result(tc, test_autobox_double());
|
||||||
|
unittest_test_suite_add_test_case(suite, tc);
|
||||||
|
|
||||||
|
unittest_generate_report(suite, config);
|
||||||
|
|
||||||
|
int failures = suite->total_failed + suite->total_errors;
|
||||||
|
unittest_test_suite_destroy(suite);
|
||||||
|
unittest_config_destroy(config);
|
||||||
|
|
||||||
|
return failures > 0 ? 1 : 0;
|
||||||
|
}
|
||||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
@ -1,77 +1,128 @@
|
|||||||
#include "../lexer/lexer.h"
|
#include "test_utils.h"
|
||||||
#include "../parser/parser.h"
|
|
||||||
#include "../semantic/semantic.h"
|
|
||||||
#include "../ir/ir.h"
|
|
||||||
#include "../ir/ir_gen.h"
|
|
||||||
#include "../runtime/runtime.h"
|
|
||||||
#include <stdio.h>
|
|
||||||
#include <stdlib.h>
|
|
||||||
#include <string.h>
|
|
||||||
|
|
||||||
static char* read_file(const char *filename) {
|
UnittestTestResult_t* test_elseif_example(void) {
|
||||||
FILE *file = fopen(filename, "r");
|
UNITTEST_BEGIN_TEST("TestElseIf", "test_elseif_example");
|
||||||
if (!file) return NULL;
|
|
||||||
fseek(file, 0, SEEK_END);
|
RAVA_TEST_FILE_EXECUTES(_unittest_result,
|
||||||
long size = ftell(file);
|
"examples/18_ElseIf.java",
|
||||||
fseek(file, 0, SEEK_SET);
|
"ElseIf", "main",
|
||||||
char *content = malloc(size + 1);
|
"else-if example should execute successfully");
|
||||||
size_t read_bytes = fread(content, 1, size, file); (void)read_bytes;
|
|
||||||
content[size] = '\0';
|
UNITTEST_END_TEST();
|
||||||
fclose(file);
|
|
||||||
return content;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
int main() {
|
UnittestTestResult_t* test_elseif_first_branch(void) {
|
||||||
char *source = read_file("examples/18_ElseIf.java");
|
UNITTEST_BEGIN_TEST("TestElseIf", "test_elseif_first_branch");
|
||||||
if (!source) {
|
|
||||||
printf("Failed to read file\n");
|
RAVA_TEST_RUN(_unittest_result,
|
||||||
return 1;
|
"public class Test {\n"
|
||||||
|
" public static int main() {\n"
|
||||||
|
" int x = 10;\n"
|
||||||
|
" if (x > 5) {\n"
|
||||||
|
" return 1;\n"
|
||||||
|
" } else if (x > 0) {\n"
|
||||||
|
" return 2;\n"
|
||||||
|
" } else {\n"
|
||||||
|
" return 3;\n"
|
||||||
|
" }\n"
|
||||||
|
" }\n"
|
||||||
|
"}\n",
|
||||||
|
"Test", "main", 1, "should take first branch when x > 5");
|
||||||
|
|
||||||
|
UNITTEST_END_TEST();
|
||||||
}
|
}
|
||||||
|
|
||||||
RavaLexer_t *lexer = rava_lexer_create(source);
|
UnittestTestResult_t* test_elseif_second_branch(void) {
|
||||||
RavaParser_t *parser = rava_parser_create(lexer);
|
UNITTEST_BEGIN_TEST("TestElseIf", "test_elseif_second_branch");
|
||||||
RavaASTNode_t *ast = rava_parser_parse(parser);
|
|
||||||
|
|
||||||
if (parser->had_error) {
|
RAVA_TEST_RUN(_unittest_result,
|
||||||
printf("Parse error: %s\n", parser->error_message);
|
"public class Test {\n"
|
||||||
free(source);
|
" public static int main() {\n"
|
||||||
return 1;
|
" int x = 3;\n"
|
||||||
|
" if (x > 5) {\n"
|
||||||
|
" return 1;\n"
|
||||||
|
" } else if (x > 0) {\n"
|
||||||
|
" return 2;\n"
|
||||||
|
" } else {\n"
|
||||||
|
" return 3;\n"
|
||||||
|
" }\n"
|
||||||
|
" }\n"
|
||||||
|
"}\n",
|
||||||
|
"Test", "main", 2, "should take else-if branch when 0 < x <= 5");
|
||||||
|
|
||||||
|
UNITTEST_END_TEST();
|
||||||
}
|
}
|
||||||
|
|
||||||
printf("Parse: OK\n");
|
UnittestTestResult_t* test_elseif_else_branch(void) {
|
||||||
|
UNITTEST_BEGIN_TEST("TestElseIf", "test_elseif_else_branch");
|
||||||
|
|
||||||
RavaSemanticAnalyzer_t *analyzer = rava_semantic_analyzer_create();
|
RAVA_TEST_RUN(_unittest_result,
|
||||||
if (!rava_semantic_analyze(analyzer, ast)) {
|
"public class Test {\n"
|
||||||
printf("Semantic error: %s\n", analyzer->error_message);
|
" public static int main() {\n"
|
||||||
free(source);
|
" int x = -5;\n"
|
||||||
return 1;
|
" if (x > 5) {\n"
|
||||||
|
" return 1;\n"
|
||||||
|
" } else if (x > 0) {\n"
|
||||||
|
" return 2;\n"
|
||||||
|
" } else {\n"
|
||||||
|
" return 3;\n"
|
||||||
|
" }\n"
|
||||||
|
" }\n"
|
||||||
|
"}\n",
|
||||||
|
"Test", "main", 3, "should take else branch when x <= 0");
|
||||||
|
|
||||||
|
UNITTEST_END_TEST();
|
||||||
}
|
}
|
||||||
|
|
||||||
printf("Semantic: OK\n");
|
UnittestTestResult_t* test_elseif_chain(void) {
|
||||||
|
UNITTEST_BEGIN_TEST("TestElseIf", "test_elseif_chain");
|
||||||
|
|
||||||
RavaIRGenerator_t *ir_gen = rava_ir_generator_create(analyzer);
|
RAVA_TEST_RUN(_unittest_result,
|
||||||
RavaProgram_t *program = rava_ir_generate(ir_gen, ast);
|
"public class Test {\n"
|
||||||
|
" public static int main() {\n"
|
||||||
|
" int x = 75;\n"
|
||||||
|
" if (x >= 90) {\n"
|
||||||
|
" return 1;\n"
|
||||||
|
" } else if (x >= 80) {\n"
|
||||||
|
" return 2;\n"
|
||||||
|
" } else if (x >= 70) {\n"
|
||||||
|
" return 3;\n"
|
||||||
|
" } else if (x >= 60) {\n"
|
||||||
|
" return 4;\n"
|
||||||
|
" } else {\n"
|
||||||
|
" return 5;\n"
|
||||||
|
" }\n"
|
||||||
|
" }\n"
|
||||||
|
"}\n",
|
||||||
|
"Test", "main", 3, "should take third branch for grade C");
|
||||||
|
|
||||||
if (!program) {
|
UNITTEST_END_TEST();
|
||||||
printf("IR generation failed\n");
|
|
||||||
free(source);
|
|
||||||
return 1;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
printf("IR Gen: OK\n");
|
int main(int argc, char **argv) {
|
||||||
printf("\nOutput:\n");
|
UnittestConfig_t *config = unittest_config_create();
|
||||||
|
config->verbosity = 2;
|
||||||
|
|
||||||
RavaVM_t *vm = rava_vm_create(program);
|
if (argc > 1 && strcmp(argv[1], "--json") == 0) {
|
||||||
if (!rava_vm_execute(vm, "ElseIf", "main")) {
|
config->output_format = UNITTEST_FORMAT_JSON;
|
||||||
printf("Runtime error: %s\n", vm->error_message);
|
config->use_colors = false;
|
||||||
rava_vm_destroy(vm);
|
|
||||||
free(source);
|
|
||||||
return 1;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
printf("\nExecution: OK\n");
|
UnittestTestSuite_t *suite = unittest_test_suite_create("Else-If Tests");
|
||||||
|
|
||||||
rava_vm_destroy(vm);
|
UnittestTestCase_t *tc = unittest_test_case_create("TestElseIf");
|
||||||
free(source);
|
unittest_test_case_add_result(tc, test_elseif_example());
|
||||||
return 0;
|
unittest_test_case_add_result(tc, test_elseif_first_branch());
|
||||||
|
unittest_test_case_add_result(tc, test_elseif_second_branch());
|
||||||
|
unittest_test_case_add_result(tc, test_elseif_else_branch());
|
||||||
|
unittest_test_case_add_result(tc, test_elseif_chain());
|
||||||
|
unittest_test_suite_add_test_case(suite, tc);
|
||||||
|
|
||||||
|
unittest_generate_report(suite, config);
|
||||||
|
|
||||||
|
int failures = suite->total_failed + suite->total_errors;
|
||||||
|
unittest_test_suite_destroy(suite);
|
||||||
|
unittest_config_destroy(config);
|
||||||
|
|
||||||
|
return failures > 0 ? 1 : 0;
|
||||||
}
|
}
|
||||||
|
|||||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
@ -1,86 +1,93 @@
|
|||||||
#include <stdio.h>
|
#include "test_utils.h"
|
||||||
#include <assert.h>
|
|
||||||
#include "../runtime/fastframe.h"
|
#include "../runtime/fastframe.h"
|
||||||
|
|
||||||
static int tests_passed = 0;
|
UnittestTestResult_t* test_init(void) {
|
||||||
|
UNITTEST_BEGIN_TEST("TestFastFrame", "test_init");
|
||||||
|
|
||||||
#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();
|
rava_fastframe_init();
|
||||||
assert(rava_fastframe_get_depth() == 0);
|
UNITTEST_ASSERT_EQUAL(_unittest_result, 0, rava_fastframe_get_depth(), "initial depth should be 0");
|
||||||
assert(rava_fastframe_current() == NULL);
|
UNITTEST_ASSERT_NULL(_unittest_result, rava_fastframe_current(), "current frame should be NULL");
|
||||||
|
|
||||||
|
UNITTEST_END_TEST();
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST(push_pop) {
|
UnittestTestResult_t* test_push_pop(void) {
|
||||||
|
UNITTEST_BEGIN_TEST("TestFastFrame", "test_push_pop");
|
||||||
|
|
||||||
rava_fastframe_init();
|
rava_fastframe_init();
|
||||||
|
|
||||||
FastFrame_t* frame = rava_fastframe_push(NULL, 4);
|
FastFrame_t* frame = rava_fastframe_push(NULL, 4);
|
||||||
assert(frame != NULL);
|
UNITTEST_ASSERT_NOT_NULL(_unittest_result, frame, "pushed frame should not be NULL");
|
||||||
assert(rava_fastframe_get_depth() == 1);
|
UNITTEST_ASSERT_EQUAL(_unittest_result, 1, rava_fastframe_get_depth(), "depth should be 1");
|
||||||
assert(rava_fastframe_current() == frame);
|
UNITTEST_ASSERT_TRUE(_unittest_result, rava_fastframe_current() == frame, "current should match pushed frame");
|
||||||
|
|
||||||
rava_fastframe_pop();
|
rava_fastframe_pop();
|
||||||
assert(rava_fastframe_get_depth() == 0);
|
UNITTEST_ASSERT_EQUAL(_unittest_result, 0, rava_fastframe_get_depth(), "depth should be 0 after pop");
|
||||||
assert(rava_fastframe_current() == NULL);
|
UNITTEST_ASSERT_NULL(_unittest_result, rava_fastframe_current(), "current should be NULL after pop");
|
||||||
|
|
||||||
|
UNITTEST_END_TEST();
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST(nested_frames) {
|
UnittestTestResult_t* test_nested_frames(void) {
|
||||||
|
UNITTEST_BEGIN_TEST("TestFastFrame", "test_nested_frames");
|
||||||
|
|
||||||
rava_fastframe_init();
|
rava_fastframe_init();
|
||||||
|
|
||||||
FastFrame_t* f1 = rava_fastframe_push(NULL, 2);
|
FastFrame_t* f1 = rava_fastframe_push(NULL, 2);
|
||||||
FastFrame_t* f2 = rava_fastframe_push(NULL, 2);
|
FastFrame_t* f2 = rava_fastframe_push(NULL, 2);
|
||||||
FastFrame_t* f3 = rava_fastframe_push(NULL, 2);
|
FastFrame_t* f3 = rava_fastframe_push(NULL, 2);
|
||||||
|
|
||||||
assert(rava_fastframe_get_depth() == 3);
|
UNITTEST_ASSERT_EQUAL(_unittest_result, 3, rava_fastframe_get_depth(), "depth should be 3");
|
||||||
assert(rava_fastframe_current() == f3);
|
UNITTEST_ASSERT_TRUE(_unittest_result, rava_fastframe_current() == f3, "current should be f3");
|
||||||
|
|
||||||
rava_fastframe_pop();
|
rava_fastframe_pop();
|
||||||
assert(rava_fastframe_current() == f2);
|
UNITTEST_ASSERT_TRUE(_unittest_result, rava_fastframe_current() == f2, "current should be f2");
|
||||||
|
|
||||||
rava_fastframe_pop();
|
rava_fastframe_pop();
|
||||||
assert(rava_fastframe_current() == f1);
|
UNITTEST_ASSERT_TRUE(_unittest_result, rava_fastframe_current() == f1, "current should be f1");
|
||||||
|
|
||||||
rava_fastframe_pop();
|
rava_fastframe_pop();
|
||||||
assert(rava_fastframe_current() == NULL);
|
UNITTEST_ASSERT_NULL(_unittest_result, rava_fastframe_current(), "current should be NULL");
|
||||||
|
|
||||||
|
UNITTEST_END_TEST();
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST(stack_operations) {
|
UnittestTestResult_t* test_stack_operations(void) {
|
||||||
|
UNITTEST_BEGIN_TEST("TestFastFrame", "test_stack_operations");
|
||||||
|
|
||||||
rava_fastframe_init();
|
rava_fastframe_init();
|
||||||
|
|
||||||
FastFrame_t* frame = rava_fastframe_push(NULL, 4);
|
FastFrame_t* frame = rava_fastframe_push(NULL, 4);
|
||||||
assert(rava_fastframe_stack_is_empty(frame));
|
UNITTEST_ASSERT_TRUE(_unittest_result, rava_fastframe_stack_is_empty(frame), "stack should be empty");
|
||||||
|
|
||||||
rava_fastframe_stack_push(frame, rava_nanbox_int(10));
|
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(20));
|
||||||
rava_fastframe_stack_push(frame, rava_nanbox_int(30));
|
rava_fastframe_stack_push(frame, rava_nanbox_int(30));
|
||||||
|
|
||||||
assert(!rava_fastframe_stack_is_empty(frame));
|
UNITTEST_ASSERT_FALSE(_unittest_result, rava_fastframe_stack_is_empty(frame), "stack should not be empty");
|
||||||
assert(frame->stack_top == 3);
|
UNITTEST_ASSERT_EQUAL(_unittest_result, 3, frame->stack_top, "stack top should be 3");
|
||||||
|
|
||||||
RavaNanboxValue_t top = rava_fastframe_stack_peek(frame);
|
RavaNanboxValue_t top = rava_fastframe_stack_peek(frame);
|
||||||
assert(rava_nanbox_as_int(top) == 30);
|
UNITTEST_ASSERT_EQUAL(_unittest_result, 30, rava_nanbox_as_int(top), "peek should return 30");
|
||||||
assert(frame->stack_top == 3);
|
UNITTEST_ASSERT_EQUAL(_unittest_result, 3, frame->stack_top, "peek should not change stack top");
|
||||||
|
|
||||||
RavaNanboxValue_t v1 = rava_fastframe_stack_pop(frame);
|
RavaNanboxValue_t v1 = rava_fastframe_stack_pop(frame);
|
||||||
RavaNanboxValue_t v2 = rava_fastframe_stack_pop(frame);
|
RavaNanboxValue_t v2 = rava_fastframe_stack_pop(frame);
|
||||||
RavaNanboxValue_t v3 = rava_fastframe_stack_pop(frame);
|
RavaNanboxValue_t v3 = rava_fastframe_stack_pop(frame);
|
||||||
|
|
||||||
assert(rava_nanbox_as_int(v1) == 30);
|
UNITTEST_ASSERT_EQUAL(_unittest_result, 30, rava_nanbox_as_int(v1), "first pop should return 30");
|
||||||
assert(rava_nanbox_as_int(v2) == 20);
|
UNITTEST_ASSERT_EQUAL(_unittest_result, 20, rava_nanbox_as_int(v2), "second pop should return 20");
|
||||||
assert(rava_nanbox_as_int(v3) == 10);
|
UNITTEST_ASSERT_EQUAL(_unittest_result, 10, rava_nanbox_as_int(v3), "third pop should return 10");
|
||||||
assert(rava_fastframe_stack_is_empty(frame));
|
UNITTEST_ASSERT_TRUE(_unittest_result, rava_fastframe_stack_is_empty(frame), "stack should be empty after pops");
|
||||||
|
|
||||||
rava_fastframe_reset();
|
rava_fastframe_reset();
|
||||||
|
|
||||||
|
UNITTEST_END_TEST();
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST(locals) {
|
UnittestTestResult_t* test_locals(void) {
|
||||||
|
UNITTEST_BEGIN_TEST("TestFastFrame", "test_locals");
|
||||||
|
|
||||||
rava_fastframe_init();
|
rava_fastframe_init();
|
||||||
|
|
||||||
FastFrame_t* frame = rava_fastframe_push(NULL, 8);
|
FastFrame_t* frame = rava_fastframe_push(NULL, 8);
|
||||||
@ -89,27 +96,35 @@ TEST(locals) {
|
|||||||
frame->locals[1] = rava_nanbox_int(200);
|
frame->locals[1] = rava_nanbox_int(200);
|
||||||
frame->locals[2] = rava_nanbox_bool(true);
|
frame->locals[2] = rava_nanbox_bool(true);
|
||||||
|
|
||||||
assert(rava_nanbox_as_int(frame->locals[0]) == 100);
|
UNITTEST_ASSERT_EQUAL(_unittest_result, 100, rava_nanbox_as_int(frame->locals[0]), "local 0 should be 100");
|
||||||
assert(rava_nanbox_as_int(frame->locals[1]) == 200);
|
UNITTEST_ASSERT_EQUAL(_unittest_result, 200, rava_nanbox_as_int(frame->locals[1]), "local 1 should be 200");
|
||||||
assert(rava_nanbox_as_bool(frame->locals[2]) == true);
|
UNITTEST_ASSERT_TRUE(_unittest_result, rava_nanbox_as_bool(frame->locals[2]), "local 2 should be true");
|
||||||
|
|
||||||
rava_fastframe_reset();
|
rava_fastframe_reset();
|
||||||
|
|
||||||
|
UNITTEST_END_TEST();
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST(reset) {
|
UnittestTestResult_t* test_reset(void) {
|
||||||
|
UNITTEST_BEGIN_TEST("TestFastFrame", "test_reset");
|
||||||
|
|
||||||
rava_fastframe_init();
|
rava_fastframe_init();
|
||||||
|
|
||||||
rava_fastframe_push(NULL, 2);
|
rava_fastframe_push(NULL, 2);
|
||||||
rava_fastframe_push(NULL, 2);
|
rava_fastframe_push(NULL, 2);
|
||||||
rava_fastframe_push(NULL, 2);
|
rava_fastframe_push(NULL, 2);
|
||||||
|
|
||||||
assert(rava_fastframe_get_depth() == 3);
|
UNITTEST_ASSERT_EQUAL(_unittest_result, 3, rava_fastframe_get_depth(), "depth should be 3");
|
||||||
|
|
||||||
rava_fastframe_reset();
|
rava_fastframe_reset();
|
||||||
assert(rava_fastframe_get_depth() == 0);
|
UNITTEST_ASSERT_EQUAL(_unittest_result, 0, rava_fastframe_get_depth(), "depth should be 0 after reset");
|
||||||
|
|
||||||
|
UNITTEST_END_TEST();
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST(stack_clear) {
|
UnittestTestResult_t* test_stack_clear(void) {
|
||||||
|
UNITTEST_BEGIN_TEST("TestFastFrame", "test_stack_clear");
|
||||||
|
|
||||||
rava_fastframe_init();
|
rava_fastframe_init();
|
||||||
|
|
||||||
FastFrame_t* frame = rava_fastframe_push(NULL, 4);
|
FastFrame_t* frame = rava_fastframe_push(NULL, 4);
|
||||||
@ -117,26 +132,43 @@ TEST(stack_clear) {
|
|||||||
rava_fastframe_stack_push(frame, rava_nanbox_int(2));
|
rava_fastframe_stack_push(frame, rava_nanbox_int(2));
|
||||||
rava_fastframe_stack_push(frame, rava_nanbox_int(3));
|
rava_fastframe_stack_push(frame, rava_nanbox_int(3));
|
||||||
|
|
||||||
assert(frame->stack_top == 3);
|
UNITTEST_ASSERT_EQUAL(_unittest_result, 3, frame->stack_top, "stack top should be 3");
|
||||||
|
|
||||||
rava_fastframe_stack_clear(frame);
|
rava_fastframe_stack_clear(frame);
|
||||||
assert(frame->stack_top == 0);
|
UNITTEST_ASSERT_EQUAL(_unittest_result, 0, frame->stack_top, "stack top should be 0 after clear");
|
||||||
assert(rava_fastframe_stack_is_empty(frame));
|
UNITTEST_ASSERT_TRUE(_unittest_result, rava_fastframe_stack_is_empty(frame), "stack should be empty after clear");
|
||||||
|
|
||||||
rava_fastframe_reset();
|
rava_fastframe_reset();
|
||||||
|
|
||||||
|
UNITTEST_END_TEST();
|
||||||
}
|
}
|
||||||
|
|
||||||
int main(void) {
|
int main(int argc, char **argv) {
|
||||||
printf("=== Fast Frame Unit Tests ===\n\n");
|
UnittestConfig_t *config = unittest_config_create();
|
||||||
|
config->verbosity = 2;
|
||||||
|
|
||||||
RUN_TEST(init);
|
if (argc > 1 && strcmp(argv[1], "--json") == 0) {
|
||||||
RUN_TEST(push_pop);
|
config->output_format = UNITTEST_FORMAT_JSON;
|
||||||
RUN_TEST(nested_frames);
|
config->use_colors = false;
|
||||||
RUN_TEST(stack_operations);
|
}
|
||||||
RUN_TEST(locals);
|
|
||||||
RUN_TEST(reset);
|
UnittestTestSuite_t *suite = unittest_test_suite_create("Fast Frame Tests");
|
||||||
RUN_TEST(stack_clear);
|
|
||||||
|
UnittestTestCase_t *tc = unittest_test_case_create("TestFastFrame");
|
||||||
printf("\n=== Results: %d tests passed ===\n", tests_passed);
|
unittest_test_case_add_result(tc, test_init());
|
||||||
return 0;
|
unittest_test_case_add_result(tc, test_push_pop());
|
||||||
|
unittest_test_case_add_result(tc, test_nested_frames());
|
||||||
|
unittest_test_case_add_result(tc, test_stack_operations());
|
||||||
|
unittest_test_case_add_result(tc, test_locals());
|
||||||
|
unittest_test_case_add_result(tc, test_reset());
|
||||||
|
unittest_test_case_add_result(tc, test_stack_clear());
|
||||||
|
unittest_test_suite_add_test_case(suite, tc);
|
||||||
|
|
||||||
|
unittest_generate_report(suite, config);
|
||||||
|
|
||||||
|
int failures = suite->total_failed + suite->total_errors;
|
||||||
|
unittest_test_suite_destroy(suite);
|
||||||
|
unittest_config_destroy(config);
|
||||||
|
|
||||||
|
return failures > 0 ? 1 : 0;
|
||||||
}
|
}
|
||||||
|
|||||||
Binary file not shown.
@ -1,77 +1,133 @@
|
|||||||
#include "../lexer/lexer.h"
|
#include "test_utils.h"
|
||||||
#include "../parser/parser.h"
|
|
||||||
#include "../semantic/semantic.h"
|
|
||||||
#include "../ir/ir.h"
|
|
||||||
#include "../ir/ir_gen.h"
|
|
||||||
#include "../runtime/runtime.h"
|
|
||||||
#include <stdio.h>
|
|
||||||
#include <stdlib.h>
|
|
||||||
#include <string.h>
|
|
||||||
|
|
||||||
static char* read_file(const char *filename) {
|
UnittestTestResult_t* test_forloop_example(void) {
|
||||||
FILE *file = fopen(filename, "r");
|
UNITTEST_BEGIN_TEST("TestForLoop", "test_forloop_example");
|
||||||
if (!file) return NULL;
|
|
||||||
fseek(file, 0, SEEK_END);
|
RAVA_TEST_FILE_EXECUTES(_unittest_result,
|
||||||
long size = ftell(file);
|
"examples/16_ForLoop.java",
|
||||||
fseek(file, 0, SEEK_SET);
|
"ForLoop", "main",
|
||||||
char *content = malloc(size + 1);
|
"for loop example should execute successfully");
|
||||||
size_t read_bytes = fread(content, 1, size, file); (void)read_bytes;
|
|
||||||
content[size] = '\0';
|
UNITTEST_END_TEST();
|
||||||
fclose(file);
|
|
||||||
return content;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
int main() {
|
UnittestTestResult_t* test_forloop_sum(void) {
|
||||||
char *source = read_file("examples/16_ForLoop.java");
|
UNITTEST_BEGIN_TEST("TestForLoop", "test_forloop_sum");
|
||||||
if (!source) {
|
|
||||||
printf("Failed to read file\n");
|
RAVA_TEST_RUN(_unittest_result,
|
||||||
return 1;
|
"public class Test {\n"
|
||||||
|
" public static int main() {\n"
|
||||||
|
" int sum = 0;\n"
|
||||||
|
" for (int i = 1; i <= 10; i++) {\n"
|
||||||
|
" sum = sum + i;\n"
|
||||||
|
" }\n"
|
||||||
|
" return sum;\n"
|
||||||
|
" }\n"
|
||||||
|
"}\n",
|
||||||
|
"Test", "main", 55, "sum 1 to 10 should equal 55");
|
||||||
|
|
||||||
|
UNITTEST_END_TEST();
|
||||||
}
|
}
|
||||||
|
|
||||||
RavaLexer_t *lexer = rava_lexer_create(source);
|
UnittestTestResult_t* test_forloop_countdown(void) {
|
||||||
RavaParser_t *parser = rava_parser_create(lexer);
|
UNITTEST_BEGIN_TEST("TestForLoop", "test_forloop_countdown");
|
||||||
RavaASTNode_t *ast = rava_parser_parse(parser);
|
|
||||||
|
|
||||||
if (parser->had_error) {
|
RAVA_TEST_RUN(_unittest_result,
|
||||||
printf("Parse error: %s\n", parser->error_message);
|
"public class Test {\n"
|
||||||
free(source);
|
" public static int main() {\n"
|
||||||
return 1;
|
" int count = 0;\n"
|
||||||
|
" for (int i = 10; i > 0; i--) {\n"
|
||||||
|
" count = count + 1;\n"
|
||||||
|
" }\n"
|
||||||
|
" return count;\n"
|
||||||
|
" }\n"
|
||||||
|
"}\n",
|
||||||
|
"Test", "main", 10, "countdown from 10 should iterate 10 times");
|
||||||
|
|
||||||
|
UNITTEST_END_TEST();
|
||||||
}
|
}
|
||||||
|
|
||||||
printf("Parse: OK\n");
|
UnittestTestResult_t* test_forloop_nested(void) {
|
||||||
|
UNITTEST_BEGIN_TEST("TestForLoop", "test_forloop_nested");
|
||||||
|
|
||||||
RavaSemanticAnalyzer_t *analyzer = rava_semantic_analyzer_create();
|
RAVA_TEST_RUN(_unittest_result,
|
||||||
if (!rava_semantic_analyze(analyzer, ast)) {
|
"public class Test {\n"
|
||||||
printf("Semantic error: %s\n", analyzer->error_message);
|
" public static int main() {\n"
|
||||||
free(source);
|
" int count = 0;\n"
|
||||||
return 1;
|
" for (int i = 0; i < 3; i++) {\n"
|
||||||
|
" for (int j = 0; j < 4; j++) {\n"
|
||||||
|
" count = count + 1;\n"
|
||||||
|
" }\n"
|
||||||
|
" }\n"
|
||||||
|
" return count;\n"
|
||||||
|
" }\n"
|
||||||
|
"}\n",
|
||||||
|
"Test", "main", 12, "3x4 nested loops should count 12");
|
||||||
|
|
||||||
|
UNITTEST_END_TEST();
|
||||||
}
|
}
|
||||||
|
|
||||||
printf("Semantic: OK\n");
|
UnittestTestResult_t* test_forloop_step_by_two(void) {
|
||||||
|
UNITTEST_BEGIN_TEST("TestForLoop", "test_forloop_step_by_two");
|
||||||
|
|
||||||
RavaIRGenerator_t *ir_gen = rava_ir_generator_create(analyzer);
|
RAVA_TEST_RUN(_unittest_result,
|
||||||
RavaProgram_t *program = rava_ir_generate(ir_gen, ast);
|
"public class Test {\n"
|
||||||
|
" public static int main() {\n"
|
||||||
|
" int sum = 0;\n"
|
||||||
|
" for (int i = 0; i < 10; i = i + 2) {\n"
|
||||||
|
" sum = sum + i;\n"
|
||||||
|
" }\n"
|
||||||
|
" return sum;\n"
|
||||||
|
" }\n"
|
||||||
|
"}\n",
|
||||||
|
"Test", "main", 20, "sum even numbers 0-8 should equal 20");
|
||||||
|
|
||||||
if (!program) {
|
UNITTEST_END_TEST();
|
||||||
printf("IR generation failed\n");
|
|
||||||
free(source);
|
|
||||||
return 1;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
printf("IR Gen: OK\n");
|
UnittestTestResult_t* test_forloop_zero_iterations(void) {
|
||||||
printf("\nOutput:\n");
|
UNITTEST_BEGIN_TEST("TestForLoop", "test_forloop_zero_iterations");
|
||||||
|
|
||||||
RavaVM_t *vm = rava_vm_create(program);
|
RAVA_TEST_RUN(_unittest_result,
|
||||||
if (!rava_vm_execute(vm, "ForLoop", "main")) {
|
"public class Test {\n"
|
||||||
printf("Runtime error: %s\n", vm->error_message);
|
" public static int main() {\n"
|
||||||
rava_vm_destroy(vm);
|
" int count = 0;\n"
|
||||||
free(source);
|
" for (int i = 0; i < 0; i++) {\n"
|
||||||
return 1;
|
" count = count + 1;\n"
|
||||||
|
" }\n"
|
||||||
|
" return count;\n"
|
||||||
|
" }\n"
|
||||||
|
"}\n",
|
||||||
|
"Test", "main", 0, "loop with false condition should not execute");
|
||||||
|
|
||||||
|
UNITTEST_END_TEST();
|
||||||
}
|
}
|
||||||
|
|
||||||
printf("\nExecution: OK\n");
|
int main(int argc, char **argv) {
|
||||||
|
UnittestConfig_t *config = unittest_config_create();
|
||||||
|
config->verbosity = 2;
|
||||||
|
|
||||||
rava_vm_destroy(vm);
|
if (argc > 1 && strcmp(argv[1], "--json") == 0) {
|
||||||
free(source);
|
config->output_format = UNITTEST_FORMAT_JSON;
|
||||||
return 0;
|
config->use_colors = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
UnittestTestSuite_t *suite = unittest_test_suite_create("For Loop Tests");
|
||||||
|
|
||||||
|
UnittestTestCase_t *tc = unittest_test_case_create("TestForLoop");
|
||||||
|
unittest_test_case_add_result(tc, test_forloop_example());
|
||||||
|
unittest_test_case_add_result(tc, test_forloop_sum());
|
||||||
|
unittest_test_case_add_result(tc, test_forloop_countdown());
|
||||||
|
unittest_test_case_add_result(tc, test_forloop_nested());
|
||||||
|
unittest_test_case_add_result(tc, test_forloop_step_by_two());
|
||||||
|
unittest_test_case_add_result(tc, test_forloop_zero_iterations());
|
||||||
|
unittest_test_suite_add_test_case(suite, tc);
|
||||||
|
|
||||||
|
unittest_generate_report(suite, config);
|
||||||
|
|
||||||
|
int failures = suite->total_failed + suite->total_errors;
|
||||||
|
unittest_test_suite_destroy(suite);
|
||||||
|
unittest_config_destroy(config);
|
||||||
|
|
||||||
|
return failures > 0 ? 1 : 0;
|
||||||
}
|
}
|
||||||
|
|||||||
232
tests/test_gc.c
Normal file
232
tests/test_gc.c
Normal file
@ -0,0 +1,232 @@
|
|||||||
|
#include "test_utils.h"
|
||||||
|
|
||||||
|
UnittestTestResult_t* test_gc_basic_allocation(void) {
|
||||||
|
UNITTEST_BEGIN_TEST("TestGC", "test_gc_basic_allocation");
|
||||||
|
|
||||||
|
const char *source =
|
||||||
|
"public class Test {\n"
|
||||||
|
" public static int main() {\n"
|
||||||
|
" int[] arr = new int[100];\n"
|
||||||
|
" for (int i = 0; i < 100; i++) {\n"
|
||||||
|
" arr[i] = i;\n"
|
||||||
|
" }\n"
|
||||||
|
" return arr[99];\n"
|
||||||
|
" }\n"
|
||||||
|
"}\n";
|
||||||
|
|
||||||
|
RAVA_TEST_RUN(_unittest_result, source, "Test", "main", 99,
|
||||||
|
"Should allocate array without crash");
|
||||||
|
|
||||||
|
UNITTEST_END_TEST();
|
||||||
|
}
|
||||||
|
|
||||||
|
UnittestTestResult_t* test_gc_object_allocation(void) {
|
||||||
|
UNITTEST_BEGIN_TEST("TestGC", "test_gc_object_allocation");
|
||||||
|
|
||||||
|
const char *source =
|
||||||
|
"public class Point {\n"
|
||||||
|
" public int x;\n"
|
||||||
|
" public int y;\n"
|
||||||
|
"}\n"
|
||||||
|
"public class Test {\n"
|
||||||
|
" public static int main() {\n"
|
||||||
|
" Point p = new Point();\n"
|
||||||
|
" p.x = 10;\n"
|
||||||
|
" p.y = 20;\n"
|
||||||
|
" return p.x + p.y;\n"
|
||||||
|
" }\n"
|
||||||
|
"}\n";
|
||||||
|
|
||||||
|
RAVA_TEST_RUN(_unittest_result, source, "Test", "main", 30,
|
||||||
|
"Should allocate object without crash");
|
||||||
|
|
||||||
|
UNITTEST_END_TEST();
|
||||||
|
}
|
||||||
|
|
||||||
|
UnittestTestResult_t* test_gc_many_allocations(void) {
|
||||||
|
UNITTEST_BEGIN_TEST("TestGC", "test_gc_many_allocations");
|
||||||
|
|
||||||
|
const char *source =
|
||||||
|
"public class Test {\n"
|
||||||
|
" public static int main() {\n"
|
||||||
|
" int sum = 0;\n"
|
||||||
|
" for (int i = 0; i < 1000; i++) {\n"
|
||||||
|
" int[] temp = new int[10];\n"
|
||||||
|
" temp[0] = i;\n"
|
||||||
|
" sum = sum + temp[0];\n"
|
||||||
|
" }\n"
|
||||||
|
" return sum;\n"
|
||||||
|
" }\n"
|
||||||
|
"}\n";
|
||||||
|
|
||||||
|
RAVA_TEST_RUN(_unittest_result, source, "Test", "main", 499500,
|
||||||
|
"Should handle many allocations");
|
||||||
|
|
||||||
|
UNITTEST_END_TEST();
|
||||||
|
}
|
||||||
|
|
||||||
|
UnittestTestResult_t* test_gc_arraylist(void) {
|
||||||
|
UNITTEST_BEGIN_TEST("TestGC", "test_gc_arraylist");
|
||||||
|
|
||||||
|
const char *source =
|
||||||
|
"public class Test {\n"
|
||||||
|
" public static int main() {\n"
|
||||||
|
" ArrayList list = new ArrayList();\n"
|
||||||
|
" for (int i = 0; i < 100; i++) {\n"
|
||||||
|
" list.add(i);\n"
|
||||||
|
" }\n"
|
||||||
|
" return list.size();\n"
|
||||||
|
" }\n"
|
||||||
|
"}\n";
|
||||||
|
|
||||||
|
RAVA_TEST_RUN(_unittest_result, source, "Test", "main", 100,
|
||||||
|
"Should handle ArrayList allocations");
|
||||||
|
|
||||||
|
UNITTEST_END_TEST();
|
||||||
|
}
|
||||||
|
|
||||||
|
UnittestTestResult_t* test_gc_hashmap(void) {
|
||||||
|
UNITTEST_BEGIN_TEST("TestGC", "test_gc_hashmap");
|
||||||
|
|
||||||
|
const char *source =
|
||||||
|
"public class Test {\n"
|
||||||
|
" public static int main() {\n"
|
||||||
|
" HashMap map = new HashMap();\n"
|
||||||
|
" map.put(\"one\", 1);\n"
|
||||||
|
" map.put(\"two\", 2);\n"
|
||||||
|
" map.put(\"three\", 3);\n"
|
||||||
|
" return map.size();\n"
|
||||||
|
" }\n"
|
||||||
|
"}\n";
|
||||||
|
|
||||||
|
RAVA_TEST_RUN(_unittest_result, source, "Test", "main", 3,
|
||||||
|
"Should handle HashMap allocations");
|
||||||
|
|
||||||
|
UNITTEST_END_TEST();
|
||||||
|
}
|
||||||
|
|
||||||
|
UnittestTestResult_t* test_gc_collection_triggered(void) {
|
||||||
|
UNITTEST_BEGIN_TEST("TestGC", "test_gc_collection_triggered");
|
||||||
|
|
||||||
|
const char *source =
|
||||||
|
"public class Test {\n"
|
||||||
|
" public static int main() {\n"
|
||||||
|
" int count = 0;\n"
|
||||||
|
" for (int i = 0; i < 10000; i++) {\n"
|
||||||
|
" int[] temp = new int[100];\n"
|
||||||
|
" temp[0] = i;\n"
|
||||||
|
" count = count + 1;\n"
|
||||||
|
" }\n"
|
||||||
|
" return count;\n"
|
||||||
|
" }\n"
|
||||||
|
"}\n";
|
||||||
|
|
||||||
|
RAVA_TEST_RUN(_unittest_result, source, "Test", "main", 10000,
|
||||||
|
"Should handle many temporary allocations via GC");
|
||||||
|
|
||||||
|
UNITTEST_END_TEST();
|
||||||
|
}
|
||||||
|
|
||||||
|
UnittestTestResult_t* test_gc_circular_references(void) {
|
||||||
|
UNITTEST_BEGIN_TEST("TestGC", "test_gc_circular_references");
|
||||||
|
|
||||||
|
const char *source =
|
||||||
|
"public class Test {\n"
|
||||||
|
" public static int main() {\n"
|
||||||
|
" int sum = 0;\n"
|
||||||
|
" for (int i = 0; i < 100; i++) {\n"
|
||||||
|
" int[] a = new int[10];\n"
|
||||||
|
" int[] b = new int[10];\n"
|
||||||
|
" a[0] = i;\n"
|
||||||
|
" b[0] = i * 2;\n"
|
||||||
|
" sum = sum + a[0] + b[0];\n"
|
||||||
|
" }\n"
|
||||||
|
" return sum;\n"
|
||||||
|
" }\n"
|
||||||
|
"}\n";
|
||||||
|
|
||||||
|
RAVA_TEST_RUN(_unittest_result, source, "Test", "main", 14850,
|
||||||
|
"Should handle many paired allocations");
|
||||||
|
|
||||||
|
UNITTEST_END_TEST();
|
||||||
|
}
|
||||||
|
|
||||||
|
UnittestTestResult_t* test_gc_deep_object_graph(void) {
|
||||||
|
UNITTEST_BEGIN_TEST("TestGC", "test_gc_deep_object_graph");
|
||||||
|
|
||||||
|
const char *source =
|
||||||
|
"public class Test {\n"
|
||||||
|
" public static int main() {\n"
|
||||||
|
" int[][] matrix = new int[50][50];\n"
|
||||||
|
" int sum = 0;\n"
|
||||||
|
" for (int i = 0; i < 50; i++) {\n"
|
||||||
|
" for (int j = 0; j < 50; j++) {\n"
|
||||||
|
" matrix[i][j] = i + j;\n"
|
||||||
|
" sum = sum + matrix[i][j];\n"
|
||||||
|
" }\n"
|
||||||
|
" }\n"
|
||||||
|
" return sum;\n"
|
||||||
|
" }\n"
|
||||||
|
"}\n";
|
||||||
|
|
||||||
|
RAVA_TEST_RUN(_unittest_result, source, "Test", "main", 122500,
|
||||||
|
"Should handle nested array allocations");
|
||||||
|
|
||||||
|
UNITTEST_END_TEST();
|
||||||
|
}
|
||||||
|
|
||||||
|
UnittestTestResult_t* test_gc_mixed_types(void) {
|
||||||
|
UNITTEST_BEGIN_TEST("TestGC", "test_gc_mixed_types");
|
||||||
|
|
||||||
|
const char *source =
|
||||||
|
"public class Test {\n"
|
||||||
|
" public static int main() {\n"
|
||||||
|
" int[] data = new int[50];\n"
|
||||||
|
" for (int i = 0; i < 50; i++) {\n"
|
||||||
|
" data[i] = i * 2;\n"
|
||||||
|
" }\n"
|
||||||
|
" int sum = 0;\n"
|
||||||
|
" for (int j = 0; j < 50; j++) {\n"
|
||||||
|
" sum = sum + data[j];\n"
|
||||||
|
" }\n"
|
||||||
|
" return sum;\n"
|
||||||
|
" }\n"
|
||||||
|
"}\n";
|
||||||
|
|
||||||
|
RAVA_TEST_RUN(_unittest_result, source, "Test", "main", 2450,
|
||||||
|
"Should handle array operations");
|
||||||
|
|
||||||
|
UNITTEST_END_TEST();
|
||||||
|
}
|
||||||
|
|
||||||
|
int main(int argc, char **argv) {
|
||||||
|
UnittestConfig_t *config = unittest_config_create();
|
||||||
|
config->verbosity = 2;
|
||||||
|
|
||||||
|
if (argc > 1 && strcmp(argv[1], "--json") == 0) {
|
||||||
|
config->output_format = UNITTEST_FORMAT_JSON;
|
||||||
|
config->use_colors = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
UnittestTestSuite_t *suite = unittest_test_suite_create("GC Tests");
|
||||||
|
|
||||||
|
UnittestTestCase_t *tc = unittest_test_case_create("TestGC");
|
||||||
|
unittest_test_case_add_result(tc, test_gc_basic_allocation());
|
||||||
|
unittest_test_case_add_result(tc, test_gc_object_allocation());
|
||||||
|
unittest_test_case_add_result(tc, test_gc_many_allocations());
|
||||||
|
unittest_test_case_add_result(tc, test_gc_arraylist());
|
||||||
|
unittest_test_case_add_result(tc, test_gc_hashmap());
|
||||||
|
unittest_test_case_add_result(tc, test_gc_collection_triggered());
|
||||||
|
unittest_test_case_add_result(tc, test_gc_circular_references());
|
||||||
|
unittest_test_case_add_result(tc, test_gc_deep_object_graph());
|
||||||
|
unittest_test_case_add_result(tc, test_gc_mixed_types());
|
||||||
|
unittest_test_suite_add_test_case(suite, tc);
|
||||||
|
|
||||||
|
unittest_generate_report(suite, config);
|
||||||
|
|
||||||
|
int failures = suite->total_failed + suite->total_errors;
|
||||||
|
unittest_test_suite_destroy(suite);
|
||||||
|
unittest_config_destroy(config);
|
||||||
|
|
||||||
|
return failures > 0 ? 1 : 0;
|
||||||
|
}
|
||||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
@ -1,33 +1,31 @@
|
|||||||
#include <stdio.h>
|
#include "test_utils.h"
|
||||||
#include <assert.h>
|
|
||||||
#include <stdlib.h>
|
|
||||||
#include "../ir/ir.h"
|
#include "../ir/ir.h"
|
||||||
#include "../runtime/labeltable.h"
|
#include "../runtime/labeltable.h"
|
||||||
|
|
||||||
static int tests_passed = 0;
|
UnittestTestResult_t* test_create_empty(void) {
|
||||||
|
UNITTEST_BEGIN_TEST("TestLabelTable", "test_create_empty");
|
||||||
|
|
||||||
#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();
|
RavaInstructionList_t* list = rava_instruction_list_create();
|
||||||
LabelTable_t* table = rava_labeltable_create(list);
|
LabelTable_t* table = rava_labeltable_create(list);
|
||||||
assert(table != NULL);
|
UNITTEST_ASSERT_NOT_NULL(_unittest_result, table, "table should not be NULL");
|
||||||
rava_labeltable_destroy(table);
|
rava_labeltable_destroy(table);
|
||||||
rava_instruction_list_destroy(list);
|
rava_instruction_list_destroy(list);
|
||||||
|
|
||||||
|
UNITTEST_END_TEST();
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST(create_null) {
|
UnittestTestResult_t* test_create_null(void) {
|
||||||
|
UNITTEST_BEGIN_TEST("TestLabelTable", "test_create_null");
|
||||||
|
|
||||||
LabelTable_t* table = rava_labeltable_create(NULL);
|
LabelTable_t* table = rava_labeltable_create(NULL);
|
||||||
assert(table == NULL);
|
UNITTEST_ASSERT_NULL(_unittest_result, table, "table should be NULL for NULL input");
|
||||||
|
|
||||||
|
UNITTEST_END_TEST();
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST(single_label) {
|
UnittestTestResult_t* test_single_label(void) {
|
||||||
|
UNITTEST_BEGIN_TEST("TestLabelTable", "test_single_label");
|
||||||
|
|
||||||
RavaInstructionList_t* list = rava_instruction_list_create();
|
RavaInstructionList_t* list = rava_instruction_list_create();
|
||||||
|
|
||||||
RavaInstruction_t instr1 = {.opcode = RAVA_OP_LOAD_CONST, .operand.int_value = 10};
|
RavaInstruction_t instr1 = {.opcode = RAVA_OP_LOAD_CONST, .operand.int_value = 10};
|
||||||
@ -39,16 +37,20 @@ TEST(single_label) {
|
|||||||
rava_instruction_list_add(list, instr3);
|
rava_instruction_list_add(list, instr3);
|
||||||
|
|
||||||
LabelTable_t* table = rava_labeltable_create(list);
|
LabelTable_t* table = rava_labeltable_create(list);
|
||||||
assert(table != NULL);
|
UNITTEST_ASSERT_NOT_NULL(_unittest_result, table, "table should not be NULL");
|
||||||
|
|
||||||
size_t pc = rava_labeltable_lookup(table, 0);
|
size_t pc = rava_labeltable_lookup(table, 0);
|
||||||
assert(pc == 2);
|
UNITTEST_ASSERT_EQUAL(_unittest_result, 2, (int)pc, "label 0 should point to PC 2");
|
||||||
|
|
||||||
rava_labeltable_destroy(table);
|
rava_labeltable_destroy(table);
|
||||||
rava_instruction_list_destroy(list);
|
rava_instruction_list_destroy(list);
|
||||||
|
|
||||||
|
UNITTEST_END_TEST();
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST(multiple_labels) {
|
UnittestTestResult_t* test_multiple_labels(void) {
|
||||||
|
UNITTEST_BEGIN_TEST("TestLabelTable", "test_multiple_labels");
|
||||||
|
|
||||||
RavaInstructionList_t* list = rava_instruction_list_create();
|
RavaInstructionList_t* list = rava_instruction_list_create();
|
||||||
|
|
||||||
RavaInstruction_t instr0 = {.opcode = RAVA_OP_LOAD_CONST, .operand.int_value = 0};
|
RavaInstruction_t instr0 = {.opcode = RAVA_OP_LOAD_CONST, .operand.int_value = 0};
|
||||||
@ -66,59 +68,84 @@ TEST(multiple_labels) {
|
|||||||
rava_instruction_list_add(list, label2);
|
rava_instruction_list_add(list, label2);
|
||||||
|
|
||||||
LabelTable_t* table = rava_labeltable_create(list);
|
LabelTable_t* table = rava_labeltable_create(list);
|
||||||
assert(table != NULL);
|
UNITTEST_ASSERT_NOT_NULL(_unittest_result, table, "table should not be NULL");
|
||||||
|
|
||||||
assert(rava_labeltable_lookup(table, 0) == 2);
|
UNITTEST_ASSERT_EQUAL(_unittest_result, 2, (int)rava_labeltable_lookup(table, 0), "label 0 should point to PC 2");
|
||||||
assert(rava_labeltable_lookup(table, 1) == 4);
|
UNITTEST_ASSERT_EQUAL(_unittest_result, 4, (int)rava_labeltable_lookup(table, 1), "label 1 should point to PC 4");
|
||||||
assert(rava_labeltable_lookup(table, 2) == 6);
|
UNITTEST_ASSERT_EQUAL(_unittest_result, 6, (int)rava_labeltable_lookup(table, 2), "label 2 should point to PC 6");
|
||||||
|
|
||||||
rava_labeltable_destroy(table);
|
rava_labeltable_destroy(table);
|
||||||
rava_instruction_list_destroy(list);
|
rava_instruction_list_destroy(list);
|
||||||
|
|
||||||
|
UNITTEST_END_TEST();
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST(missing_label) {
|
UnittestTestResult_t* test_missing_label(void) {
|
||||||
|
UNITTEST_BEGIN_TEST("TestLabelTable", "test_missing_label");
|
||||||
|
|
||||||
RavaInstructionList_t* list = rava_instruction_list_create();
|
RavaInstructionList_t* list = rava_instruction_list_create();
|
||||||
|
|
||||||
RavaInstruction_t label = {.opcode = RAVA_OP_LABEL, .operand.label_id = 5};
|
RavaInstruction_t label = {.opcode = RAVA_OP_LABEL, .operand.label_id = 5};
|
||||||
rava_instruction_list_add(list, label);
|
rava_instruction_list_add(list, label);
|
||||||
|
|
||||||
LabelTable_t* table = rava_labeltable_create(list);
|
LabelTable_t* table = rava_labeltable_create(list);
|
||||||
assert(table != NULL);
|
UNITTEST_ASSERT_NOT_NULL(_unittest_result, table, "table should not be NULL");
|
||||||
|
|
||||||
assert(rava_labeltable_lookup(table, 0) == 0);
|
UNITTEST_ASSERT_EQUAL(_unittest_result, 0, (int)rava_labeltable_lookup(table, 0), "missing label 0 should return 0");
|
||||||
assert(rava_labeltable_lookup(table, 1) == 0);
|
UNITTEST_ASSERT_EQUAL(_unittest_result, 0, (int)rava_labeltable_lookup(table, 1), "missing label 1 should return 0");
|
||||||
assert(rava_labeltable_lookup(table, 5) == 1);
|
UNITTEST_ASSERT_EQUAL(_unittest_result, 1, (int)rava_labeltable_lookup(table, 5), "label 5 should point to PC 1");
|
||||||
|
|
||||||
rava_labeltable_destroy(table);
|
rava_labeltable_destroy(table);
|
||||||
rava_instruction_list_destroy(list);
|
rava_instruction_list_destroy(list);
|
||||||
|
|
||||||
|
UNITTEST_END_TEST();
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST(out_of_range) {
|
UnittestTestResult_t* test_out_of_range(void) {
|
||||||
|
UNITTEST_BEGIN_TEST("TestLabelTable", "test_out_of_range");
|
||||||
|
|
||||||
RavaInstructionList_t* list = rava_instruction_list_create();
|
RavaInstructionList_t* list = rava_instruction_list_create();
|
||||||
|
|
||||||
RavaInstruction_t label = {.opcode = RAVA_OP_LABEL, .operand.label_id = 2};
|
RavaInstruction_t label = {.opcode = RAVA_OP_LABEL, .operand.label_id = 2};
|
||||||
rava_instruction_list_add(list, label);
|
rava_instruction_list_add(list, label);
|
||||||
|
|
||||||
LabelTable_t* table = rava_labeltable_create(list);
|
LabelTable_t* table = rava_labeltable_create(list);
|
||||||
assert(table != NULL);
|
UNITTEST_ASSERT_NOT_NULL(_unittest_result, table, "table should not be NULL");
|
||||||
|
|
||||||
assert(rava_labeltable_lookup(table, 100) == 0);
|
UNITTEST_ASSERT_EQUAL(_unittest_result, 0, (int)rava_labeltable_lookup(table, 100), "out of range label should return 0");
|
||||||
assert(rava_labeltable_lookup(table, -1) == 0);
|
UNITTEST_ASSERT_EQUAL(_unittest_result, 0, (int)rava_labeltable_lookup(table, -1), "negative label should return 0");
|
||||||
|
|
||||||
rava_labeltable_destroy(table);
|
rava_labeltable_destroy(table);
|
||||||
rava_instruction_list_destroy(list);
|
rava_instruction_list_destroy(list);
|
||||||
|
|
||||||
|
UNITTEST_END_TEST();
|
||||||
}
|
}
|
||||||
|
|
||||||
int main(void) {
|
int main(int argc, char **argv) {
|
||||||
printf("=== Label Table Unit Tests ===\n\n");
|
UnittestConfig_t *config = unittest_config_create();
|
||||||
|
config->verbosity = 2;
|
||||||
|
|
||||||
RUN_TEST(create_empty);
|
if (argc > 1 && strcmp(argv[1], "--json") == 0) {
|
||||||
RUN_TEST(create_null);
|
config->output_format = UNITTEST_FORMAT_JSON;
|
||||||
RUN_TEST(single_label);
|
config->use_colors = false;
|
||||||
RUN_TEST(multiple_labels);
|
}
|
||||||
RUN_TEST(missing_label);
|
|
||||||
RUN_TEST(out_of_range);
|
UnittestTestSuite_t *suite = unittest_test_suite_create("Label Table Tests");
|
||||||
|
|
||||||
printf("\n=== Results: %d tests passed ===\n", tests_passed);
|
UnittestTestCase_t *tc = unittest_test_case_create("TestLabelTable");
|
||||||
return 0;
|
unittest_test_case_add_result(tc, test_create_empty());
|
||||||
|
unittest_test_case_add_result(tc, test_create_null());
|
||||||
|
unittest_test_case_add_result(tc, test_single_label());
|
||||||
|
unittest_test_case_add_result(tc, test_multiple_labels());
|
||||||
|
unittest_test_case_add_result(tc, test_missing_label());
|
||||||
|
unittest_test_case_add_result(tc, test_out_of_range());
|
||||||
|
unittest_test_suite_add_test_case(suite, tc);
|
||||||
|
|
||||||
|
unittest_generate_report(suite, config);
|
||||||
|
|
||||||
|
int failures = suite->total_failed + suite->total_errors;
|
||||||
|
unittest_test_suite_destroy(suite);
|
||||||
|
unittest_config_destroy(config);
|
||||||
|
|
||||||
|
return failures > 0 ? 1 : 0;
|
||||||
}
|
}
|
||||||
|
|||||||
233
tests/test_loader.c
Normal file
233
tests/test_loader.c
Normal file
@ -0,0 +1,233 @@
|
|||||||
|
#include "test_utils.h"
|
||||||
|
#include "../loader/loader.h"
|
||||||
|
|
||||||
|
static RavaNativeValue_t test_add(RavaNativeValue_t *args, size_t arg_count, void *user_data) {
|
||||||
|
(void)user_data;
|
||||||
|
if (arg_count != 2) return rava_native_int(0);
|
||||||
|
int32_t a = args[0].data.int_val;
|
||||||
|
int32_t b = args[1].data.int_val;
|
||||||
|
return rava_native_int(a + b);
|
||||||
|
}
|
||||||
|
|
||||||
|
static RavaNativeValue_t test_multiply(RavaNativeValue_t *args, size_t arg_count, void *user_data) {
|
||||||
|
(void)user_data;
|
||||||
|
if (arg_count != 2) return rava_native_int(0);
|
||||||
|
int32_t a = args[0].data.int_val;
|
||||||
|
int32_t b = args[1].data.int_val;
|
||||||
|
return rava_native_int(a * b);
|
||||||
|
}
|
||||||
|
|
||||||
|
static RavaNativeValue_t test_greet(RavaNativeValue_t *args, size_t arg_count, void *user_data) {
|
||||||
|
(void)user_data;
|
||||||
|
if (arg_count != 1) return rava_native_string("");
|
||||||
|
const char *name = args[0].data.string_val;
|
||||||
|
char buffer[256];
|
||||||
|
snprintf(buffer, sizeof(buffer), "Hello, %s!", name ? name : "World");
|
||||||
|
return rava_native_string(buffer);
|
||||||
|
}
|
||||||
|
|
||||||
|
UnittestTestResult_t* test_registry_create_destroy(void) {
|
||||||
|
UNITTEST_BEGIN_TEST("TestLoader", "test_registry_create_destroy");
|
||||||
|
|
||||||
|
RavaNativeRegistry_t *registry = rava_native_registry_create();
|
||||||
|
UNITTEST_ASSERT_NOT_NULL(_unittest_result, registry, "registry should be created");
|
||||||
|
UNITTEST_ASSERT_EQUAL_INT(_unittest_result, 0, (int)registry->library_count, "library count should be 0");
|
||||||
|
UNITTEST_ASSERT_EQUAL_INT(_unittest_result, 0, (int)registry->cache_count, "cache count should be 0");
|
||||||
|
|
||||||
|
rava_native_registry_destroy(registry);
|
||||||
|
UNITTEST_ASSERT_PASS(_unittest_result, "registry destroyed without crash");
|
||||||
|
|
||||||
|
UNITTEST_END_TEST();
|
||||||
|
}
|
||||||
|
|
||||||
|
UnittestTestResult_t* test_register_method(void) {
|
||||||
|
UNITTEST_BEGIN_TEST("TestLoader", "test_register_method");
|
||||||
|
|
||||||
|
RavaNativeRegistry_t *registry = rava_native_registry_create();
|
||||||
|
|
||||||
|
RavaNativeType_e params[] = {RAVA_NATIVE_INT, RAVA_NATIVE_INT};
|
||||||
|
bool result = rava_native_register_method(registry, "Math", "add",
|
||||||
|
RAVA_NATIVE_INT, params, 2,
|
||||||
|
test_add, NULL);
|
||||||
|
UNITTEST_ASSERT_TRUE(_unittest_result, result, "method registration should succeed");
|
||||||
|
UNITTEST_ASSERT_EQUAL_INT(_unittest_result, 1, (int)registry->cache_count, "cache count should be 1");
|
||||||
|
|
||||||
|
rava_native_registry_destroy(registry);
|
||||||
|
|
||||||
|
UNITTEST_END_TEST();
|
||||||
|
}
|
||||||
|
|
||||||
|
UnittestTestResult_t* test_find_method(void) {
|
||||||
|
UNITTEST_BEGIN_TEST("TestLoader", "test_find_method");
|
||||||
|
|
||||||
|
RavaNativeRegistry_t *registry = rava_native_registry_create();
|
||||||
|
|
||||||
|
RavaNativeType_e params[] = {RAVA_NATIVE_INT, RAVA_NATIVE_INT};
|
||||||
|
rava_native_register_method(registry, "Math", "add",
|
||||||
|
RAVA_NATIVE_INT, params, 2,
|
||||||
|
test_add, NULL);
|
||||||
|
|
||||||
|
RavaNativeMethod_t *method = rava_native_find_method(registry, "Math", "add");
|
||||||
|
UNITTEST_ASSERT_NOT_NULL(_unittest_result, method, "method should be found");
|
||||||
|
UNITTEST_ASSERT_EQUAL_STR(_unittest_result, "Math", method->class_name, "class name should match");
|
||||||
|
UNITTEST_ASSERT_EQUAL_STR(_unittest_result, "add", method->method_name, "method name should match");
|
||||||
|
UNITTEST_ASSERT_EQUAL_INT(_unittest_result, RAVA_NATIVE_INT, (int)method->return_type, "return type should be INT");
|
||||||
|
UNITTEST_ASSERT_EQUAL_INT(_unittest_result, 2, (int)method->param_count, "param count should be 2");
|
||||||
|
|
||||||
|
RavaNativeMethod_t *not_found = rava_native_find_method(registry, "Math", "subtract");
|
||||||
|
UNITTEST_ASSERT_NULL(_unittest_result, not_found, "non-existent method should return NULL");
|
||||||
|
|
||||||
|
rava_native_registry_destroy(registry);
|
||||||
|
|
||||||
|
UNITTEST_END_TEST();
|
||||||
|
}
|
||||||
|
|
||||||
|
UnittestTestResult_t* test_invoke_method(void) {
|
||||||
|
UNITTEST_BEGIN_TEST("TestLoader", "test_invoke_method");
|
||||||
|
|
||||||
|
RavaNativeRegistry_t *registry = rava_native_registry_create();
|
||||||
|
|
||||||
|
RavaNativeType_e params[] = {RAVA_NATIVE_INT, RAVA_NATIVE_INT};
|
||||||
|
rava_native_register_method(registry, "Math", "add",
|
||||||
|
RAVA_NATIVE_INT, params, 2,
|
||||||
|
test_add, NULL);
|
||||||
|
|
||||||
|
RavaNativeMethod_t *method = rava_native_find_method(registry, "Math", "add");
|
||||||
|
|
||||||
|
RavaNativeValue_t args[2];
|
||||||
|
args[0] = rava_native_int(10);
|
||||||
|
args[1] = rava_native_int(20);
|
||||||
|
|
||||||
|
RavaNativeValue_t result = rava_native_invoke(method, args, 2);
|
||||||
|
UNITTEST_ASSERT_EQUAL_INT(_unittest_result, RAVA_NATIVE_INT, (int)result.type, "result should be INT");
|
||||||
|
UNITTEST_ASSERT_EQUAL_INT(_unittest_result, 30, result.data.int_val, "10 + 20 = 30");
|
||||||
|
|
||||||
|
rava_native_registry_destroy(registry);
|
||||||
|
|
||||||
|
UNITTEST_END_TEST();
|
||||||
|
}
|
||||||
|
|
||||||
|
UnittestTestResult_t* test_multiple_methods(void) {
|
||||||
|
UNITTEST_BEGIN_TEST("TestLoader", "test_multiple_methods");
|
||||||
|
|
||||||
|
RavaNativeRegistry_t *registry = rava_native_registry_create();
|
||||||
|
|
||||||
|
RavaNativeType_e int_params[] = {RAVA_NATIVE_INT, RAVA_NATIVE_INT};
|
||||||
|
rava_native_register_method(registry, "Math", "add",
|
||||||
|
RAVA_NATIVE_INT, int_params, 2,
|
||||||
|
test_add, NULL);
|
||||||
|
rava_native_register_method(registry, "Math", "multiply",
|
||||||
|
RAVA_NATIVE_INT, int_params, 2,
|
||||||
|
test_multiply, NULL);
|
||||||
|
|
||||||
|
RavaNativeType_e string_params[] = {RAVA_NATIVE_STRING};
|
||||||
|
rava_native_register_method(registry, "Greeter", "greet",
|
||||||
|
RAVA_NATIVE_STRING, string_params, 1,
|
||||||
|
test_greet, NULL);
|
||||||
|
|
||||||
|
UNITTEST_ASSERT_EQUAL_INT(_unittest_result, 3, (int)registry->cache_count, "should have 3 methods");
|
||||||
|
|
||||||
|
RavaNativeMethod_t *add = rava_native_find_method(registry, "Math", "add");
|
||||||
|
RavaNativeMethod_t *mul = rava_native_find_method(registry, "Math", "multiply");
|
||||||
|
RavaNativeMethod_t *greet = rava_native_find_method(registry, "Greeter", "greet");
|
||||||
|
|
||||||
|
UNITTEST_ASSERT_NOT_NULL(_unittest_result, add, "add should exist");
|
||||||
|
UNITTEST_ASSERT_NOT_NULL(_unittest_result, mul, "multiply should exist");
|
||||||
|
UNITTEST_ASSERT_NOT_NULL(_unittest_result, greet, "greet should exist");
|
||||||
|
|
||||||
|
RavaNativeValue_t args[2];
|
||||||
|
args[0] = rava_native_int(5);
|
||||||
|
args[1] = rava_native_int(7);
|
||||||
|
|
||||||
|
RavaNativeValue_t add_result = rava_native_invoke(add, args, 2);
|
||||||
|
UNITTEST_ASSERT_EQUAL_INT(_unittest_result, 12, add_result.data.int_val, "5 + 7 = 12");
|
||||||
|
|
||||||
|
RavaNativeValue_t mul_result = rava_native_invoke(mul, args, 2);
|
||||||
|
UNITTEST_ASSERT_EQUAL_INT(_unittest_result, 35, mul_result.data.int_val, "5 * 7 = 35");
|
||||||
|
|
||||||
|
rava_native_registry_destroy(registry);
|
||||||
|
|
||||||
|
UNITTEST_END_TEST();
|
||||||
|
}
|
||||||
|
|
||||||
|
UnittestTestResult_t* test_value_conversion(void) {
|
||||||
|
UNITTEST_BEGIN_TEST("TestLoader", "test_value_conversion");
|
||||||
|
|
||||||
|
RavaValue_t int_val = rava_value_int(42);
|
||||||
|
RavaNativeValue_t native_int = rava_value_to_native(int_val);
|
||||||
|
UNITTEST_ASSERT_EQUAL_INT(_unittest_result, RAVA_NATIVE_INT, (int)native_int.type, "type should be INT");
|
||||||
|
UNITTEST_ASSERT_EQUAL_INT(_unittest_result, 42, native_int.data.int_val, "value should be 42");
|
||||||
|
|
||||||
|
RavaValue_t back_to_rava = rava_native_to_value(native_int);
|
||||||
|
UNITTEST_ASSERT_EQUAL_INT(_unittest_result, RAVA_VAL_INT, (int)back_to_rava.type, "type should be RAVA_VAL_INT");
|
||||||
|
UNITTEST_ASSERT_EQUAL_INT(_unittest_result, 42, back_to_rava.data.int_val, "value should be 42");
|
||||||
|
|
||||||
|
RavaValue_t long_val = rava_value_long(123456789012LL);
|
||||||
|
RavaNativeValue_t native_long = rava_value_to_native(long_val);
|
||||||
|
UNITTEST_ASSERT_EQUAL_INT(_unittest_result, RAVA_NATIVE_LONG, (int)native_long.type, "type should be LONG");
|
||||||
|
UNITTEST_ASSERT_EQUAL_LONG(_unittest_result, 123456789012LL, native_long.data.long_val, "long value should match");
|
||||||
|
|
||||||
|
RavaValue_t bool_val = rava_value_boolean(true);
|
||||||
|
RavaNativeValue_t native_bool = rava_value_to_native(bool_val);
|
||||||
|
UNITTEST_ASSERT_EQUAL_INT(_unittest_result, RAVA_NATIVE_BOOLEAN, (int)native_bool.type, "type should be BOOLEAN");
|
||||||
|
UNITTEST_ASSERT_TRUE(_unittest_result, native_bool.data.bool_val, "bool should be true");
|
||||||
|
|
||||||
|
UNITTEST_END_TEST();
|
||||||
|
}
|
||||||
|
|
||||||
|
UnittestTestResult_t* test_string_method(void) {
|
||||||
|
UNITTEST_BEGIN_TEST("TestLoader", "test_string_method");
|
||||||
|
|
||||||
|
RavaNativeRegistry_t *registry = rava_native_registry_create();
|
||||||
|
|
||||||
|
RavaNativeType_e string_params[] = {RAVA_NATIVE_STRING};
|
||||||
|
rava_native_register_method(registry, "Greeter", "greet",
|
||||||
|
RAVA_NATIVE_STRING, string_params, 1,
|
||||||
|
test_greet, NULL);
|
||||||
|
|
||||||
|
RavaNativeMethod_t *greet = rava_native_find_method(registry, "Greeter", "greet");
|
||||||
|
UNITTEST_ASSERT_NOT_NULL(_unittest_result, greet, "greet should exist");
|
||||||
|
|
||||||
|
RavaNativeValue_t args[1];
|
||||||
|
args[0] = rava_native_string("Rava");
|
||||||
|
|
||||||
|
RavaNativeValue_t result = rava_native_invoke(greet, args, 1);
|
||||||
|
UNITTEST_ASSERT_EQUAL_INT(_unittest_result, RAVA_NATIVE_STRING, (int)result.type, "result should be STRING");
|
||||||
|
UNITTEST_ASSERT_EQUAL_STR(_unittest_result, "Hello, Rava!", result.data.string_val, "greeting should match");
|
||||||
|
|
||||||
|
free(args[0].data.string_val);
|
||||||
|
free(result.data.string_val);
|
||||||
|
rava_native_registry_destroy(registry);
|
||||||
|
|
||||||
|
UNITTEST_END_TEST();
|
||||||
|
}
|
||||||
|
|
||||||
|
int main(int argc, char **argv) {
|
||||||
|
UnittestConfig_t *config = unittest_config_create();
|
||||||
|
config->verbosity = 2;
|
||||||
|
|
||||||
|
if (argc > 1 && strcmp(argv[1], "--json") == 0) {
|
||||||
|
config->output_format = UNITTEST_FORMAT_JSON;
|
||||||
|
config->use_colors = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
UnittestTestSuite_t *suite = unittest_test_suite_create("Dynamic Library Loader Tests");
|
||||||
|
|
||||||
|
UnittestTestCase_t *tc = unittest_test_case_create("TestLoader");
|
||||||
|
unittest_test_case_add_result(tc, test_registry_create_destroy());
|
||||||
|
unittest_test_case_add_result(tc, test_register_method());
|
||||||
|
unittest_test_case_add_result(tc, test_find_method());
|
||||||
|
unittest_test_case_add_result(tc, test_invoke_method());
|
||||||
|
unittest_test_case_add_result(tc, test_multiple_methods());
|
||||||
|
unittest_test_case_add_result(tc, test_value_conversion());
|
||||||
|
unittest_test_case_add_result(tc, test_string_method());
|
||||||
|
unittest_test_suite_add_test_case(suite, tc);
|
||||||
|
|
||||||
|
unittest_generate_report(suite, config);
|
||||||
|
|
||||||
|
int failures = suite->total_failed + suite->total_errors;
|
||||||
|
unittest_test_suite_destroy(suite);
|
||||||
|
unittest_config_destroy(config);
|
||||||
|
|
||||||
|
return failures > 0 ? 1 : 0;
|
||||||
|
}
|
||||||
Binary file not shown.
81
tests/test_method_ref.c
Normal file
81
tests/test_method_ref.c
Normal file
@ -0,0 +1,81 @@
|
|||||||
|
#include "test_utils.h"
|
||||||
|
|
||||||
|
UnittestTestResult_t* test_method_ref_parse_static(void) {
|
||||||
|
UNITTEST_BEGIN_TEST("TestMethodRef", "test_method_ref_parse_static");
|
||||||
|
|
||||||
|
const char *source =
|
||||||
|
"public class Test {\n"
|
||||||
|
" public static int getValue() {\n"
|
||||||
|
" return 42;\n"
|
||||||
|
" }\n"
|
||||||
|
" public static int main() {\n"
|
||||||
|
" return Test.getValue();\n"
|
||||||
|
" }\n"
|
||||||
|
"}\n";
|
||||||
|
|
||||||
|
RAVA_TEST_PARSER_OK(_unittest_result, source, "Parser should handle static method call");
|
||||||
|
|
||||||
|
UNITTEST_END_TEST();
|
||||||
|
}
|
||||||
|
|
||||||
|
UnittestTestResult_t* test_method_ref_syntax(void) {
|
||||||
|
UNITTEST_BEGIN_TEST("TestMethodRef", "test_method_ref_syntax");
|
||||||
|
|
||||||
|
const char *source =
|
||||||
|
"public class Test {\n"
|
||||||
|
" public static int helper(int x) {\n"
|
||||||
|
" return x * 2;\n"
|
||||||
|
" }\n"
|
||||||
|
" public static int main() {\n"
|
||||||
|
" return helper(21);\n"
|
||||||
|
" }\n"
|
||||||
|
"}\n";
|
||||||
|
|
||||||
|
RAVA_TEST_RUN(_unittest_result, source, "Test", "main", 42, "Should execute helper method");
|
||||||
|
|
||||||
|
UNITTEST_END_TEST();
|
||||||
|
}
|
||||||
|
|
||||||
|
UnittestTestResult_t* test_method_ref_ir_generation(void) {
|
||||||
|
UNITTEST_BEGIN_TEST("TestMethodRef", "test_method_ref_ir_generation");
|
||||||
|
|
||||||
|
const char *source =
|
||||||
|
"public class Test {\n"
|
||||||
|
" public static int getValue() {\n"
|
||||||
|
" return 100;\n"
|
||||||
|
" }\n"
|
||||||
|
" public static int main() {\n"
|
||||||
|
" return getValue();\n"
|
||||||
|
" }\n"
|
||||||
|
"}\n";
|
||||||
|
|
||||||
|
RAVA_TEST_IR_OK(_unittest_result, source, "IR generation should succeed");
|
||||||
|
|
||||||
|
UNITTEST_END_TEST();
|
||||||
|
}
|
||||||
|
|
||||||
|
int main(int argc, char **argv) {
|
||||||
|
UnittestConfig_t *config = unittest_config_create();
|
||||||
|
config->verbosity = 2;
|
||||||
|
|
||||||
|
if (argc > 1 && strcmp(argv[1], "--json") == 0) {
|
||||||
|
config->output_format = UNITTEST_FORMAT_JSON;
|
||||||
|
config->use_colors = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
UnittestTestSuite_t *suite = unittest_test_suite_create("Method Reference Tests");
|
||||||
|
|
||||||
|
UnittestTestCase_t *tc = unittest_test_case_create("TestMethodRef");
|
||||||
|
unittest_test_case_add_result(tc, test_method_ref_parse_static());
|
||||||
|
unittest_test_case_add_result(tc, test_method_ref_syntax());
|
||||||
|
unittest_test_case_add_result(tc, test_method_ref_ir_generation());
|
||||||
|
unittest_test_suite_add_test_case(suite, tc);
|
||||||
|
|
||||||
|
unittest_generate_report(suite, config);
|
||||||
|
|
||||||
|
int failures = suite->total_failed + suite->total_errors;
|
||||||
|
unittest_test_suite_destroy(suite);
|
||||||
|
unittest_config_destroy(config);
|
||||||
|
|
||||||
|
return failures > 0 ? 1 : 0;
|
||||||
|
}
|
||||||
@ -1,26 +1,21 @@
|
|||||||
#include <stdio.h>
|
#include "test_utils.h"
|
||||||
#include <assert.h>
|
|
||||||
#include "../runtime/methodcache.h"
|
#include "../runtime/methodcache.h"
|
||||||
|
|
||||||
static int tests_passed = 0;
|
UnittestTestResult_t* test_create_destroy(void) {
|
||||||
|
UNITTEST_BEGIN_TEST("TestMethodCache", "test_create_destroy");
|
||||||
|
|
||||||
#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();
|
MethodCache_t* cache = rava_methodcache_create();
|
||||||
assert(cache != NULL);
|
UNITTEST_ASSERT_NOT_NULL(_unittest_result, cache, "cache should not be NULL");
|
||||||
rava_methodcache_destroy(cache);
|
rava_methodcache_destroy(cache);
|
||||||
|
|
||||||
|
UNITTEST_END_TEST();
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST(insert_lookup) {
|
UnittestTestResult_t* test_insert_lookup(void) {
|
||||||
|
UNITTEST_BEGIN_TEST("TestMethodCache", "test_insert_lookup");
|
||||||
|
|
||||||
MethodCache_t* cache = rava_methodcache_create();
|
MethodCache_t* cache = rava_methodcache_create();
|
||||||
assert(cache != NULL);
|
UNITTEST_ASSERT_NOT_NULL(_unittest_result, cache, "cache should not be NULL");
|
||||||
|
|
||||||
int dummy_method = 42;
|
int dummy_method = 42;
|
||||||
RavaMethod_t* method = (RavaMethod_t*)&dummy_method;
|
RavaMethod_t* method = (RavaMethod_t*)&dummy_method;
|
||||||
@ -28,24 +23,32 @@ TEST(insert_lookup) {
|
|||||||
rava_methodcache_insert(cache, "TestClass", "testMethod", method);
|
rava_methodcache_insert(cache, "TestClass", "testMethod", method);
|
||||||
|
|
||||||
RavaMethod_t* found = rava_methodcache_lookup(cache, "TestClass", "testMethod");
|
RavaMethod_t* found = rava_methodcache_lookup(cache, "TestClass", "testMethod");
|
||||||
assert(found == method);
|
UNITTEST_ASSERT_TRUE(_unittest_result, found == method, "found method should match inserted");
|
||||||
|
|
||||||
rava_methodcache_destroy(cache);
|
rava_methodcache_destroy(cache);
|
||||||
|
|
||||||
|
UNITTEST_END_TEST();
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST(lookup_miss) {
|
UnittestTestResult_t* test_lookup_miss(void) {
|
||||||
|
UNITTEST_BEGIN_TEST("TestMethodCache", "test_lookup_miss");
|
||||||
|
|
||||||
MethodCache_t* cache = rava_methodcache_create();
|
MethodCache_t* cache = rava_methodcache_create();
|
||||||
assert(cache != NULL);
|
UNITTEST_ASSERT_NOT_NULL(_unittest_result, cache, "cache should not be NULL");
|
||||||
|
|
||||||
RavaMethod_t* found = rava_methodcache_lookup(cache, "NonExistent", "method");
|
RavaMethod_t* found = rava_methodcache_lookup(cache, "NonExistent", "method");
|
||||||
assert(found == NULL);
|
UNITTEST_ASSERT_NULL(_unittest_result, found, "lookup miss should return NULL");
|
||||||
|
|
||||||
rava_methodcache_destroy(cache);
|
rava_methodcache_destroy(cache);
|
||||||
|
|
||||||
|
UNITTEST_END_TEST();
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST(multiple_methods) {
|
UnittestTestResult_t* test_multiple_methods(void) {
|
||||||
|
UNITTEST_BEGIN_TEST("TestMethodCache", "test_multiple_methods");
|
||||||
|
|
||||||
MethodCache_t* cache = rava_methodcache_create();
|
MethodCache_t* cache = rava_methodcache_create();
|
||||||
assert(cache != NULL);
|
UNITTEST_ASSERT_NOT_NULL(_unittest_result, cache, "cache should not be NULL");
|
||||||
|
|
||||||
int m1 = 1, m2 = 2;
|
int m1 = 1, m2 = 2;
|
||||||
RavaMethod_t* method1 = (RavaMethod_t*)&m1;
|
RavaMethod_t* method1 = (RavaMethod_t*)&m1;
|
||||||
@ -53,67 +56,96 @@ TEST(multiple_methods) {
|
|||||||
|
|
||||||
rava_methodcache_insert(cache, "TestClass", "methodA", method1);
|
rava_methodcache_insert(cache, "TestClass", "methodA", method1);
|
||||||
RavaMethod_t* found1 = rava_methodcache_lookup(cache, "TestClass", "methodA");
|
RavaMethod_t* found1 = rava_methodcache_lookup(cache, "TestClass", "methodA");
|
||||||
assert(found1 == method1);
|
UNITTEST_ASSERT_TRUE(_unittest_result, found1 == method1, "found1 should match method1");
|
||||||
|
|
||||||
rava_methodcache_insert(cache, "OtherClass", "methodB", method2);
|
rava_methodcache_insert(cache, "OtherClass", "methodB", method2);
|
||||||
RavaMethod_t* found2 = rava_methodcache_lookup(cache, "OtherClass", "methodB");
|
RavaMethod_t* found2 = rava_methodcache_lookup(cache, "OtherClass", "methodB");
|
||||||
assert(found2 == method2);
|
UNITTEST_ASSERT_TRUE(_unittest_result, found2 == method2, "found2 should match method2");
|
||||||
|
|
||||||
rava_methodcache_destroy(cache);
|
rava_methodcache_destroy(cache);
|
||||||
|
|
||||||
|
UNITTEST_END_TEST();
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST(clear) {
|
UnittestTestResult_t* test_clear(void) {
|
||||||
|
UNITTEST_BEGIN_TEST("TestMethodCache", "test_clear");
|
||||||
|
|
||||||
MethodCache_t* cache = rava_methodcache_create();
|
MethodCache_t* cache = rava_methodcache_create();
|
||||||
assert(cache != NULL);
|
UNITTEST_ASSERT_NOT_NULL(_unittest_result, cache, "cache should not be NULL");
|
||||||
|
|
||||||
int dummy = 42;
|
int dummy = 42;
|
||||||
RavaMethod_t* method = (RavaMethod_t*)&dummy;
|
RavaMethod_t* method = (RavaMethod_t*)&dummy;
|
||||||
|
|
||||||
rava_methodcache_insert(cache, "TestClass", "testMethod", method);
|
rava_methodcache_insert(cache, "TestClass", "testMethod", method);
|
||||||
assert(rava_methodcache_lookup(cache, "TestClass", "testMethod") == method);
|
UNITTEST_ASSERT_TRUE(_unittest_result, rava_methodcache_lookup(cache, "TestClass", "testMethod") == method, "should find method before clear");
|
||||||
|
|
||||||
rava_methodcache_clear(cache);
|
rava_methodcache_clear(cache);
|
||||||
assert(rava_methodcache_lookup(cache, "TestClass", "testMethod") == NULL);
|
UNITTEST_ASSERT_NULL(_unittest_result, rava_methodcache_lookup(cache, "TestClass", "testMethod"), "should not find method after clear");
|
||||||
|
|
||||||
rava_methodcache_destroy(cache);
|
rava_methodcache_destroy(cache);
|
||||||
|
|
||||||
|
UNITTEST_END_TEST();
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST(null_params) {
|
UnittestTestResult_t* test_null_params(void) {
|
||||||
|
UNITTEST_BEGIN_TEST("TestMethodCache", "test_null_params");
|
||||||
|
|
||||||
MethodCache_t* cache = rava_methodcache_create();
|
MethodCache_t* cache = rava_methodcache_create();
|
||||||
|
|
||||||
rava_methodcache_insert(NULL, "Class", "method", NULL);
|
rava_methodcache_insert(NULL, "Class", "method", NULL);
|
||||||
rava_methodcache_insert(cache, NULL, "method", NULL);
|
rava_methodcache_insert(cache, NULL, "method", NULL);
|
||||||
rava_methodcache_insert(cache, "Class", NULL, NULL);
|
rava_methodcache_insert(cache, "Class", NULL, NULL);
|
||||||
|
|
||||||
assert(rava_methodcache_lookup(NULL, "Class", "method") == NULL);
|
UNITTEST_ASSERT_NULL(_unittest_result, rava_methodcache_lookup(NULL, "Class", "method"), "NULL cache should return NULL");
|
||||||
assert(rava_methodcache_lookup(cache, NULL, "method") == NULL);
|
UNITTEST_ASSERT_NULL(_unittest_result, rava_methodcache_lookup(cache, NULL, "method"), "NULL class should return NULL");
|
||||||
assert(rava_methodcache_lookup(cache, "Class", NULL) == NULL);
|
UNITTEST_ASSERT_NULL(_unittest_result, rava_methodcache_lookup(cache, "Class", NULL), "NULL method should return NULL");
|
||||||
|
|
||||||
rava_methodcache_destroy(cache);
|
rava_methodcache_destroy(cache);
|
||||||
|
|
||||||
|
UNITTEST_END_TEST();
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST(hash_function) {
|
UnittestTestResult_t* test_hash_function(void) {
|
||||||
|
UNITTEST_BEGIN_TEST("TestMethodCache", "test_hash_function");
|
||||||
|
|
||||||
uint32_t h1 = rava_methodcache_hash("hello");
|
uint32_t h1 = rava_methodcache_hash("hello");
|
||||||
uint32_t h2 = rava_methodcache_hash("hello");
|
uint32_t h2 = rava_methodcache_hash("hello");
|
||||||
uint32_t h3 = rava_methodcache_hash("world");
|
uint32_t h3 = rava_methodcache_hash("world");
|
||||||
|
|
||||||
assert(h1 == h2);
|
UNITTEST_ASSERT_EQUAL(_unittest_result, h1, h2, "same string should produce same hash");
|
||||||
assert(h1 != h3);
|
UNITTEST_ASSERT_TRUE(_unittest_result, h1 != h3, "different strings should produce different hashes");
|
||||||
assert(h1 != 0);
|
UNITTEST_ASSERT_TRUE(_unittest_result, h1 != 0, "hash should not be 0");
|
||||||
assert(h3 != 0);
|
UNITTEST_ASSERT_TRUE(_unittest_result, h3 != 0, "hash should not be 0");
|
||||||
|
|
||||||
|
UNITTEST_END_TEST();
|
||||||
}
|
}
|
||||||
|
|
||||||
int main(void) {
|
int main(int argc, char **argv) {
|
||||||
printf("=== Method Cache Unit Tests ===\n\n");
|
UnittestConfig_t *config = unittest_config_create();
|
||||||
|
config->verbosity = 2;
|
||||||
|
|
||||||
RUN_TEST(create_destroy);
|
if (argc > 1 && strcmp(argv[1], "--json") == 0) {
|
||||||
RUN_TEST(insert_lookup);
|
config->output_format = UNITTEST_FORMAT_JSON;
|
||||||
RUN_TEST(lookup_miss);
|
config->use_colors = false;
|
||||||
RUN_TEST(multiple_methods);
|
}
|
||||||
RUN_TEST(clear);
|
|
||||||
RUN_TEST(null_params);
|
UnittestTestSuite_t *suite = unittest_test_suite_create("Method Cache Tests");
|
||||||
RUN_TEST(hash_function);
|
|
||||||
|
UnittestTestCase_t *tc = unittest_test_case_create("TestMethodCache");
|
||||||
printf("\n=== Results: %d tests passed ===\n", tests_passed);
|
unittest_test_case_add_result(tc, test_create_destroy());
|
||||||
return 0;
|
unittest_test_case_add_result(tc, test_insert_lookup());
|
||||||
|
unittest_test_case_add_result(tc, test_lookup_miss());
|
||||||
|
unittest_test_case_add_result(tc, test_multiple_methods());
|
||||||
|
unittest_test_case_add_result(tc, test_clear());
|
||||||
|
unittest_test_case_add_result(tc, test_null_params());
|
||||||
|
unittest_test_case_add_result(tc, test_hash_function());
|
||||||
|
unittest_test_suite_add_test_case(suite, tc);
|
||||||
|
|
||||||
|
unittest_generate_report(suite, config);
|
||||||
|
|
||||||
|
int failures = suite->total_failed + suite->total_errors;
|
||||||
|
unittest_test_suite_destroy(suite);
|
||||||
|
unittest_config_destroy(config);
|
||||||
|
|
||||||
|
return failures > 0 ? 1 : 0;
|
||||||
}
|
}
|
||||||
|
|||||||
Binary file not shown.
@ -1,146 +1,211 @@
|
|||||||
#include <stdio.h>
|
#include "test_utils.h"
|
||||||
#include <assert.h>
|
|
||||||
#include <math.h>
|
#include <math.h>
|
||||||
#include "../runtime/nanbox.h"
|
#include "../runtime/nanbox.h"
|
||||||
|
|
||||||
static int tests_passed = 0;
|
UnittestTestResult_t* test_int_basic(void) {
|
||||||
static int tests_failed = 0;
|
UNITTEST_BEGIN_TEST("TestNanbox", "test_int_basic");
|
||||||
|
|
||||||
#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);
|
RavaNanboxValue_t val = rava_nanbox_int(42);
|
||||||
assert(rava_nanbox_is_int(val));
|
UNITTEST_ASSERT_TRUE(_unittest_result, rava_nanbox_is_int(val), "should be int");
|
||||||
assert(!rava_nanbox_is_bool(val));
|
UNITTEST_ASSERT_FALSE(_unittest_result, rava_nanbox_is_bool(val), "should not be bool");
|
||||||
assert(!rava_nanbox_is_null(val));
|
UNITTEST_ASSERT_FALSE(_unittest_result, rava_nanbox_is_null(val), "should not be null");
|
||||||
assert(rava_nanbox_as_int(val) == 42);
|
UNITTEST_ASSERT_EQUAL(_unittest_result, 42, rava_nanbox_as_int(val), "should equal 42");
|
||||||
|
|
||||||
|
UNITTEST_END_TEST();
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST(int_negative) {
|
UnittestTestResult_t* test_int_negative(void) {
|
||||||
|
UNITTEST_BEGIN_TEST("TestNanbox", "test_int_negative");
|
||||||
|
|
||||||
RavaNanboxValue_t val = rava_nanbox_int(-100);
|
RavaNanboxValue_t val = rava_nanbox_int(-100);
|
||||||
assert(rava_nanbox_is_int(val));
|
UNITTEST_ASSERT_TRUE(_unittest_result, rava_nanbox_is_int(val), "should be int");
|
||||||
assert(rava_nanbox_as_int(val) == -100);
|
UNITTEST_ASSERT_EQUAL(_unittest_result, -100, rava_nanbox_as_int(val), "should equal -100");
|
||||||
|
|
||||||
|
UNITTEST_END_TEST();
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST(int_zero) {
|
UnittestTestResult_t* test_int_zero(void) {
|
||||||
|
UNITTEST_BEGIN_TEST("TestNanbox", "test_int_zero");
|
||||||
|
|
||||||
RavaNanboxValue_t val = rava_nanbox_int(0);
|
RavaNanboxValue_t val = rava_nanbox_int(0);
|
||||||
assert(rava_nanbox_is_int(val));
|
UNITTEST_ASSERT_TRUE(_unittest_result, rava_nanbox_is_int(val), "should be int");
|
||||||
assert(rava_nanbox_as_int(val) == 0);
|
UNITTEST_ASSERT_EQUAL(_unittest_result, 0, rava_nanbox_as_int(val), "should equal 0");
|
||||||
|
|
||||||
|
UNITTEST_END_TEST();
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST(long_basic) {
|
UnittestTestResult_t* test_long_basic(void) {
|
||||||
|
UNITTEST_BEGIN_TEST("TestNanbox", "test_long_basic");
|
||||||
|
|
||||||
RavaNanboxValue_t val = rava_nanbox_long(1000000000000LL);
|
RavaNanboxValue_t val = rava_nanbox_long(1000000000000LL);
|
||||||
assert(rava_nanbox_is_long(val));
|
UNITTEST_ASSERT_TRUE(_unittest_result, rava_nanbox_is_long(val), "should be long");
|
||||||
int64_t result = rava_nanbox_as_long(val);
|
|
||||||
(void)result;
|
UNITTEST_END_TEST();
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST(bool_true) {
|
UnittestTestResult_t* test_bool_true(void) {
|
||||||
|
UNITTEST_BEGIN_TEST("TestNanbox", "test_bool_true");
|
||||||
|
|
||||||
RavaNanboxValue_t val = rava_nanbox_bool(true);
|
RavaNanboxValue_t val = rava_nanbox_bool(true);
|
||||||
assert(rava_nanbox_is_bool(val));
|
UNITTEST_ASSERT_TRUE(_unittest_result, rava_nanbox_is_bool(val), "should be bool");
|
||||||
assert(rava_nanbox_as_bool(val) == true);
|
UNITTEST_ASSERT_TRUE(_unittest_result, rava_nanbox_as_bool(val), "should be true");
|
||||||
|
|
||||||
|
UNITTEST_END_TEST();
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST(bool_false) {
|
UnittestTestResult_t* test_bool_false(void) {
|
||||||
|
UNITTEST_BEGIN_TEST("TestNanbox", "test_bool_false");
|
||||||
|
|
||||||
RavaNanboxValue_t val = rava_nanbox_bool(false);
|
RavaNanboxValue_t val = rava_nanbox_bool(false);
|
||||||
assert(rava_nanbox_is_bool(val));
|
UNITTEST_ASSERT_TRUE(_unittest_result, rava_nanbox_is_bool(val), "should be bool");
|
||||||
assert(rava_nanbox_as_bool(val) == false);
|
UNITTEST_ASSERT_FALSE(_unittest_result, rava_nanbox_as_bool(val), "should be false");
|
||||||
|
|
||||||
|
UNITTEST_END_TEST();
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST(null) {
|
UnittestTestResult_t* test_null(void) {
|
||||||
|
UNITTEST_BEGIN_TEST("TestNanbox", "test_null");
|
||||||
|
|
||||||
RavaNanboxValue_t val = rava_nanbox_null();
|
RavaNanboxValue_t val = rava_nanbox_null();
|
||||||
assert(rava_nanbox_is_null(val));
|
UNITTEST_ASSERT_TRUE(_unittest_result, rava_nanbox_is_null(val), "should be null");
|
||||||
assert(!rava_nanbox_is_int(val));
|
UNITTEST_ASSERT_FALSE(_unittest_result, rava_nanbox_is_int(val), "should not be int");
|
||||||
assert(!rava_nanbox_is_bool(val));
|
UNITTEST_ASSERT_FALSE(_unittest_result, rava_nanbox_is_bool(val), "should not be bool");
|
||||||
|
|
||||||
|
UNITTEST_END_TEST();
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST(double_basic) {
|
UnittestTestResult_t* test_double_basic(void) {
|
||||||
|
UNITTEST_BEGIN_TEST("TestNanbox", "test_double_basic");
|
||||||
|
|
||||||
RavaNanboxValue_t val = rava_nanbox_double(3.14159);
|
RavaNanboxValue_t val = rava_nanbox_double(3.14159);
|
||||||
assert(rava_nanbox_is_double(val));
|
UNITTEST_ASSERT_TRUE(_unittest_result, rava_nanbox_is_double(val), "should be double");
|
||||||
double d = rava_nanbox_as_double(val);
|
double d = rava_nanbox_as_double(val);
|
||||||
assert(fabs(d - 3.14159) < 0.0001);
|
UNITTEST_ASSERT_TRUE(_unittest_result, fabs(d - 3.14159) < 0.0001, "should equal 3.14159");
|
||||||
|
|
||||||
|
UNITTEST_END_TEST();
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST(double_negative) {
|
UnittestTestResult_t* test_double_negative(void) {
|
||||||
|
UNITTEST_BEGIN_TEST("TestNanbox", "test_double_negative");
|
||||||
|
|
||||||
RavaNanboxValue_t val = rava_nanbox_double(-123.456);
|
RavaNanboxValue_t val = rava_nanbox_double(-123.456);
|
||||||
assert(rava_nanbox_is_double(val));
|
UNITTEST_ASSERT_TRUE(_unittest_result, rava_nanbox_is_double(val), "should be double");
|
||||||
double d = rava_nanbox_as_double(val);
|
double d = rava_nanbox_as_double(val);
|
||||||
assert(fabs(d - (-123.456)) < 0.0001);
|
UNITTEST_ASSERT_TRUE(_unittest_result, fabs(d - (-123.456)) < 0.0001, "should equal -123.456");
|
||||||
|
|
||||||
|
UNITTEST_END_TEST();
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST(conversion_int_to_long) {
|
UnittestTestResult_t* test_conversion_int_to_long(void) {
|
||||||
|
UNITTEST_BEGIN_TEST("TestNanbox", "test_conversion_int_to_long");
|
||||||
|
|
||||||
RavaNanboxValue_t val = rava_nanbox_int(42);
|
RavaNanboxValue_t val = rava_nanbox_int(42);
|
||||||
assert(rava_nanbox_to_long(val) == 42);
|
UNITTEST_ASSERT_EQUAL(_unittest_result, 42, (int)rava_nanbox_to_long(val), "int to long should equal 42");
|
||||||
|
|
||||||
|
UNITTEST_END_TEST();
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST(conversion_int_to_double) {
|
UnittestTestResult_t* test_conversion_int_to_double(void) {
|
||||||
|
UNITTEST_BEGIN_TEST("TestNanbox", "test_conversion_int_to_double");
|
||||||
|
|
||||||
RavaNanboxValue_t val = rava_nanbox_int(10);
|
RavaNanboxValue_t val = rava_nanbox_int(10);
|
||||||
assert(fabs(rava_nanbox_to_double(val) - 10.0) < 0.0001);
|
UNITTEST_ASSERT_TRUE(_unittest_result, fabs(rava_nanbox_to_double(val) - 10.0) < 0.0001, "int to double should equal 10.0");
|
||||||
|
|
||||||
|
UNITTEST_END_TEST();
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST(conversion_bool_to_int) {
|
UnittestTestResult_t* test_conversion_bool_to_int(void) {
|
||||||
|
UNITTEST_BEGIN_TEST("TestNanbox", "test_conversion_bool_to_int");
|
||||||
|
|
||||||
RavaNanboxValue_t t = rava_nanbox_bool(true);
|
RavaNanboxValue_t t = rava_nanbox_bool(true);
|
||||||
RavaNanboxValue_t f = rava_nanbox_bool(false);
|
RavaNanboxValue_t f = rava_nanbox_bool(false);
|
||||||
assert(rava_nanbox_to_int(t) == 1);
|
UNITTEST_ASSERT_EQUAL(_unittest_result, 1, rava_nanbox_to_int(t), "true to int should equal 1");
|
||||||
assert(rava_nanbox_to_int(f) == 0);
|
UNITTEST_ASSERT_EQUAL(_unittest_result, 0, rava_nanbox_to_int(f), "false to int should equal 0");
|
||||||
|
|
||||||
|
UNITTEST_END_TEST();
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST(to_bool) {
|
UnittestTestResult_t* test_to_bool(void) {
|
||||||
assert(rava_nanbox_to_bool(rava_nanbox_null()) == false);
|
UNITTEST_BEGIN_TEST("TestNanbox", "test_to_bool");
|
||||||
assert(rava_nanbox_to_bool(rava_nanbox_bool(true)) == true);
|
|
||||||
assert(rava_nanbox_to_bool(rava_nanbox_bool(false)) == false);
|
UNITTEST_ASSERT_FALSE(_unittest_result, rava_nanbox_to_bool(rava_nanbox_null()), "null to bool should be false");
|
||||||
assert(rava_nanbox_to_bool(rava_nanbox_int(0)) == false);
|
UNITTEST_ASSERT_TRUE(_unittest_result, rava_nanbox_to_bool(rava_nanbox_bool(true)), "true to bool should be true");
|
||||||
assert(rava_nanbox_to_bool(rava_nanbox_int(1)) == true);
|
UNITTEST_ASSERT_FALSE(_unittest_result, rava_nanbox_to_bool(rava_nanbox_bool(false)), "false to bool should be false");
|
||||||
assert(rava_nanbox_to_bool(rava_nanbox_int(-1)) == true);
|
UNITTEST_ASSERT_FALSE(_unittest_result, rava_nanbox_to_bool(rava_nanbox_int(0)), "0 to bool should be false");
|
||||||
|
UNITTEST_ASSERT_TRUE(_unittest_result, rava_nanbox_to_bool(rava_nanbox_int(1)), "1 to bool should be true");
|
||||||
|
UNITTEST_ASSERT_TRUE(_unittest_result, rava_nanbox_to_bool(rava_nanbox_int(-1)), "-1 to bool should be true");
|
||||||
|
|
||||||
|
UNITTEST_END_TEST();
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST(object_pointer) {
|
UnittestTestResult_t* test_object_pointer(void) {
|
||||||
|
UNITTEST_BEGIN_TEST("TestNanbox", "test_object_pointer");
|
||||||
|
|
||||||
int dummy = 42;
|
int dummy = 42;
|
||||||
RavaNanboxValue_t val = rava_nanbox_object(&dummy);
|
RavaNanboxValue_t val = rava_nanbox_object(&dummy);
|
||||||
assert(rava_nanbox_is_object(val));
|
UNITTEST_ASSERT_TRUE(_unittest_result, rava_nanbox_is_object(val), "should be object");
|
||||||
assert(rava_nanbox_as_object(val) == &dummy);
|
UNITTEST_ASSERT_TRUE(_unittest_result, rava_nanbox_as_object(val) == &dummy, "pointer should match");
|
||||||
|
|
||||||
|
UNITTEST_END_TEST();
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST(string_pointer) {
|
UnittestTestResult_t* test_string_pointer(void) {
|
||||||
|
UNITTEST_BEGIN_TEST("TestNanbox", "test_string_pointer");
|
||||||
|
|
||||||
const char* str = "hello";
|
const char* str = "hello";
|
||||||
RavaNanboxValue_t val = rava_nanbox_string(str);
|
RavaNanboxValue_t val = rava_nanbox_string(str);
|
||||||
assert(rava_nanbox_is_string(val));
|
UNITTEST_ASSERT_TRUE(_unittest_result, rava_nanbox_is_string(val), "should be string");
|
||||||
assert(rava_nanbox_as_string(val) == str);
|
UNITTEST_ASSERT_TRUE(_unittest_result, rava_nanbox_as_string(val) == str, "pointer should match");
|
||||||
|
|
||||||
|
UNITTEST_END_TEST();
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST(array_pointer) {
|
UnittestTestResult_t* test_array_pointer(void) {
|
||||||
|
UNITTEST_BEGIN_TEST("TestNanbox", "test_array_pointer");
|
||||||
|
|
||||||
int arr[10];
|
int arr[10];
|
||||||
RavaNanboxValue_t val = rava_nanbox_array(arr);
|
RavaNanboxValue_t val = rava_nanbox_array(arr);
|
||||||
assert(rava_nanbox_is_array(val));
|
UNITTEST_ASSERT_TRUE(_unittest_result, rava_nanbox_is_array(val), "should be array");
|
||||||
assert(rava_nanbox_as_array(val) == arr);
|
UNITTEST_ASSERT_TRUE(_unittest_result, rava_nanbox_as_array(val) == arr, "pointer should match");
|
||||||
|
|
||||||
|
UNITTEST_END_TEST();
|
||||||
}
|
}
|
||||||
|
|
||||||
int main(void) {
|
int main(int argc, char **argv) {
|
||||||
printf("=== NaN Boxing Unit Tests ===\n\n");
|
UnittestConfig_t *config = unittest_config_create();
|
||||||
|
config->verbosity = 2;
|
||||||
|
|
||||||
RUN_TEST(int_basic);
|
if (argc > 1 && strcmp(argv[1], "--json") == 0) {
|
||||||
RUN_TEST(int_negative);
|
config->output_format = UNITTEST_FORMAT_JSON;
|
||||||
RUN_TEST(int_zero);
|
config->use_colors = false;
|
||||||
RUN_TEST(long_basic);
|
}
|
||||||
RUN_TEST(bool_true);
|
|
||||||
RUN_TEST(bool_false);
|
UnittestTestSuite_t *suite = unittest_test_suite_create("NaN Boxing Tests");
|
||||||
RUN_TEST(null);
|
|
||||||
RUN_TEST(double_basic);
|
UnittestTestCase_t *tc = unittest_test_case_create("TestNanbox");
|
||||||
RUN_TEST(double_negative);
|
unittest_test_case_add_result(tc, test_int_basic());
|
||||||
RUN_TEST(conversion_int_to_long);
|
unittest_test_case_add_result(tc, test_int_negative());
|
||||||
RUN_TEST(conversion_int_to_double);
|
unittest_test_case_add_result(tc, test_int_zero());
|
||||||
RUN_TEST(conversion_bool_to_int);
|
unittest_test_case_add_result(tc, test_long_basic());
|
||||||
RUN_TEST(to_bool);
|
unittest_test_case_add_result(tc, test_bool_true());
|
||||||
RUN_TEST(object_pointer);
|
unittest_test_case_add_result(tc, test_bool_false());
|
||||||
RUN_TEST(string_pointer);
|
unittest_test_case_add_result(tc, test_null());
|
||||||
RUN_TEST(array_pointer);
|
unittest_test_case_add_result(tc, test_double_basic());
|
||||||
|
unittest_test_case_add_result(tc, test_double_negative());
|
||||||
printf("\n=== Results: %d passed, %d failed ===\n", tests_passed, tests_failed);
|
unittest_test_case_add_result(tc, test_conversion_int_to_long());
|
||||||
return tests_failed > 0 ? 1 : 0;
|
unittest_test_case_add_result(tc, test_conversion_int_to_double());
|
||||||
|
unittest_test_case_add_result(tc, test_conversion_bool_to_int());
|
||||||
|
unittest_test_case_add_result(tc, test_to_bool());
|
||||||
|
unittest_test_case_add_result(tc, test_object_pointer());
|
||||||
|
unittest_test_case_add_result(tc, test_string_pointer());
|
||||||
|
unittest_test_case_add_result(tc, test_array_pointer());
|
||||||
|
unittest_test_suite_add_test_case(suite, tc);
|
||||||
|
|
||||||
|
unittest_generate_report(suite, config);
|
||||||
|
|
||||||
|
int failures = suite->total_failed + suite->total_errors;
|
||||||
|
unittest_test_suite_destroy(suite);
|
||||||
|
unittest_config_destroy(config);
|
||||||
|
|
||||||
|
return failures > 0 ? 1 : 0;
|
||||||
}
|
}
|
||||||
|
|||||||
163
tests/test_object_methods.c
Normal file
163
tests/test_object_methods.c
Normal file
@ -0,0 +1,163 @@
|
|||||||
|
#include "test_utils.h"
|
||||||
|
|
||||||
|
UnittestTestResult_t* test_hashcode_int(void) {
|
||||||
|
UNITTEST_BEGIN_TEST("TestObjectMethods", "test_hashcode_int");
|
||||||
|
|
||||||
|
RAVA_TEST_RUN(_unittest_result,
|
||||||
|
"public class Test {\n"
|
||||||
|
" public static int main() {\n"
|
||||||
|
" int x = 42;\n"
|
||||||
|
" return x.hashCode();\n"
|
||||||
|
" }\n"
|
||||||
|
"}\n",
|
||||||
|
"Test", "main", 42, "int.hashCode() should return the int value");
|
||||||
|
|
||||||
|
UNITTEST_END_TEST();
|
||||||
|
}
|
||||||
|
|
||||||
|
UnittestTestResult_t* test_hashcode_string(void) {
|
||||||
|
UNITTEST_BEGIN_TEST("TestObjectMethods", "test_hashcode_string");
|
||||||
|
|
||||||
|
RAVA_TEST_RUN(_unittest_result,
|
||||||
|
"public class Test {\n"
|
||||||
|
" public static int main() {\n"
|
||||||
|
" String s = \"hello\";\n"
|
||||||
|
" int h = s.hashCode();\n"
|
||||||
|
" return h != 0 ? 1 : 0;\n"
|
||||||
|
" }\n"
|
||||||
|
"}\n",
|
||||||
|
"Test", "main", 1, "String.hashCode() should return non-zero for non-empty string");
|
||||||
|
|
||||||
|
UNITTEST_END_TEST();
|
||||||
|
}
|
||||||
|
|
||||||
|
UnittestTestResult_t* test_equals_strings(void) {
|
||||||
|
UNITTEST_BEGIN_TEST("TestObjectMethods", "test_equals_strings");
|
||||||
|
|
||||||
|
RAVA_TEST_RUN(_unittest_result,
|
||||||
|
"public class Test {\n"
|
||||||
|
" public static int main() {\n"
|
||||||
|
" String a = \"hello\";\n"
|
||||||
|
" String b = \"hello\";\n"
|
||||||
|
" return a.equals(b) ? 1 : 0;\n"
|
||||||
|
" }\n"
|
||||||
|
"}\n",
|
||||||
|
"Test", "main", 1, "String.equals() should return true for equal strings");
|
||||||
|
|
||||||
|
UNITTEST_END_TEST();
|
||||||
|
}
|
||||||
|
|
||||||
|
UnittestTestResult_t* test_equals_different_strings(void) {
|
||||||
|
UNITTEST_BEGIN_TEST("TestObjectMethods", "test_equals_different_strings");
|
||||||
|
|
||||||
|
RAVA_TEST_RUN(_unittest_result,
|
||||||
|
"public class Test {\n"
|
||||||
|
" public static int main() {\n"
|
||||||
|
" String a = \"hello\";\n"
|
||||||
|
" String b = \"world\";\n"
|
||||||
|
" return a.equals(b) ? 1 : 0;\n"
|
||||||
|
" }\n"
|
||||||
|
"}\n",
|
||||||
|
"Test", "main", 0, "String.equals() should return false for different strings");
|
||||||
|
|
||||||
|
UNITTEST_END_TEST();
|
||||||
|
}
|
||||||
|
|
||||||
|
UnittestTestResult_t* test_tostring_int(void) {
|
||||||
|
UNITTEST_BEGIN_TEST("TestObjectMethods", "test_tostring_int");
|
||||||
|
|
||||||
|
RAVA_TEST_RUN(_unittest_result,
|
||||||
|
"public class Test {\n"
|
||||||
|
" public static int main() {\n"
|
||||||
|
" int x = 42;\n"
|
||||||
|
" return x.toString().equals(\"42\") ? 1 : 0;\n"
|
||||||
|
" }\n"
|
||||||
|
"}\n",
|
||||||
|
"Test", "main", 1, "int.toString() should return correct string");
|
||||||
|
|
||||||
|
UNITTEST_END_TEST();
|
||||||
|
}
|
||||||
|
|
||||||
|
UnittestTestResult_t* test_getclass_string(void) {
|
||||||
|
UNITTEST_BEGIN_TEST("TestObjectMethods", "test_getclass_string");
|
||||||
|
|
||||||
|
RAVA_TEST_RUN(_unittest_result,
|
||||||
|
"public class Test {\n"
|
||||||
|
" public static int main() {\n"
|
||||||
|
" String s = \"hello\";\n"
|
||||||
|
" return s.getClass().equals(\"String\") ? 1 : 0;\n"
|
||||||
|
" }\n"
|
||||||
|
"}\n",
|
||||||
|
"Test", "main", 1, "String.getClass() should return \"String\"");
|
||||||
|
|
||||||
|
UNITTEST_END_TEST();
|
||||||
|
}
|
||||||
|
|
||||||
|
UnittestTestResult_t* test_object_equals_same(void) {
|
||||||
|
UNITTEST_BEGIN_TEST("TestObjectMethods", "test_object_equals_same");
|
||||||
|
|
||||||
|
RAVA_TEST_RUN(_unittest_result,
|
||||||
|
"public class Obj {\n"
|
||||||
|
" public int x;\n"
|
||||||
|
"}\n"
|
||||||
|
"public class Test {\n"
|
||||||
|
" public static int main() {\n"
|
||||||
|
" Obj a = new Obj();\n"
|
||||||
|
" a.x = 10;\n"
|
||||||
|
" return a.equals(a) ? 1 : 0;\n"
|
||||||
|
" }\n"
|
||||||
|
"}\n",
|
||||||
|
"Test", "main", 1, "Object.equals() should return true for same reference");
|
||||||
|
|
||||||
|
UNITTEST_END_TEST();
|
||||||
|
}
|
||||||
|
|
||||||
|
UnittestTestResult_t* test_object_equals_different(void) {
|
||||||
|
UNITTEST_BEGIN_TEST("TestObjectMethods", "test_object_equals_different");
|
||||||
|
|
||||||
|
RAVA_TEST_RUN(_unittest_result,
|
||||||
|
"public class Obj {\n"
|
||||||
|
" public int x;\n"
|
||||||
|
"}\n"
|
||||||
|
"public class Test {\n"
|
||||||
|
" public static int main() {\n"
|
||||||
|
" Obj a = new Obj();\n"
|
||||||
|
" Obj b = new Obj();\n"
|
||||||
|
" return a.equals(b) ? 1 : 0;\n"
|
||||||
|
" }\n"
|
||||||
|
"}\n",
|
||||||
|
"Test", "main", 0, "Object.equals() should return false for different references");
|
||||||
|
|
||||||
|
UNITTEST_END_TEST();
|
||||||
|
}
|
||||||
|
|
||||||
|
int main(int argc, char **argv) {
|
||||||
|
UnittestConfig_t *config = unittest_config_create();
|
||||||
|
config->verbosity = 2;
|
||||||
|
|
||||||
|
if (argc > 1 && strcmp(argv[1], "--json") == 0) {
|
||||||
|
config->output_format = UNITTEST_FORMAT_JSON;
|
||||||
|
config->use_colors = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
UnittestTestSuite_t *suite = unittest_test_suite_create("Object Methods Tests");
|
||||||
|
|
||||||
|
UnittestTestCase_t *tc = unittest_test_case_create("TestObjectMethods");
|
||||||
|
unittest_test_case_add_result(tc, test_hashcode_int());
|
||||||
|
unittest_test_case_add_result(tc, test_hashcode_string());
|
||||||
|
unittest_test_case_add_result(tc, test_equals_strings());
|
||||||
|
unittest_test_case_add_result(tc, test_equals_different_strings());
|
||||||
|
unittest_test_case_add_result(tc, test_tostring_int());
|
||||||
|
unittest_test_case_add_result(tc, test_getclass_string());
|
||||||
|
unittest_test_case_add_result(tc, test_object_equals_same());
|
||||||
|
unittest_test_case_add_result(tc, test_object_equals_different());
|
||||||
|
unittest_test_suite_add_test_case(suite, tc);
|
||||||
|
|
||||||
|
unittest_generate_report(suite, config);
|
||||||
|
|
||||||
|
int failures = suite->total_failed + suite->total_errors;
|
||||||
|
unittest_test_suite_destroy(suite);
|
||||||
|
unittest_config_destroy(config);
|
||||||
|
|
||||||
|
return failures > 0 ? 1 : 0;
|
||||||
|
}
|
||||||
Binary file not shown.
@ -1,72 +1,92 @@
|
|||||||
#include "../lexer/lexer.h"
|
#include "test_utils.h"
|
||||||
#include "../parser/parser.h"
|
|
||||||
#include "../semantic/semantic.h"
|
|
||||||
#include "../ir/ir.h"
|
|
||||||
#include "../ir/ir_gen.h"
|
|
||||||
#include "../runtime/runtime.h"
|
|
||||||
#include <stdio.h>
|
|
||||||
#include <stdlib.h>
|
|
||||||
|
|
||||||
int main() {
|
UnittestTestResult_t* test_println_int(void) {
|
||||||
const char *source =
|
UNITTEST_BEGIN_TEST("TestPrintln", "test_println_int");
|
||||||
|
|
||||||
|
RAVA_TEST_RUN(_unittest_result,
|
||||||
"public class Test {\n"
|
"public class Test {\n"
|
||||||
" public static int main() {\n"
|
" public static int main() {\n"
|
||||||
" System.out.println(42);\n"
|
" System.out.println(42);\n"
|
||||||
" System.out.println(100);\n"
|
" return 42;\n"
|
||||||
|
" }\n"
|
||||||
|
"}\n",
|
||||||
|
"Test", "main", 42, "println should execute and return value");
|
||||||
|
|
||||||
|
UNITTEST_END_TEST();
|
||||||
|
}
|
||||||
|
|
||||||
|
UnittestTestResult_t* test_println_expression(void) {
|
||||||
|
UNITTEST_BEGIN_TEST("TestPrintln", "test_println_expression");
|
||||||
|
|
||||||
|
RAVA_TEST_RUN(_unittest_result,
|
||||||
|
"public class Test {\n"
|
||||||
|
" public static int main() {\n"
|
||||||
" int x = 10;\n"
|
" int x = 10;\n"
|
||||||
" int y = 20;\n"
|
" int y = 20;\n"
|
||||||
" System.out.println(x + y);\n"
|
" System.out.println(x + y);\n"
|
||||||
" return 0;\n"
|
" return x + y;\n"
|
||||||
" }\n"
|
" }\n"
|
||||||
"}\n";
|
"}\n",
|
||||||
|
"Test", "main", 30, "println with expression should work");
|
||||||
|
|
||||||
printf("Source:\n%s\n", source);
|
UNITTEST_END_TEST();
|
||||||
|
|
||||||
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();
|
UnittestTestResult_t* test_println_multiple(void) {
|
||||||
if (!rava_semantic_analyze(analyzer, ast)) {
|
UNITTEST_BEGIN_TEST("TestPrintln", "test_println_multiple");
|
||||||
printf("Semantic error: %s\n", analyzer->error_message);
|
|
||||||
return 1;
|
RAVA_TEST_RUN(_unittest_result,
|
||||||
|
"public class Test {\n"
|
||||||
|
" public static int main() {\n"
|
||||||
|
" System.out.println(1);\n"
|
||||||
|
" System.out.println(2);\n"
|
||||||
|
" System.out.println(3);\n"
|
||||||
|
" return 6;\n"
|
||||||
|
" }\n"
|
||||||
|
"}\n",
|
||||||
|
"Test", "main", 6, "multiple println calls should work");
|
||||||
|
|
||||||
|
UNITTEST_END_TEST();
|
||||||
}
|
}
|
||||||
|
|
||||||
RavaIRGenerator_t *ir_gen = rava_ir_generator_create(analyzer);
|
UnittestTestResult_t* test_print_no_newline(void) {
|
||||||
RavaProgram_t *program = rava_ir_generate(ir_gen, ast);
|
UNITTEST_BEGIN_TEST("TestPrintln", "test_print_no_newline");
|
||||||
|
|
||||||
if (!program) {
|
RAVA_TEST_RUN(_unittest_result,
|
||||||
printf("IR generation failed\n");
|
"public class Test {\n"
|
||||||
return 1;
|
" public static int main() {\n"
|
||||||
|
" System.out.print(42);\n"
|
||||||
|
" return 42;\n"
|
||||||
|
" }\n"
|
||||||
|
"}\n",
|
||||||
|
"Test", "main", 42, "print without newline should work");
|
||||||
|
|
||||||
|
UNITTEST_END_TEST();
|
||||||
}
|
}
|
||||||
|
|
||||||
printf("\nGenerated IR:\n");
|
int main(int argc, char **argv) {
|
||||||
rava_ir_print(program);
|
UnittestConfig_t *config = unittest_config_create();
|
||||||
|
config->verbosity = 2;
|
||||||
|
|
||||||
RavaVM_t *vm = rava_vm_create(program);
|
if (argc > 1 && strcmp(argv[1], "--json") == 0) {
|
||||||
printf("\nExecuting Test.main()...\n");
|
config->output_format = UNITTEST_FORMAT_JSON;
|
||||||
printf("Output:\n");
|
config->use_colors = false;
|
||||||
|
|
||||||
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");
|
UnittestTestSuite_t *suite = unittest_test_suite_create("Print/Println Tests");
|
||||||
|
|
||||||
rava_vm_destroy(vm);
|
UnittestTestCase_t *tc = unittest_test_case_create("TestPrintln");
|
||||||
rava_program_destroy(program);
|
unittest_test_case_add_result(tc, test_println_int());
|
||||||
rava_ir_generator_destroy(ir_gen);
|
unittest_test_case_add_result(tc, test_println_expression());
|
||||||
rava_semantic_analyzer_destroy(analyzer);
|
unittest_test_case_add_result(tc, test_println_multiple());
|
||||||
rava_ast_node_destroy(ast);
|
unittest_test_case_add_result(tc, test_print_no_newline());
|
||||||
rava_parser_destroy(parser);
|
unittest_test_suite_add_test_case(suite, tc);
|
||||||
rava_lexer_destroy(lexer);
|
|
||||||
|
|
||||||
return 0;
|
unittest_generate_report(suite, config);
|
||||||
|
|
||||||
|
int failures = suite->total_failed + suite->total_errors;
|
||||||
|
unittest_test_suite_destroy(suite);
|
||||||
|
unittest_config_destroy(config);
|
||||||
|
|
||||||
|
return failures > 0 ? 1 : 0;
|
||||||
}
|
}
|
||||||
|
|||||||
Binary file not shown.
Binary file not shown.
60
tests/test_sockets.c
Normal file
60
tests/test_sockets.c
Normal file
@ -0,0 +1,60 @@
|
|||||||
|
#include "test_utils.h"
|
||||||
|
|
||||||
|
UnittestTestResult_t* test_socket_create_server(void) {
|
||||||
|
UNITTEST_BEGIN_TEST("TestSockets", "test_socket_create_server");
|
||||||
|
|
||||||
|
RAVA_TEST_RUN(_unittest_result,
|
||||||
|
"public class Test {\n"
|
||||||
|
" public static int main() {\n"
|
||||||
|
" ServerSocket server = new ServerSocket(9999);\n"
|
||||||
|
" server.close();\n"
|
||||||
|
" return 1;\n"
|
||||||
|
" }\n"
|
||||||
|
"}\n",
|
||||||
|
"Test", "main", 1, "Should create and close ServerSocket");
|
||||||
|
|
||||||
|
UNITTEST_END_TEST();
|
||||||
|
}
|
||||||
|
|
||||||
|
UnittestTestResult_t* test_socket_create_multiple(void) {
|
||||||
|
UNITTEST_BEGIN_TEST("TestSockets", "test_socket_create_multiple");
|
||||||
|
|
||||||
|
RAVA_TEST_RUN(_unittest_result,
|
||||||
|
"public class Test {\n"
|
||||||
|
" public static int main() {\n"
|
||||||
|
" ServerSocket server1 = new ServerSocket(9997);\n"
|
||||||
|
" ServerSocket server2 = new ServerSocket(9996);\n"
|
||||||
|
" server1.close();\n"
|
||||||
|
" server2.close();\n"
|
||||||
|
" return 2;\n"
|
||||||
|
" }\n"
|
||||||
|
"}\n",
|
||||||
|
"Test", "main", 2, "Should create multiple ServerSockets");
|
||||||
|
|
||||||
|
UNITTEST_END_TEST();
|
||||||
|
}
|
||||||
|
|
||||||
|
int main(int argc, char **argv) {
|
||||||
|
UnittestConfig_t *config = unittest_config_create();
|
||||||
|
config->verbosity = 2;
|
||||||
|
|
||||||
|
if (argc > 1 && strcmp(argv[1], "--json") == 0) {
|
||||||
|
config->output_format = UNITTEST_FORMAT_JSON;
|
||||||
|
config->use_colors = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
UnittestTestSuite_t *suite = unittest_test_suite_create("Socket Tests");
|
||||||
|
|
||||||
|
UnittestTestCase_t *tc = unittest_test_case_create("TestSockets");
|
||||||
|
unittest_test_case_add_result(tc, test_socket_create_server());
|
||||||
|
unittest_test_case_add_result(tc, test_socket_create_multiple());
|
||||||
|
unittest_test_suite_add_test_case(suite, tc);
|
||||||
|
|
||||||
|
unittest_generate_report(suite, config);
|
||||||
|
|
||||||
|
int failures = suite->total_failed + suite->total_errors;
|
||||||
|
unittest_test_suite_destroy(suite);
|
||||||
|
unittest_config_destroy(config);
|
||||||
|
|
||||||
|
return failures > 0 ? 1 : 0;
|
||||||
|
}
|
||||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
@ -168,6 +168,9 @@ void _unittest_format_tap(UnittestTestSuite_t *suite, UnittestConfig_t *config,
|
|||||||
|
|
||||||
double unittest_get_time_ms(void);
|
double unittest_get_time_ms(void);
|
||||||
|
|
||||||
|
#define UNITTEST_ASSERT_EQUAL(result, expected, actual, msg) \
|
||||||
|
unittest_assert_int_equal((result), (expected), (actual), (msg), __LINE__, __FILE__)
|
||||||
|
|
||||||
#define UNITTEST_ASSERT_EQUAL_INT(result, expected, actual, msg) \
|
#define UNITTEST_ASSERT_EQUAL_INT(result, expected, actual, msg) \
|
||||||
unittest_assert_int_equal((result), (expected), (actual), (msg), __LINE__, __FILE__)
|
unittest_assert_int_equal((result), (expected), (actual), (msg), __LINE__, __FILE__)
|
||||||
|
|
||||||
|
|||||||
@ -118,6 +118,27 @@ bool rava_type_is_reference(RavaType_t *type) {
|
|||||||
type->kind == RAVA_TYPE_NULL;
|
type->kind == RAVA_TYPE_NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static RavaTypeKind_e _get_wrapper_primitive(RavaType_t *type) {
|
||||||
|
if (type->kind != RAVA_TYPE_CLASS || !type->data.class_type.class_name) {
|
||||||
|
return RAVA_TYPE_UNKNOWN;
|
||||||
|
}
|
||||||
|
const char *name = type->data.class_type.class_name;
|
||||||
|
if (strcmp(name, "Integer") == 0) return RAVA_TYPE_INT;
|
||||||
|
if (strcmp(name, "Long") == 0) return RAVA_TYPE_LONG;
|
||||||
|
if (strcmp(name, "Double") == 0) return RAVA_TYPE_DOUBLE;
|
||||||
|
if (strcmp(name, "Float") == 0) return RAVA_TYPE_FLOAT;
|
||||||
|
if (strcmp(name, "Boolean") == 0) return RAVA_TYPE_BOOLEAN;
|
||||||
|
if (strcmp(name, "Character") == 0) return RAVA_TYPE_CHAR;
|
||||||
|
if (strcmp(name, "Byte") == 0) return RAVA_TYPE_BYTE;
|
||||||
|
if (strcmp(name, "Short") == 0) return RAVA_TYPE_SHORT;
|
||||||
|
return RAVA_TYPE_UNKNOWN;
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool _is_wrapper_for_primitive(RavaType_t *wrapper, RavaType_t *primitive) {
|
||||||
|
RavaTypeKind_e wk = _get_wrapper_primitive(wrapper);
|
||||||
|
return wk != RAVA_TYPE_UNKNOWN && wk == primitive->kind;
|
||||||
|
}
|
||||||
|
|
||||||
bool rava_type_equals(RavaType_t *a, RavaType_t *b) {
|
bool rava_type_equals(RavaType_t *a, RavaType_t *b) {
|
||||||
if (!a || !b) return false;
|
if (!a || !b) return false;
|
||||||
if (a->kind != b->kind) return false;
|
if (a->kind != b->kind) return false;
|
||||||
@ -149,6 +170,14 @@ bool rava_type_is_assignable_to(RavaType_t *from, RavaType_t *to) {
|
|||||||
return from_rank <= to_rank;
|
return from_rank <= to_rank;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (rava_type_is_primitive(from) && _is_wrapper_for_primitive(to, from)) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (rava_type_is_primitive(to) && _is_wrapper_for_primitive(from, to)) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user