From de48b1e64c5c6359ed7d96b40dec806d60d2c391 Mon Sep 17 00:00:00 2001 From: retoor Date: Tue, 2 Dec 2025 21:12:50 +0100 Subject: [PATCH] Update. --- Makefile | 91 ++- examples/21_DoWhile.java | 21 + ir/ir.h | 33 +- ir/ir_gen.c | 565 +++++++++++++++- parser/parser.h | 59 ++ parser/parser_declarations.c | 110 +++- parser/parser_expressions.c | 171 ++++- parser/parser_statements.c | 236 ++++++- runtime/runtime.c | 1179 +++++++++++++++++++++++++++++++++- runtime/runtime.h | 17 + semantic/semantic.c | 24 +- 11 files changed, 2435 insertions(+), 71 deletions(-) create mode 100644 examples/21_DoWhile.java diff --git a/Makefile b/Makefile index 60e05ac..8891eb1 100644 --- a/Makefile +++ b/Makefile @@ -1,6 +1,6 @@ CC = gcc CFLAGS = -Wall -Wextra -Werror -std=gnu99 -O3 -march=native -I. -LDFLAGS = -ldl +LDFLAGS = -ldl -lm LEXER_SOURCES = lexer/lexer_tokenizer.c lexer/lexer_keywords.c lexer/lexer_literals.c LEXER_OBJECTS = $(LEXER_SOURCES:.c=.o) @@ -53,7 +53,43 @@ TEST_INSTANCE_OBJECTS = $(TEST_INSTANCE_SOURCES:.c=.o) TEST_FILEIO_SOURCES = tests/test_fileio.c TEST_FILEIO_OBJECTS = $(TEST_FILEIO_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_SOURCES = tests/test_dowhile.c +TEST_DOWHILE_OBJECTS = $(TEST_DOWHILE_SOURCES:.c=.o) + +TEST_SWITCH_SOURCES = tests/test_switch.c +TEST_SWITCH_OBJECTS = $(TEST_SWITCH_SOURCES:.c=.o) + +TEST_MATH_SOURCES = tests/test_math.c +TEST_MATH_OBJECTS = $(TEST_MATH_SOURCES:.c=.o) + +TEST_STRING_METHODS_SOURCES = tests/test_string_methods.c +TEST_STRING_METHODS_OBJECTS = $(TEST_STRING_METHODS_SOURCES:.c=.o) + +TEST_STATIC_SOURCES = tests/test_static.c +TEST_STATIC_OBJECTS = $(TEST_STATIC_SOURCES:.c=.o) + +TEST_INTERFACES_SOURCES = tests/test_interfaces.c +TEST_INTERFACES_OBJECTS = $(TEST_INTERFACES_SOURCES:.c=.o) + +TEST_EXCEPTIONS_SOURCES = tests/test_exceptions.c +TEST_EXCEPTIONS_OBJECTS = $(TEST_EXCEPTIONS_SOURCES:.c=.o) + +TEST_TERNARY_SOURCES = tests/test_ternary.c +TEST_TERNARY_OBJECTS = $(TEST_TERNARY_SOURCES:.c=.o) + +TEST_BITWISE_SOURCES = tests/test_bitwise.c +TEST_BITWISE_OBJECTS = $(TEST_BITWISE_SOURCES:.c=.o) + +TEST_ENHANCED_FOR_SOURCES = tests/test_enhanced_for.c +TEST_ENHANCED_FOR_OBJECTS = $(TEST_ENHANCED_FOR_SOURCES:.c=.o) + +TEST_ARRAY_INIT_SOURCES = tests/test_array_init.c +TEST_ARRAY_INIT_OBJECTS = $(TEST_ARRAY_INIT_SOURCES:.c=.o) + +TEST_INSTANCEOF_SOURCES = tests/test_instanceof.c +TEST_INSTANCEOF_OBJECTS = $(TEST_INSTANCEOF_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_lexer: $(LEXER_OBJECTS) $(TEST_LEXER_OBJECTS) $(CC) $(CFLAGS) -o $@ $^ $(LDFLAGS) @@ -85,6 +121,42 @@ test_instance_methods: $(LEXER_OBJECTS) $(PARSER_OBJECTS) $(TYPES_OBJECTS) $(SEM test_fileio: $(LEXER_OBJECTS) $(PARSER_OBJECTS) $(TYPES_OBJECTS) $(SEMANTIC_OBJECTS) $(IR_OBJECTS) $(RUNTIME_OBJECTS) $(TEST_FILEIO_OBJECTS) $(CC) $(CFLAGS) -o $@ $^ $(LDFLAGS) +test_dowhile: $(LEXER_OBJECTS) $(PARSER_OBJECTS) $(TYPES_OBJECTS) $(SEMANTIC_OBJECTS) $(IR_OBJECTS) $(RUNTIME_OBJECTS) $(TEST_DOWHILE_OBJECTS) + $(CC) $(CFLAGS) -o $@ $^ $(LDFLAGS) + +test_switch: $(LEXER_OBJECTS) $(PARSER_OBJECTS) $(TYPES_OBJECTS) $(SEMANTIC_OBJECTS) $(IR_OBJECTS) $(RUNTIME_OBJECTS) $(TEST_SWITCH_OBJECTS) + $(CC) $(CFLAGS) -o $@ $^ $(LDFLAGS) + +test_math: $(LEXER_OBJECTS) $(PARSER_OBJECTS) $(TYPES_OBJECTS) $(SEMANTIC_OBJECTS) $(IR_OBJECTS) $(RUNTIME_OBJECTS) $(TEST_MATH_OBJECTS) + $(CC) $(CFLAGS) -o $@ $^ $(LDFLAGS) + +test_string_methods: $(LEXER_OBJECTS) $(PARSER_OBJECTS) $(TYPES_OBJECTS) $(SEMANTIC_OBJECTS) $(IR_OBJECTS) $(RUNTIME_OBJECTS) $(TEST_STRING_METHODS_OBJECTS) + $(CC) $(CFLAGS) -o $@ $^ $(LDFLAGS) + +test_static: $(LEXER_OBJECTS) $(PARSER_OBJECTS) $(TYPES_OBJECTS) $(SEMANTIC_OBJECTS) $(IR_OBJECTS) $(RUNTIME_OBJECTS) $(TEST_STATIC_OBJECTS) + $(CC) $(CFLAGS) -o $@ $^ $(LDFLAGS) + +test_interfaces: $(LEXER_OBJECTS) $(PARSER_OBJECTS) $(TYPES_OBJECTS) $(SEMANTIC_OBJECTS) $(IR_OBJECTS) $(RUNTIME_OBJECTS) $(TEST_INTERFACES_OBJECTS) + $(CC) $(CFLAGS) -o $@ $^ $(LDFLAGS) + +test_exceptions: $(LEXER_OBJECTS) $(PARSER_OBJECTS) $(TYPES_OBJECTS) $(SEMANTIC_OBJECTS) $(IR_OBJECTS) $(RUNTIME_OBJECTS) $(TEST_EXCEPTIONS_OBJECTS) + $(CC) $(CFLAGS) -o $@ $^ $(LDFLAGS) + +test_ternary: $(LEXER_OBJECTS) $(PARSER_OBJECTS) $(TYPES_OBJECTS) $(SEMANTIC_OBJECTS) $(IR_OBJECTS) $(RUNTIME_OBJECTS) $(TEST_TERNARY_OBJECTS) + $(CC) $(CFLAGS) -o $@ $^ $(LDFLAGS) + +test_bitwise: $(LEXER_OBJECTS) $(PARSER_OBJECTS) $(TYPES_OBJECTS) $(SEMANTIC_OBJECTS) $(IR_OBJECTS) $(RUNTIME_OBJECTS) $(TEST_BITWISE_OBJECTS) + $(CC) $(CFLAGS) -o $@ $^ $(LDFLAGS) + +test_enhanced_for: $(LEXER_OBJECTS) $(PARSER_OBJECTS) $(TYPES_OBJECTS) $(SEMANTIC_OBJECTS) $(IR_OBJECTS) $(RUNTIME_OBJECTS) $(TEST_ENHANCED_FOR_OBJECTS) + $(CC) $(CFLAGS) -o $@ $^ $(LDFLAGS) + +test_array_init: $(LEXER_OBJECTS) $(PARSER_OBJECTS) $(TYPES_OBJECTS) $(SEMANTIC_OBJECTS) $(IR_OBJECTS) $(RUNTIME_OBJECTS) $(TEST_ARRAY_INIT_OBJECTS) + $(CC) $(CFLAGS) -o $@ $^ $(LDFLAGS) + +test_instanceof: $(LEXER_OBJECTS) $(PARSER_OBJECTS) $(TYPES_OBJECTS) $(SEMANTIC_OBJECTS) $(IR_OBJECTS) $(RUNTIME_OBJECTS) $(TEST_INSTANCEOF_OBJECTS) + $(CC) $(CFLAGS) -o $@ $^ $(LDFLAGS) + %.o: %.c $(CC) $(CFLAGS) -c $< -o $@ @@ -150,8 +222,17 @@ clean: $(PHASE0_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_BENCHMARK_OBJECTS) \ - test_lexer test_parser test_semantic test_ir test_runtime test_strings test_arrays test_objects test_instance_methods test_fileio test_benchmark \ + $(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_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_benchmark \ test_nanbox test_fastframe test_labeltable test_methodcache test_benchmark_pgo *.gcda */*.gcda -.PHONY: all clean benchmark test_phase0 pgo test_benchmark_pgo_gen pgo_run test_benchmark_pgo +.PHONY: all clean benchmark test_phase0 pgo test_benchmark_pgo_gen pgo_run test_benchmark_pgo test + +test: all + @echo "=== Running All Tests ===" + @./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 && \ + echo "" && echo "=== All Tests Passed ===" diff --git a/examples/21_DoWhile.java b/examples/21_DoWhile.java new file mode 100644 index 0000000..bd4388e --- /dev/null +++ b/examples/21_DoWhile.java @@ -0,0 +1,21 @@ +public class DoWhile { + public static int main() { + int i = 0; + int sum = 0; + + do { + sum = sum + i; + i = i + 1; + } while (i < 5); + + System.out.println(sum); + + int j = 10; + do { + System.out.println(j); + j = j - 1; + } while (j > 7); + + return 0; + } +} diff --git a/ir/ir.h b/ir/ir.h index 174ac9d..409d958 100644 --- a/ir/ir.h +++ b/ir/ir.h @@ -53,6 +53,7 @@ typedef enum { RAVA_OP_CALL, RAVA_OP_CALL_STATIC, RAVA_OP_CALL_VIRTUAL, + RAVA_OP_CALL_SUPER, RAVA_OP_CALL_NATIVE, RAVA_OP_RETURN, RAVA_OP_RETURN_VOID, @@ -67,6 +68,8 @@ typedef enum { RAVA_OP_INSTANCEOF, RAVA_OP_THROW, + RAVA_OP_TRY_BEGIN, + RAVA_OP_TRY_END, RAVA_OP_POP, RAVA_OP_DUP, @@ -78,6 +81,13 @@ typedef enum { RAVA_OP_STRING_SUBSTRING, RAVA_OP_STRING_EQUALS, RAVA_OP_STRING_COMPARETO, + RAVA_OP_STRING_INDEXOF, + RAVA_OP_STRING_CONTAINS, + RAVA_OP_STRING_STARTSWITH, + RAVA_OP_STRING_ENDSWITH, + RAVA_OP_STRING_TOLOWERCASE, + RAVA_OP_STRING_TOUPPERCASE, + RAVA_OP_STRING_TRIM, RAVA_OP_LOAD_THIS, @@ -96,7 +106,22 @@ typedef enum { RAVA_OP_LOAD_LOCAL_CONST_LE_JUMPFALSE, RAVA_OP_LOAD_TWO_LOCALS, RAVA_OP_ADD_LOCAL_TO_LOCAL, - RAVA_OP_LOAD_LOCAL_LT_LOCAL_JUMPFALSE + RAVA_OP_LOAD_LOCAL_LT_LOCAL_JUMPFALSE, + + RAVA_OP_MATH_ABS, + RAVA_OP_MATH_SQRT, + RAVA_OP_MATH_POW, + RAVA_OP_MATH_MIN, + RAVA_OP_MATH_MAX, + RAVA_OP_MATH_FLOOR, + RAVA_OP_MATH_CEIL, + RAVA_OP_MATH_ROUND, + RAVA_OP_MATH_SIN, + RAVA_OP_MATH_COS, + RAVA_OP_MATH_TAN, + RAVA_OP_MATH_LOG, + RAVA_OP_MATH_EXP, + RAVA_OP_MATH_RANDOM } RavaOpCode_e; typedef union { @@ -135,6 +160,12 @@ typedef union { int local2; int label_id; } cmp_locals; + struct { + int catch_label; + int finally_label; + int end_label; + int exception_local; + } try_handler; } RavaOperand_u; typedef struct { diff --git a/ir/ir_gen.c b/ir/ir_gen.c index e829c21..9548a57 100644 --- a/ir/ir_gen.c +++ b/ir/ir_gen.c @@ -35,6 +35,15 @@ static int _rava_ir_find_local(RavaIRGenerator_t *gen, const char *name) { return -1; } +static bool _rava_ir_is_class_name(RavaIRGenerator_t *gen, const char *name) { + for (size_t i = 0; i < gen->program->class_count; i++) { + if (strcmp(gen->program->classes[i]->name, name) == 0) { + return true; + } + } + return false; +} + RavaIRGenerator_t* rava_ir_generator_create(RavaSemanticAnalyzer_t *analyzer) { RavaIRGenerator_t *gen = calloc(1, sizeof(RavaIRGenerator_t)); gen->program = rava_program_create(); @@ -82,6 +91,12 @@ static void _rava_ir_gen_binary_expr(RavaIRGenerator_t *gen, RavaASTNode_t *expr case RAVA_BINOP_GE: instr.opcode = RAVA_OP_GE; break; case RAVA_BINOP_AND: instr.opcode = RAVA_OP_AND; break; case RAVA_BINOP_OR: instr.opcode = RAVA_OP_OR; break; + case RAVA_BINOP_BITAND: instr.opcode = RAVA_OP_AND; break; + case RAVA_BINOP_BITOR: instr.opcode = RAVA_OP_OR; break; + case RAVA_BINOP_BITXOR: instr.opcode = RAVA_OP_XOR; break; + case RAVA_BINOP_LSHIFT: instr.opcode = RAVA_OP_SHL; break; + case RAVA_BINOP_RSHIFT: instr.opcode = RAVA_OP_SHR; break; + case RAVA_BINOP_URSHIFT: instr.opcode = RAVA_OP_USHR; break; default: instr.opcode = RAVA_OP_NOP; break; } @@ -190,6 +205,19 @@ static void _rava_ir_gen_expression(RavaIRGenerator_t *gen, RavaASTNode_t *expr) instr.opcode = RAVA_OP_STORE_ARRAY; _rava_ir_emit(gen, instr); } else if (expr->data.assign.target->type == RAVA_AST_MEMBER_ACCESS_EXPR) { + RavaASTNode_t *target_member = expr->data.assign.target; + if (target_member->data.member_access.object->type == RAVA_AST_IDENTIFIER_EXPR) { + const char *obj_name = target_member->data.member_access.object->data.identifier.name; + if (_rava_ir_is_class_name(gen, obj_name) || + strcmp(obj_name, gen->current_class->name) == 0) { + _rava_ir_gen_expression(gen, expr->data.assign.value); + instr.opcode = RAVA_OP_STORE_STATIC; + instr.operand.field.class_name = strdup(obj_name); + instr.operand.field.field_name = strdup(target_member->data.member_access.member); + _rava_ir_emit(gen, instr); + break; + } + } _rava_ir_gen_expression(gen, expr->data.assign.target->data.member_access.object); _rava_ir_gen_expression(gen, expr->data.assign.value); instr.opcode = RAVA_OP_PUT_FIELD; @@ -210,6 +238,17 @@ static void _rava_ir_gen_expression(RavaIRGenerator_t *gen, RavaASTNode_t *expr) break; case RAVA_AST_MEMBER_ACCESS_EXPR: + if (expr->data.member_access.object->type == RAVA_AST_IDENTIFIER_EXPR) { + const char *obj_name = expr->data.member_access.object->data.identifier.name; + if (_rava_ir_is_class_name(gen, obj_name) || + strcmp(obj_name, gen->current_class->name) == 0) { + instr.opcode = RAVA_OP_LOAD_STATIC; + instr.operand.field.class_name = strdup(obj_name); + instr.operand.field.field_name = strdup(expr->data.member_access.member); + _rava_ir_emit(gen, instr); + break; + } + } _rava_ir_gen_expression(gen, expr->data.member_access.object); instr.opcode = RAVA_OP_GET_FIELD; instr.operand.field.field_name = strdup(expr->data.member_access.member); @@ -251,13 +290,36 @@ static void _rava_ir_gen_expression(RavaIRGenerator_t *gen, RavaASTNode_t *expr) bool is_print = false; bool is_string_length = false; bool is_string_charat = false; + bool is_string_substring = false; bool is_string_equals = false; + bool is_string_compareto = false; + bool is_string_indexof = false; + bool is_string_contains = false; + bool is_string_startswith = false; + bool is_string_endswith = false; + bool is_string_tolowercase = false; + bool is_string_touppercase = false; + bool is_string_trim = false; bool is_file_read = false; bool is_file_write = false; bool is_file_exists = false; bool is_file_delete = false; bool is_current_time_millis = false; bool is_nano_time = false; + bool is_math_abs = false; + bool is_math_sqrt = false; + bool is_math_pow = false; + bool is_math_min = false; + bool is_math_max = false; + bool is_math_floor = false; + bool is_math_ceil = false; + bool is_math_round = false; + bool is_math_sin = false; + bool is_math_cos = false; + bool is_math_tan = false; + bool is_math_log = false; + bool is_math_exp = false; + bool is_math_random = false; RavaASTNode_t *string_object = NULL; if (expr->data.call.callee->type == RAVA_AST_MEMBER_ACCESS_EXPR) { @@ -294,6 +356,39 @@ static void _rava_ir_gen_expression(RavaIRGenerator_t *gen, RavaASTNode_t *expr) is_file_delete = true; } } + if (member->data.member_access.object->type == RAVA_AST_IDENTIFIER_EXPR && + strcmp(member->data.member_access.object->data.identifier.name, "Math") == 0) { + const char *method = member->data.member_access.member; + if (strcmp(method, "abs") == 0 && expr->data.call.arguments_count == 1) { + is_math_abs = true; + } else if (strcmp(method, "sqrt") == 0 && expr->data.call.arguments_count == 1) { + is_math_sqrt = true; + } else if (strcmp(method, "pow") == 0 && expr->data.call.arguments_count == 2) { + is_math_pow = true; + } else if (strcmp(method, "min") == 0 && expr->data.call.arguments_count == 2) { + is_math_min = true; + } else if (strcmp(method, "max") == 0 && expr->data.call.arguments_count == 2) { + is_math_max = true; + } else if (strcmp(method, "floor") == 0 && expr->data.call.arguments_count == 1) { + is_math_floor = true; + } else if (strcmp(method, "ceil") == 0 && expr->data.call.arguments_count == 1) { + is_math_ceil = true; + } else if (strcmp(method, "round") == 0 && expr->data.call.arguments_count == 1) { + is_math_round = true; + } else if (strcmp(method, "sin") == 0 && expr->data.call.arguments_count == 1) { + is_math_sin = true; + } else if (strcmp(method, "cos") == 0 && expr->data.call.arguments_count == 1) { + is_math_cos = true; + } else if (strcmp(method, "tan") == 0 && expr->data.call.arguments_count == 1) { + is_math_tan = true; + } else if (strcmp(method, "log") == 0 && expr->data.call.arguments_count == 1) { + is_math_log = true; + } else if (strcmp(method, "exp") == 0 && expr->data.call.arguments_count == 1) { + is_math_exp = true; + } else if (strcmp(method, "random") == 0 && expr->data.call.arguments_count == 0) { + is_math_random = true; + } + } if (strcmp(member->data.member_access.member, "length") == 0 && expr->data.call.arguments_count == 0) { is_string_length = true; string_object = member->data.member_access.object; @@ -303,6 +398,33 @@ static void _rava_ir_gen_expression(RavaIRGenerator_t *gen, RavaASTNode_t *expr) } else if (strcmp(member->data.member_access.member, "equals") == 0 && expr->data.call.arguments_count == 1) { is_string_equals = true; string_object = member->data.member_access.object; + } else if (strcmp(member->data.member_access.member, "substring") == 0 && expr->data.call.arguments_count == 2) { + is_string_substring = true; + string_object = member->data.member_access.object; + } else if (strcmp(member->data.member_access.member, "compareTo") == 0 && expr->data.call.arguments_count == 1) { + is_string_compareto = true; + string_object = member->data.member_access.object; + } else if (strcmp(member->data.member_access.member, "indexOf") == 0 && expr->data.call.arguments_count == 1) { + is_string_indexof = true; + string_object = member->data.member_access.object; + } else if (strcmp(member->data.member_access.member, "contains") == 0 && expr->data.call.arguments_count == 1) { + is_string_contains = true; + string_object = member->data.member_access.object; + } else if (strcmp(member->data.member_access.member, "startsWith") == 0 && expr->data.call.arguments_count == 1) { + is_string_startswith = true; + string_object = member->data.member_access.object; + } else if (strcmp(member->data.member_access.member, "endsWith") == 0 && expr->data.call.arguments_count == 1) { + is_string_endswith = true; + string_object = member->data.member_access.object; + } else if (strcmp(member->data.member_access.member, "toLowerCase") == 0 && expr->data.call.arguments_count == 0) { + is_string_tolowercase = true; + string_object = member->data.member_access.object; + } else if (strcmp(member->data.member_access.member, "toUpperCase") == 0 && expr->data.call.arguments_count == 0) { + is_string_touppercase = true; + string_object = member->data.member_access.object; + } else if (strcmp(member->data.member_access.member, "trim") == 0 && expr->data.call.arguments_count == 0) { + is_string_trim = true; + string_object = member->data.member_access.object; } } @@ -343,6 +465,107 @@ static void _rava_ir_gen_expression(RavaIRGenerator_t *gen, RavaASTNode_t *expr) _rava_ir_gen_expression(gen, expr->data.call.arguments[0]); instr.opcode = RAVA_OP_STRING_EQUALS; _rava_ir_emit(gen, instr); + } else if (is_string_substring) { + _rava_ir_gen_expression(gen, string_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_STRING_SUBSTRING; + _rava_ir_emit(gen, instr); + } else if (is_string_compareto) { + _rava_ir_gen_expression(gen, string_object); + _rava_ir_gen_expression(gen, expr->data.call.arguments[0]); + instr.opcode = RAVA_OP_STRING_COMPARETO; + _rava_ir_emit(gen, instr); + } else if (is_string_indexof) { + _rava_ir_gen_expression(gen, string_object); + _rava_ir_gen_expression(gen, expr->data.call.arguments[0]); + instr.opcode = RAVA_OP_STRING_INDEXOF; + _rava_ir_emit(gen, instr); + } else if (is_string_contains) { + _rava_ir_gen_expression(gen, string_object); + _rava_ir_gen_expression(gen, expr->data.call.arguments[0]); + instr.opcode = RAVA_OP_STRING_CONTAINS; + _rava_ir_emit(gen, instr); + } else if (is_string_startswith) { + _rava_ir_gen_expression(gen, string_object); + _rava_ir_gen_expression(gen, expr->data.call.arguments[0]); + instr.opcode = RAVA_OP_STRING_STARTSWITH; + _rava_ir_emit(gen, instr); + } else if (is_string_endswith) { + _rava_ir_gen_expression(gen, string_object); + _rava_ir_gen_expression(gen, expr->data.call.arguments[0]); + instr.opcode = RAVA_OP_STRING_ENDSWITH; + _rava_ir_emit(gen, instr); + } else if (is_string_tolowercase) { + _rava_ir_gen_expression(gen, string_object); + instr.opcode = RAVA_OP_STRING_TOLOWERCASE; + _rava_ir_emit(gen, instr); + } else if (is_string_touppercase) { + _rava_ir_gen_expression(gen, string_object); + instr.opcode = RAVA_OP_STRING_TOUPPERCASE; + _rava_ir_emit(gen, instr); + } else if (is_string_trim) { + _rava_ir_gen_expression(gen, string_object); + instr.opcode = RAVA_OP_STRING_TRIM; + _rava_ir_emit(gen, instr); + } else if (is_math_abs) { + _rava_ir_gen_expression(gen, expr->data.call.arguments[0]); + instr.opcode = RAVA_OP_MATH_ABS; + _rava_ir_emit(gen, instr); + } else if (is_math_sqrt) { + _rava_ir_gen_expression(gen, expr->data.call.arguments[0]); + instr.opcode = RAVA_OP_MATH_SQRT; + _rava_ir_emit(gen, instr); + } else if (is_math_pow) { + _rava_ir_gen_expression(gen, expr->data.call.arguments[0]); + _rava_ir_gen_expression(gen, expr->data.call.arguments[1]); + instr.opcode = RAVA_OP_MATH_POW; + _rava_ir_emit(gen, instr); + } else if (is_math_min) { + _rava_ir_gen_expression(gen, expr->data.call.arguments[0]); + _rava_ir_gen_expression(gen, expr->data.call.arguments[1]); + instr.opcode = RAVA_OP_MATH_MIN; + _rava_ir_emit(gen, instr); + } else if (is_math_max) { + _rava_ir_gen_expression(gen, expr->data.call.arguments[0]); + _rava_ir_gen_expression(gen, expr->data.call.arguments[1]); + instr.opcode = RAVA_OP_MATH_MAX; + _rava_ir_emit(gen, instr); + } else if (is_math_floor) { + _rava_ir_gen_expression(gen, expr->data.call.arguments[0]); + instr.opcode = RAVA_OP_MATH_FLOOR; + _rava_ir_emit(gen, instr); + } else if (is_math_ceil) { + _rava_ir_gen_expression(gen, expr->data.call.arguments[0]); + instr.opcode = RAVA_OP_MATH_CEIL; + _rava_ir_emit(gen, instr); + } else if (is_math_round) { + _rava_ir_gen_expression(gen, expr->data.call.arguments[0]); + instr.opcode = RAVA_OP_MATH_ROUND; + _rava_ir_emit(gen, instr); + } else if (is_math_sin) { + _rava_ir_gen_expression(gen, expr->data.call.arguments[0]); + instr.opcode = RAVA_OP_MATH_SIN; + _rava_ir_emit(gen, instr); + } else if (is_math_cos) { + _rava_ir_gen_expression(gen, expr->data.call.arguments[0]); + instr.opcode = RAVA_OP_MATH_COS; + _rava_ir_emit(gen, instr); + } else if (is_math_tan) { + _rava_ir_gen_expression(gen, expr->data.call.arguments[0]); + instr.opcode = RAVA_OP_MATH_TAN; + _rava_ir_emit(gen, instr); + } else if (is_math_log) { + _rava_ir_gen_expression(gen, expr->data.call.arguments[0]); + instr.opcode = RAVA_OP_MATH_LOG; + _rava_ir_emit(gen, instr); + } else if (is_math_exp) { + _rava_ir_gen_expression(gen, expr->data.call.arguments[0]); + instr.opcode = RAVA_OP_MATH_EXP; + _rava_ir_emit(gen, instr); + } else if (is_math_random) { + instr.opcode = RAVA_OP_MATH_RANDOM; + _rava_ir_emit(gen, instr); } else if (is_println || is_print) { for (size_t i = 0; i < expr->data.call.arguments_count; i++) { _rava_ir_gen_expression(gen, expr->data.call.arguments[i]); @@ -355,15 +578,28 @@ static void _rava_ir_gen_expression(RavaIRGenerator_t *gen, RavaASTNode_t *expr) _rava_ir_emit(gen, instr); } else if (expr->data.call.callee->type == RAVA_AST_MEMBER_ACCESS_EXPR) { RavaASTNode_t *member = expr->data.call.callee; - _rava_ir_gen_expression(gen, member->data.member_access.object); - for (size_t i = 0; i < expr->data.call.arguments_count; i++) { - _rava_ir_gen_expression(gen, expr->data.call.arguments[i]); + if (member->data.member_access.object->type == RAVA_AST_SUPER_EXPR) { + instr.opcode = RAVA_OP_LOAD_THIS; + _rava_ir_emit(gen, instr); + 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_CALL_SUPER; + instr.operand.call.class_name = gen->current_class->superclass ? strdup(gen->current_class->superclass) : NULL; + instr.operand.call.method_name = strdup(member->data.member_access.member); + instr.operand.call.arg_count = expr->data.call.arguments_count; + _rava_ir_emit(gen, instr); + } else { + _rava_ir_gen_expression(gen, member->data.member_access.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_CALL_VIRTUAL; + instr.operand.call.class_name = strdup(gen->current_class->name); + instr.operand.call.method_name = strdup(member->data.member_access.member); + instr.operand.call.arg_count = expr->data.call.arguments_count; + _rava_ir_emit(gen, instr); } - instr.opcode = RAVA_OP_CALL_VIRTUAL; - instr.operand.call.class_name = strdup(gen->current_class->name); - instr.operand.call.method_name = strdup(member->data.member_access.member); - instr.operand.call.arg_count = expr->data.call.arguments_count; - _rava_ir_emit(gen, instr); } else { for (size_t i = 0; i < expr->data.call.arguments_count; i++) { _rava_ir_gen_expression(gen, expr->data.call.arguments[i]); @@ -384,6 +620,74 @@ static void _rava_ir_gen_expression(RavaIRGenerator_t *gen, RavaASTNode_t *expr) _rava_ir_emit(gen, instr); break; + case RAVA_AST_CAST_EXPR: + _rava_ir_gen_expression(gen, expr->data.cast.expression); + instr.opcode = RAVA_OP_CAST; + if (expr->data.cast.type && expr->data.cast.type->data.type.type_name) { + instr.operand.var.type = rava_type_from_name(expr->data.cast.type->data.type.type_name); + } + _rava_ir_emit(gen, instr); + break; + + case RAVA_AST_TERNARY_EXPR: { + _rava_ir_gen_expression(gen, expr->data.ternary.condition); + + int else_label = rava_instruction_list_new_label(gen->current_method->instructions); + int end_label = rava_instruction_list_new_label(gen->current_method->instructions); + + instr.opcode = RAVA_OP_JUMP_IF_FALSE; + instr.operand.label_id = else_label; + _rava_ir_emit(gen, instr); + + _rava_ir_gen_expression(gen, expr->data.ternary.true_expr); + + instr.opcode = RAVA_OP_JUMP; + instr.operand.label_id = end_label; + _rava_ir_emit(gen, instr); + + instr.opcode = RAVA_OP_LABEL; + instr.operand.label_id = else_label; + _rava_ir_emit(gen, instr); + + _rava_ir_gen_expression(gen, expr->data.ternary.false_expr); + + instr.opcode = RAVA_OP_LABEL; + instr.operand.label_id = end_label; + _rava_ir_emit(gen, instr); + break; + } + + case RAVA_AST_ARRAY_INIT_EXPR: { + instr.opcode = RAVA_OP_LOAD_CONST; + instr.operand.int_value = (int)expr->data.array_init.elements_count; + _rava_ir_emit(gen, instr); + + instr.opcode = RAVA_OP_NEW_ARRAY; + _rava_ir_emit(gen, instr); + + for (size_t i = 0; i < expr->data.array_init.elements_count; i++) { + instr.opcode = RAVA_OP_DUP; + _rava_ir_emit(gen, instr); + + instr.opcode = RAVA_OP_LOAD_CONST; + instr.operand.int_value = (int)i; + _rava_ir_emit(gen, instr); + + _rava_ir_gen_expression(gen, expr->data.array_init.elements[i]); + + instr.opcode = RAVA_OP_STORE_ARRAY; + _rava_ir_emit(gen, instr); + } + break; + } + + case RAVA_AST_INSTANCEOF_EXPR: + _rava_ir_gen_expression(gen, expr->data.instanceof_expr.expression); + instr.opcode = RAVA_OP_INSTANCEOF; + instr.operand.string_value = strdup(expr->data.instanceof_expr.type_name); + _rava_ir_emit(gen, instr); + break; + default: break; } @@ -463,6 +767,33 @@ static void _rava_ir_gen_statement(RavaIRGenerator_t *gen, RavaASTNode_t *stmt) break; } + case RAVA_AST_DO_WHILE_STMT: { + int start_label = rava_instruction_list_new_label(gen->current_method->instructions); + int end_label = rava_instruction_list_new_label(gen->current_method->instructions); + + RavaLoopContext_t loop_ctx = { .break_label = end_label, .continue_label = start_label, .parent = gen->loop_context }; + gen->loop_context = &loop_ctx; + + instr.opcode = RAVA_OP_LABEL; + instr.operand.label_id = start_label; + _rava_ir_emit(gen, instr); + + _rava_ir_gen_statement(gen, stmt->data.while_stmt.body); + + _rava_ir_gen_expression(gen, stmt->data.while_stmt.condition); + + instr.opcode = RAVA_OP_JUMP_IF_TRUE; + instr.operand.label_id = start_label; + _rava_ir_emit(gen, instr); + + instr.opcode = RAVA_OP_LABEL; + instr.operand.label_id = end_label; + _rava_ir_emit(gen, instr); + + gen->loop_context = loop_ctx.parent; + break; + } + case RAVA_AST_FOR_STMT: { if (stmt->data.for_stmt.init) { if (stmt->data.for_stmt.init->type == RAVA_AST_VAR_DECL) { @@ -516,6 +847,93 @@ static void _rava_ir_gen_statement(RavaIRGenerator_t *gen, RavaASTNode_t *stmt) break; } + case RAVA_AST_ENHANCED_FOR_STMT: { + size_t idx_local = gen->next_local++; + size_t elem_local = gen->next_local++; + gen->current_method->local_count = gen->next_local; + + _rava_ir_add_local(gen, stmt->data.enhanced_for.var_name, elem_local); + + instr.opcode = RAVA_OP_LOAD_CONST; + instr.operand.int_value = 0; + _rava_ir_emit(gen, instr); + + instr.opcode = RAVA_OP_STORE_LOCAL; + instr.operand.var.index = idx_local; + _rava_ir_emit(gen, instr); + + int start_label = rava_instruction_list_new_label(gen->current_method->instructions); + int continue_label = rava_instruction_list_new_label(gen->current_method->instructions); + int end_label = rava_instruction_list_new_label(gen->current_method->instructions); + + RavaLoopContext_t loop_ctx = { .break_label = end_label, .continue_label = continue_label, .parent = gen->loop_context }; + gen->loop_context = &loop_ctx; + + instr.opcode = RAVA_OP_LABEL; + instr.operand.label_id = start_label; + _rava_ir_emit(gen, instr); + + instr.opcode = RAVA_OP_LOAD_LOCAL; + instr.operand.var.index = idx_local; + _rava_ir_emit(gen, instr); + + _rava_ir_gen_expression(gen, stmt->data.enhanced_for.iterable); + instr.opcode = RAVA_OP_ARRAY_LENGTH; + _rava_ir_emit(gen, instr); + + instr.opcode = RAVA_OP_LT; + _rava_ir_emit(gen, instr); + + instr.opcode = RAVA_OP_JUMP_IF_FALSE; + instr.operand.label_id = end_label; + _rava_ir_emit(gen, instr); + + _rava_ir_gen_expression(gen, stmt->data.enhanced_for.iterable); + + instr.opcode = RAVA_OP_LOAD_LOCAL; + instr.operand.var.index = idx_local; + _rava_ir_emit(gen, instr); + + instr.opcode = RAVA_OP_LOAD_ARRAY; + _rava_ir_emit(gen, instr); + + instr.opcode = RAVA_OP_STORE_LOCAL; + instr.operand.var.index = elem_local; + _rava_ir_emit(gen, instr); + + _rava_ir_gen_statement(gen, stmt->data.enhanced_for.body); + + instr.opcode = RAVA_OP_LABEL; + instr.operand.label_id = continue_label; + _rava_ir_emit(gen, instr); + + instr.opcode = RAVA_OP_LOAD_LOCAL; + instr.operand.var.index = idx_local; + _rava_ir_emit(gen, instr); + + instr.opcode = RAVA_OP_LOAD_CONST; + instr.operand.int_value = 1; + _rava_ir_emit(gen, instr); + + instr.opcode = RAVA_OP_ADD; + _rava_ir_emit(gen, instr); + + instr.opcode = RAVA_OP_STORE_LOCAL; + instr.operand.var.index = idx_local; + _rava_ir_emit(gen, instr); + + instr.opcode = RAVA_OP_JUMP; + instr.operand.label_id = start_label; + _rava_ir_emit(gen, instr); + + instr.opcode = RAVA_OP_LABEL; + instr.operand.label_id = end_label; + _rava_ir_emit(gen, instr); + + gen->loop_context = loop_ctx.parent; + break; + } + case RAVA_AST_RETURN_STMT: if (stmt->data.return_stmt.value) { _rava_ir_gen_expression(gen, stmt->data.return_stmt.value); @@ -546,6 +964,67 @@ static void _rava_ir_gen_statement(RavaIRGenerator_t *gen, RavaASTNode_t *stmt) break; } + case RAVA_AST_SWITCH_STMT: { + int end_label = rava_instruction_list_new_label(gen->current_method->instructions); + + RavaLoopContext_t switch_ctx = { .break_label = end_label, .continue_label = -1, .parent = gen->loop_context }; + gen->loop_context = &switch_ctx; + + size_t case_count = stmt->children_count; + int *case_labels = malloc(case_count * sizeof(int)); + int default_label = -1; + + for (size_t i = 0; i < case_count; i++) { + case_labels[i] = rava_instruction_list_new_label(gen->current_method->instructions); + if (stmt->children[i]->data.case_stmt.is_default) { + default_label = case_labels[i]; + } + } + + for (size_t i = 0; i < case_count; i++) { + RavaASTNode_t *case_node = stmt->children[i]; + if (!case_node->data.case_stmt.is_default) { + _rava_ir_gen_expression(gen, stmt->data.switch_stmt.expression); + _rava_ir_gen_expression(gen, case_node->data.case_stmt.value); + instr.opcode = RAVA_OP_EQ; + _rava_ir_emit(gen, instr); + instr.opcode = RAVA_OP_JUMP_IF_TRUE; + instr.operand.label_id = case_labels[i]; + _rava_ir_emit(gen, instr); + } + } + + if (default_label >= 0) { + instr.opcode = RAVA_OP_JUMP; + instr.operand.label_id = default_label; + _rava_ir_emit(gen, instr); + } else { + instr.opcode = RAVA_OP_JUMP; + instr.operand.label_id = end_label; + _rava_ir_emit(gen, instr); + } + + for (size_t i = 0; i < case_count; i++) { + RavaASTNode_t *case_node = stmt->children[i]; + + instr.opcode = RAVA_OP_LABEL; + instr.operand.label_id = case_labels[i]; + _rava_ir_emit(gen, instr); + + for (size_t j = 0; j < case_node->children_count; j++) { + _rava_ir_gen_statement(gen, case_node->children[j]); + } + } + + instr.opcode = RAVA_OP_LABEL; + instr.operand.label_id = end_label; + _rava_ir_emit(gen, instr); + + free(case_labels); + gen->loop_context = switch_ctx.parent; + break; + } + case RAVA_AST_BREAK_STMT: if (gen->loop_context) { instr.opcode = RAVA_OP_JUMP; @@ -562,6 +1041,76 @@ static void _rava_ir_gen_statement(RavaIRGenerator_t *gen, RavaASTNode_t *stmt) } break; + case RAVA_AST_THROW_STMT: + if (stmt->data.throw_stmt.expression) { + _rava_ir_gen_expression(gen, stmt->data.throw_stmt.expression); + } else { + instr.opcode = RAVA_OP_LOAD_CONST; + instr.operand.int_value = 1; + _rava_ir_emit(gen, instr); + } + instr.opcode = RAVA_OP_THROW; + _rava_ir_emit(gen, instr); + break; + + case RAVA_AST_TRY_STMT: { + int catch_label = rava_instruction_list_new_label(gen->current_method->instructions); + int finally_label = rava_instruction_list_new_label(gen->current_method->instructions); + int end_label = rava_instruction_list_new_label(gen->current_method->instructions); + + int exception_local = gen->next_local++; + gen->current_method->local_count = gen->next_local; + + instr.opcode = RAVA_OP_TRY_BEGIN; + instr.operand.try_handler.catch_label = catch_label; + instr.operand.try_handler.finally_label = stmt->data.try_stmt.finally_block ? finally_label : -1; + instr.operand.try_handler.end_label = end_label; + instr.operand.try_handler.exception_local = exception_local; + _rava_ir_emit(gen, instr); + + _rava_ir_gen_statement(gen, stmt->data.try_stmt.try_block); + + instr.opcode = RAVA_OP_TRY_END; + _rava_ir_emit(gen, instr); + + if (stmt->data.try_stmt.finally_block) { + instr.opcode = RAVA_OP_JUMP; + instr.operand.label_id = finally_label; + _rava_ir_emit(gen, instr); + } else { + instr.opcode = RAVA_OP_JUMP; + instr.operand.label_id = end_label; + _rava_ir_emit(gen, instr); + } + + instr.opcode = RAVA_OP_LABEL; + instr.operand.label_id = catch_label; + _rava_ir_emit(gen, instr); + + for (size_t i = 0; i < stmt->data.try_stmt.catch_count; i++) { + RavaASTNode_t *catch_node = stmt->data.try_stmt.catch_clauses[i]; + + if (catch_node->data.catch_clause.exception_name) { + _rava_ir_add_local(gen, catch_node->data.catch_clause.exception_name, exception_local); + } + + _rava_ir_gen_statement(gen, catch_node->data.catch_clause.body); + } + + if (stmt->data.try_stmt.finally_block) { + instr.opcode = RAVA_OP_LABEL; + instr.operand.label_id = finally_label; + _rava_ir_emit(gen, instr); + + _rava_ir_gen_statement(gen, stmt->data.try_stmt.finally_block); + } + + instr.opcode = RAVA_OP_LABEL; + instr.operand.label_id = end_label; + _rava_ir_emit(gen, instr); + break; + } + default: break; } diff --git a/parser/parser.h b/parser/parser.h index 05823d7..f8fe425 100644 --- a/parser/parser.h +++ b/parser/parser.h @@ -157,11 +157,19 @@ struct RavaASTNode_t { struct { char *name; char *superclass; + char **interfaces; + size_t interfaces_count; RavaASTNode_t *type; RavaModifier_e *modifiers; size_t modifiers_count; } class_decl; + struct { + char *name; + RavaModifier_e *modifiers; + size_t modifiers_count; + } interface_decl; + struct { char *name; RavaASTNode_t *return_type; @@ -175,6 +183,14 @@ struct RavaASTNode_t { RavaASTNode_t *initializer; } var_decl; + struct { + char *name; + RavaASTNode_t *type; + RavaASTNode_t *initializer; + RavaModifier_e *modifiers; + size_t modifiers_count; + } field_decl; + struct { RavaASTNode_t *condition; RavaASTNode_t *then_stmt; @@ -193,6 +209,13 @@ struct RavaASTNode_t { RavaASTNode_t *body; } for_stmt; + struct { + RavaASTNode_t *var_type; + char *var_name; + RavaASTNode_t *iterable; + RavaASTNode_t *body; + } enhanced_for; + struct { RavaASTNode_t *value; } return_stmt; @@ -229,6 +252,42 @@ struct RavaASTNode_t { RavaASTNode_t *type; RavaASTNode_t *expression; } cast; + + struct { + RavaASTNode_t *expression; + } switch_stmt; + + struct { + RavaASTNode_t *value; + bool is_default; + } case_stmt; + + struct { + RavaASTNode_t *try_block; + RavaASTNode_t **catch_clauses; + size_t catch_count; + RavaASTNode_t *finally_block; + } try_stmt; + + struct { + char *exception_type; + char *exception_name; + RavaASTNode_t *body; + } catch_clause; + + struct { + RavaASTNode_t *expression; + } throw_stmt; + + struct { + RavaASTNode_t **elements; + size_t elements_count; + } array_init; + + struct { + RavaASTNode_t *expression; + char *type_name; + } instanceof_expr; } data; }; diff --git a/parser/parser_declarations.c b/parser/parser_declarations.c index 3c0d51d..145abe1 100644 --- a/parser/parser_declarations.c +++ b/parser/parser_declarations.c @@ -78,6 +78,8 @@ RavaASTNode_t* _rava_parser_parse_class_declaration(RavaParser_t *parser) { class_decl->data.class_decl.modifiers = modifiers; class_decl->data.class_decl.modifiers_count = modifiers_count; class_decl->data.class_decl.superclass = NULL; + class_decl->data.class_decl.interfaces = NULL; + class_decl->data.class_decl.interfaces_count = 0; if (_rava_parser_check(parser, RAVA_TOKEN_IDENTIFIER)) { class_decl->data.class_decl.name = strdup(parser->current_token->lexeme); @@ -91,6 +93,24 @@ RavaASTNode_t* _rava_parser_parse_class_declaration(RavaParser_t *parser) { } } + if (_rava_parser_match(parser, RAVA_TOKEN_KEYWORD_IMPLEMENTS)) { + size_t capacity = 4; + class_decl->data.class_decl.interfaces = malloc(capacity * sizeof(char*)); + do { + if (_rava_parser_check(parser, RAVA_TOKEN_IDENTIFIER)) { + if (class_decl->data.class_decl.interfaces_count >= capacity) { + capacity *= 2; + class_decl->data.class_decl.interfaces = realloc( + class_decl->data.class_decl.interfaces, + capacity * sizeof(char*)); + } + class_decl->data.class_decl.interfaces[class_decl->data.class_decl.interfaces_count++] = + strdup(parser->current_token->lexeme); + _rava_parser_advance(parser); + } + } while (_rava_parser_match(parser, RAVA_TOKEN_COMMA)); + } + _rava_parser_expect(parser, RAVA_TOKEN_LBRACE, "Expected '{' after class name"); while (!_rava_parser_check(parser, RAVA_TOKEN_RBRACE) && @@ -160,15 +180,18 @@ RavaASTNode_t* _rava_parser_parse_class_declaration(RavaParser_t *parser) { RavaASTNode_t *field = rava_ast_node_create(RAVA_AST_FIELD_DECL, parser->current_token->line, parser->current_token->column); - field->data.var_decl.type = member_type; - field->data.var_decl.name = name; + field->data.field_decl.type = member_type; + field->data.field_decl.name = name; + field->data.field_decl.modifiers = member_modifiers; + field->data.field_decl.modifiers_count = member_modifiers_count; if (_rava_parser_match(parser, RAVA_TOKEN_ASSIGN)) { - field->data.var_decl.initializer = _rava_parser_parse_expression(parser); + field->data.field_decl.initializer = _rava_parser_parse_expression(parser); } else { - field->data.var_decl.initializer = NULL; + field->data.field_decl.initializer = NULL; } _rava_parser_expect(parser, RAVA_TOKEN_SEMICOLON, "Expected ';' after field declaration"); rava_ast_node_add_child(class_decl, field); + member_modifiers = NULL; } } } @@ -178,6 +201,63 @@ RavaASTNode_t* _rava_parser_parse_class_declaration(RavaParser_t *parser) { return class_decl; } +static RavaASTNode_t* _rava_parser_parse_interface_declaration(RavaParser_t *parser) { + RavaModifier_e *modifiers = NULL; + size_t modifiers_count = 0; + + _rava_parser_parse_modifiers(parser, &modifiers, &modifiers_count); + + _rava_parser_expect(parser, RAVA_TOKEN_KEYWORD_INTERFACE, "Expected 'interface' keyword"); + + RavaASTNode_t *interface_decl = rava_ast_node_create(RAVA_AST_INTERFACE_DECL, + parser->current_token->line, + parser->current_token->column); + + interface_decl->data.interface_decl.modifiers = modifiers; + interface_decl->data.interface_decl.modifiers_count = modifiers_count; + + if (_rava_parser_check(parser, RAVA_TOKEN_IDENTIFIER)) { + interface_decl->data.interface_decl.name = strdup(parser->current_token->lexeme); + _rava_parser_advance(parser); + } + + _rava_parser_expect(parser, RAVA_TOKEN_LBRACE, "Expected '{' after interface name"); + + while (!_rava_parser_check(parser, RAVA_TOKEN_RBRACE) && + !_rava_parser_check(parser, RAVA_TOKEN_EOF)) { + + RavaModifier_e *member_modifiers = NULL; + size_t member_modifiers_count = 0; + + _rava_parser_parse_modifiers(parser, &member_modifiers, &member_modifiers_count); + + RavaASTNode_t *member_type = _rava_parser_parse_type(parser); + + if (_rava_parser_check(parser, RAVA_TOKEN_IDENTIFIER)) { + char *name = strdup(parser->current_token->lexeme); + _rava_parser_advance(parser); + + if (_rava_parser_check(parser, RAVA_TOKEN_LPAREN)) { + RavaASTNode_t *method = _rava_parser_parse_method_declaration(parser, + member_modifiers, + member_modifiers_count, + member_type); + method->data.method_decl.name = name; + rava_ast_node_add_child(interface_decl, method); + } else { + free(name); + free(member_modifiers); + } + } else { + free(member_modifiers); + } + } + + _rava_parser_expect(parser, RAVA_TOKEN_RBRACE, "Expected '}' after interface body"); + + return interface_decl; +} + RavaASTNode_t* rava_parser_parse(RavaParser_t *parser) { RavaASTNode_t *root = rava_ast_node_create(RAVA_AST_COMPILATION_UNIT, 1, 1); @@ -186,7 +266,27 @@ RavaASTNode_t* rava_parser_parse(RavaParser_t *parser) { break; } - RavaASTNode_t *decl = _rava_parser_parse_class_declaration(parser); + RavaModifier_e *modifiers = NULL; + size_t modifiers_count = 0; + _rava_parser_parse_modifiers(parser, &modifiers, &modifiers_count); + + RavaASTNode_t *decl = NULL; + + if (_rava_parser_check(parser, RAVA_TOKEN_KEYWORD_INTERFACE)) { + RavaToken_t *saved = parser->current_token; + parser->current_token = saved; + free(modifiers); + decl = _rava_parser_parse_interface_declaration(parser); + } else if (_rava_parser_check(parser, RAVA_TOKEN_KEYWORD_CLASS)) { + RavaToken_t *saved = parser->current_token; + parser->current_token = saved; + free(modifiers); + decl = _rava_parser_parse_class_declaration(parser); + } else { + free(modifiers); + break; + } + if (decl) { rava_ast_node_add_child(root, decl); } diff --git a/parser/parser_expressions.c b/parser/parser_expressions.c index a4fade9..ce52a90 100644 --- a/parser/parser_expressions.c +++ b/parser/parser_expressions.c @@ -10,6 +10,19 @@ extern bool _rava_parser_expect(RavaParser_t *parser, RavaTokenType_e type, cons extern RavaASTNode_t* _rava_parser_parse_type(RavaParser_t *parser); RavaASTNode_t* _rava_parser_parse_expression(RavaParser_t *parser); +RavaASTNode_t* _rava_parser_parse_array_initializer(RavaParser_t *parser); +static RavaASTNode_t* _rava_parser_parse_unary(RavaParser_t *parser); + +static bool _is_primitive_type_token(RavaTokenType_e type) { + return type == RAVA_TOKEN_KEYWORD_INT || + type == RAVA_TOKEN_KEYWORD_LONG || + type == RAVA_TOKEN_KEYWORD_DOUBLE || + type == RAVA_TOKEN_KEYWORD_FLOAT || + type == RAVA_TOKEN_KEYWORD_BOOLEAN || + type == RAVA_TOKEN_KEYWORD_CHAR || + type == RAVA_TOKEN_KEYWORD_BYTE || + type == RAVA_TOKEN_KEYWORD_SHORT; +} static RavaASTNode_t* _rava_parser_parse_primary(RavaParser_t *parser) { RavaASTNode_t *node = NULL; @@ -60,6 +73,16 @@ static RavaASTNode_t* _rava_parser_parse_primary(RavaParser_t *parser) { } if (_rava_parser_match(parser, RAVA_TOKEN_LPAREN)) { + if (_is_primitive_type_token(parser->current_token->type) && + parser->peek_token && parser->peek_token->type == RAVA_TOKEN_RPAREN) { + RavaASTNode_t *cast_node = rava_ast_node_create(RAVA_AST_CAST_EXPR, + parser->current_token->line, + parser->current_token->column); + cast_node->data.cast.type = _rava_parser_parse_type(parser); + _rava_parser_expect(parser, RAVA_TOKEN_RPAREN, "Expected ')' after type in cast"); + cast_node->data.cast.expression = _rava_parser_parse_unary(parser); + return cast_node; + } RavaASTNode_t *expr = _rava_parser_parse_expression(parser); _rava_parser_expect(parser, RAVA_TOKEN_RPAREN, "Expected ')' after expression"); return expr; @@ -76,9 +99,10 @@ static RavaASTNode_t* _rava_parser_parse_primary(RavaParser_t *parser) { node->data.new_expr.arguments = malloc(sizeof(RavaASTNode_t*) * args_capacity); node->data.new_expr.arguments_count = 0; - node->data.new_expr.arguments[node->data.new_expr.arguments_count++] = - _rava_parser_parse_expression(parser); - + if (!_rava_parser_check(parser, RAVA_TOKEN_RBRACKET)) { + node->data.new_expr.arguments[node->data.new_expr.arguments_count++] = + _rava_parser_parse_expression(parser); + } _rava_parser_expect(parser, RAVA_TOKEN_RBRACKET, "Expected ']' after array size"); while (_rava_parser_match(parser, RAVA_TOKEN_LBRACKET)) { @@ -304,13 +328,51 @@ static RavaASTNode_t* _rava_parser_parse_additive(RavaParser_t *parser) { return left; } -static RavaASTNode_t* _rava_parser_parse_relational(RavaParser_t *parser) { +static RavaASTNode_t* _rava_parser_parse_shift(RavaParser_t *parser) { RavaASTNode_t *left = _rava_parser_parse_additive(parser); + while (_rava_parser_check(parser, RAVA_TOKEN_LSHIFT) || + _rava_parser_check(parser, RAVA_TOKEN_RSHIFT) || + _rava_parser_check(parser, RAVA_TOKEN_URSHIFT)) { + + RavaBinaryOp_e op; + if (_rava_parser_match(parser, RAVA_TOKEN_LSHIFT)) op = RAVA_BINOP_LSHIFT; + else if (_rava_parser_match(parser, RAVA_TOKEN_RSHIFT)) op = RAVA_BINOP_RSHIFT; + else { _rava_parser_advance(parser); op = RAVA_BINOP_URSHIFT; } + + RavaASTNode_t *node = rava_ast_node_create(RAVA_AST_BINARY_EXPR, + parser->current_token->line, + parser->current_token->column); + node->data.binary.op = op; + node->data.binary.left = left; + node->data.binary.right = _rava_parser_parse_additive(parser); + left = node; + } + + return left; +} + +static RavaASTNode_t* _rava_parser_parse_relational(RavaParser_t *parser) { + RavaASTNode_t *left = _rava_parser_parse_shift(parser); + while (_rava_parser_check(parser, RAVA_TOKEN_LT) || _rava_parser_check(parser, RAVA_TOKEN_GT) || _rava_parser_check(parser, RAVA_TOKEN_LE) || - _rava_parser_check(parser, RAVA_TOKEN_GE)) { + _rava_parser_check(parser, RAVA_TOKEN_GE) || + _rava_parser_check(parser, RAVA_TOKEN_KEYWORD_INSTANCEOF)) { + + if (_rava_parser_match(parser, RAVA_TOKEN_KEYWORD_INSTANCEOF)) { + RavaASTNode_t *node = rava_ast_node_create(RAVA_AST_INSTANCEOF_EXPR, + parser->current_token->line, + parser->current_token->column); + node->data.instanceof_expr.expression = left; + if (_rava_parser_check(parser, RAVA_TOKEN_IDENTIFIER)) { + node->data.instanceof_expr.type_name = strdup(parser->current_token->lexeme); + _rava_parser_advance(parser); + } + left = node; + continue; + } RavaBinaryOp_e op; if (_rava_parser_match(parser, RAVA_TOKEN_LT)) op = RAVA_BINOP_LT; @@ -352,16 +414,64 @@ static RavaASTNode_t* _rava_parser_parse_equality(RavaParser_t *parser) { return left; } -static RavaASTNode_t* _rava_parser_parse_logical_and(RavaParser_t *parser) { +static RavaASTNode_t* _rava_parser_parse_bitwise_and(RavaParser_t *parser) { RavaASTNode_t *left = _rava_parser_parse_equality(parser); + while (_rava_parser_match(parser, RAVA_TOKEN_AMP)) { + RavaASTNode_t *node = rava_ast_node_create(RAVA_AST_BINARY_EXPR, + parser->current_token->line, + parser->current_token->column); + node->data.binary.op = RAVA_BINOP_BITAND; + node->data.binary.left = left; + node->data.binary.right = _rava_parser_parse_equality(parser); + left = node; + } + + return left; +} + +static RavaASTNode_t* _rava_parser_parse_bitwise_xor(RavaParser_t *parser) { + RavaASTNode_t *left = _rava_parser_parse_bitwise_and(parser); + + while (_rava_parser_match(parser, RAVA_TOKEN_CARET)) { + RavaASTNode_t *node = rava_ast_node_create(RAVA_AST_BINARY_EXPR, + parser->current_token->line, + parser->current_token->column); + node->data.binary.op = RAVA_BINOP_BITXOR; + node->data.binary.left = left; + node->data.binary.right = _rava_parser_parse_bitwise_and(parser); + left = node; + } + + return left; +} + +static RavaASTNode_t* _rava_parser_parse_bitwise_or(RavaParser_t *parser) { + RavaASTNode_t *left = _rava_parser_parse_bitwise_xor(parser); + + while (_rava_parser_match(parser, RAVA_TOKEN_PIPE)) { + RavaASTNode_t *node = rava_ast_node_create(RAVA_AST_BINARY_EXPR, + parser->current_token->line, + parser->current_token->column); + node->data.binary.op = RAVA_BINOP_BITOR; + node->data.binary.left = left; + node->data.binary.right = _rava_parser_parse_bitwise_xor(parser); + left = node; + } + + return left; +} + +static RavaASTNode_t* _rava_parser_parse_logical_and(RavaParser_t *parser) { + RavaASTNode_t *left = _rava_parser_parse_bitwise_or(parser); + while (_rava_parser_match(parser, RAVA_TOKEN_AND)) { RavaASTNode_t *node = rava_ast_node_create(RAVA_AST_BINARY_EXPR, parser->current_token->line, parser->current_token->column); node->data.binary.op = RAVA_BINOP_AND; node->data.binary.left = left; - node->data.binary.right = _rava_parser_parse_equality(parser); + node->data.binary.right = _rava_parser_parse_bitwise_or(parser); left = node; } @@ -384,8 +494,25 @@ static RavaASTNode_t* _rava_parser_parse_logical_or(RavaParser_t *parser) { return left; } +static RavaASTNode_t* _rava_parser_parse_ternary(RavaParser_t *parser) { + RavaASTNode_t *condition = _rava_parser_parse_logical_or(parser); + + if (_rava_parser_match(parser, RAVA_TOKEN_QUESTION)) { + RavaASTNode_t *node = rava_ast_node_create(RAVA_AST_TERNARY_EXPR, + parser->current_token->line, + parser->current_token->column); + node->data.ternary.condition = condition; + node->data.ternary.true_expr = _rava_parser_parse_expression(parser); + _rava_parser_expect(parser, RAVA_TOKEN_COLON, "Expected ':' in ternary expression"); + node->data.ternary.false_expr = _rava_parser_parse_ternary(parser); + return node; + } + + return condition; +} + static RavaASTNode_t* _rava_parser_parse_assignment(RavaParser_t *parser) { - RavaASTNode_t *left = _rava_parser_parse_logical_or(parser); + RavaASTNode_t *left = _rava_parser_parse_ternary(parser); if (_rava_parser_match(parser, RAVA_TOKEN_ASSIGN)) { RavaASTNode_t *node = rava_ast_node_create(RAVA_AST_ASSIGN_EXPR, @@ -428,6 +555,34 @@ static RavaASTNode_t* _rava_parser_parse_assignment(RavaParser_t *parser) { return left; } +RavaASTNode_t* _rava_parser_parse_array_initializer(RavaParser_t *parser) { + RavaASTNode_t *node = rava_ast_node_create(RAVA_AST_ARRAY_INIT_EXPR, + parser->current_token->line, + parser->current_token->column); + + _rava_parser_expect(parser, RAVA_TOKEN_LBRACE, "Expected '{' for array initializer"); + + size_t capacity = 8; + node->data.array_init.elements = malloc(sizeof(RavaASTNode_t*) * capacity); + node->data.array_init.elements_count = 0; + + if (!_rava_parser_check(parser, RAVA_TOKEN_RBRACE)) { + do { + if (node->data.array_init.elements_count >= capacity) { + capacity *= 2; + node->data.array_init.elements = realloc(node->data.array_init.elements, + sizeof(RavaASTNode_t*) * capacity); + } + node->data.array_init.elements[node->data.array_init.elements_count++] = + _rava_parser_parse_expression(parser); + } while (_rava_parser_match(parser, RAVA_TOKEN_COMMA)); + } + + _rava_parser_expect(parser, RAVA_TOKEN_RBRACE, "Expected '}' after array initializer"); + + return node; +} + RavaASTNode_t* _rava_parser_parse_expression(RavaParser_t *parser) { return _rava_parser_parse_assignment(parser); } diff --git a/parser/parser_statements.c b/parser/parser_statements.c index bd5e109..80ede02 100644 --- a/parser/parser_statements.c +++ b/parser/parser_statements.c @@ -8,6 +8,7 @@ extern bool _rava_parser_check(RavaParser_t *parser, RavaTokenType_e type); extern bool _rava_parser_match(RavaParser_t *parser, RavaTokenType_e type); extern bool _rava_parser_expect(RavaParser_t *parser, RavaTokenType_e type, const char *message); extern RavaASTNode_t* _rava_parser_parse_expression(RavaParser_t *parser); +extern RavaASTNode_t* _rava_parser_parse_array_initializer(RavaParser_t *parser); extern RavaASTNode_t* _rava_parser_parse_type(RavaParser_t *parser); RavaASTNode_t* _rava_parser_parse_statement(RavaParser_t *parser); @@ -72,11 +73,26 @@ RavaASTNode_t* _rava_parser_parse_statement(RavaParser_t *parser) { return node; } - if (_rava_parser_match(parser, RAVA_TOKEN_KEYWORD_FOR)) { - RavaASTNode_t *node = rava_ast_node_create(RAVA_AST_FOR_STMT, + if (_rava_parser_match(parser, RAVA_TOKEN_KEYWORD_DO)) { + RavaASTNode_t *node = rava_ast_node_create(RAVA_AST_DO_WHILE_STMT, parser->current_token->line, parser->current_token->column); + node->data.while_stmt.body = _rava_parser_parse_statement(parser); + + _rava_parser_expect(parser, RAVA_TOKEN_KEYWORD_WHILE, "Expected 'while' after do body"); + _rava_parser_expect(parser, RAVA_TOKEN_LPAREN, "Expected '(' after 'while'"); + node->data.while_stmt.condition = _rava_parser_parse_expression(parser); + _rava_parser_expect(parser, RAVA_TOKEN_RPAREN, "Expected ')' after do-while condition"); + _rava_parser_expect(parser, RAVA_TOKEN_SEMICOLON, "Expected ';' after do-while"); + + return node; + } + + if (_rava_parser_match(parser, RAVA_TOKEN_KEYWORD_FOR)) { + int line = parser->current_token->line; + int column = parser->current_token->column; + _rava_parser_expect(parser, RAVA_TOKEN_LPAREN, "Expected '(' after 'for'"); if (!_rava_parser_check(parser, RAVA_TOKEN_SEMICOLON)) { @@ -94,41 +110,154 @@ RavaASTNode_t* _rava_parser_parse_statement(RavaParser_t *parser) { } if (is_type_decl) { RavaASTNode_t *type = _rava_parser_parse_type(parser); + char *var_name = NULL; + if (_rava_parser_check(parser, RAVA_TOKEN_IDENTIFIER)) { + var_name = strdup(parser->current_token->lexeme); + _rava_parser_advance(parser); + } + + if (_rava_parser_match(parser, RAVA_TOKEN_COLON)) { + RavaASTNode_t *node = rava_ast_node_create(RAVA_AST_ENHANCED_FOR_STMT, line, column); + node->data.enhanced_for.var_type = type; + node->data.enhanced_for.var_name = var_name; + node->data.enhanced_for.iterable = _rava_parser_parse_expression(parser); + _rava_parser_expect(parser, RAVA_TOKEN_RPAREN, "Expected ')' after enhanced for"); + node->data.enhanced_for.body = _rava_parser_parse_statement(parser); + return node; + } + + RavaASTNode_t *node = rava_ast_node_create(RAVA_AST_FOR_STMT, line, column); RavaASTNode_t *var_decl = rava_ast_node_create(RAVA_AST_VAR_DECL, parser->current_token->line, parser->current_token->column); var_decl->data.var_decl.type = type; - if (_rava_parser_check(parser, RAVA_TOKEN_IDENTIFIER)) { - var_decl->data.var_decl.name = strdup(parser->current_token->lexeme); - _rava_parser_advance(parser); - } + var_decl->data.var_decl.name = var_name; if (_rava_parser_match(parser, RAVA_TOKEN_ASSIGN)) { var_decl->data.var_decl.initializer = _rava_parser_parse_expression(parser); } node->data.for_stmt.init = var_decl; + _rava_parser_expect(parser, RAVA_TOKEN_SEMICOLON, "Expected ';' after for init"); + + if (!_rava_parser_check(parser, RAVA_TOKEN_SEMICOLON)) { + node->data.for_stmt.condition = _rava_parser_parse_expression(parser); + } else { + node->data.for_stmt.condition = NULL; + } + _rava_parser_expect(parser, RAVA_TOKEN_SEMICOLON, "Expected ';' after for condition"); + + if (!_rava_parser_check(parser, RAVA_TOKEN_RPAREN)) { + node->data.for_stmt.update = _rava_parser_parse_expression(parser); + } else { + node->data.for_stmt.update = NULL; + } + _rava_parser_expect(parser, RAVA_TOKEN_RPAREN, "Expected ')' after for update"); + + node->data.for_stmt.body = _rava_parser_parse_statement(parser); + return node; } else { + RavaASTNode_t *node = rava_ast_node_create(RAVA_AST_FOR_STMT, line, column); node->data.for_stmt.init = _rava_parser_parse_expression(parser); + _rava_parser_expect(parser, RAVA_TOKEN_SEMICOLON, "Expected ';' after for init"); + + if (!_rava_parser_check(parser, RAVA_TOKEN_SEMICOLON)) { + node->data.for_stmt.condition = _rava_parser_parse_expression(parser); + } else { + node->data.for_stmt.condition = NULL; + } + _rava_parser_expect(parser, RAVA_TOKEN_SEMICOLON, "Expected ';' after for condition"); + + if (!_rava_parser_check(parser, RAVA_TOKEN_RPAREN)) { + node->data.for_stmt.update = _rava_parser_parse_expression(parser); + } else { + node->data.for_stmt.update = NULL; + } + _rava_parser_expect(parser, RAVA_TOKEN_RPAREN, "Expected ')' after for update"); + + node->data.for_stmt.body = _rava_parser_parse_statement(parser); + return node; } } else { + RavaASTNode_t *node = rava_ast_node_create(RAVA_AST_FOR_STMT, line, column); node->data.for_stmt.init = NULL; - } - _rava_parser_expect(parser, RAVA_TOKEN_SEMICOLON, "Expected ';' after for init"); + _rava_parser_expect(parser, RAVA_TOKEN_SEMICOLON, "Expected ';' after for init"); - if (!_rava_parser_check(parser, RAVA_TOKEN_SEMICOLON)) { - node->data.for_stmt.condition = _rava_parser_parse_expression(parser); - } else { - node->data.for_stmt.condition = NULL; - } - _rava_parser_expect(parser, RAVA_TOKEN_SEMICOLON, "Expected ';' after for condition"); + if (!_rava_parser_check(parser, RAVA_TOKEN_SEMICOLON)) { + node->data.for_stmt.condition = _rava_parser_parse_expression(parser); + } else { + node->data.for_stmt.condition = NULL; + } + _rava_parser_expect(parser, RAVA_TOKEN_SEMICOLON, "Expected ';' after for condition"); - if (!_rava_parser_check(parser, RAVA_TOKEN_RPAREN)) { - node->data.for_stmt.update = _rava_parser_parse_expression(parser); - } else { - node->data.for_stmt.update = NULL; - } - _rava_parser_expect(parser, RAVA_TOKEN_RPAREN, "Expected ')' after for update"); + if (!_rava_parser_check(parser, RAVA_TOKEN_RPAREN)) { + node->data.for_stmt.update = _rava_parser_parse_expression(parser); + } else { + node->data.for_stmt.update = NULL; + } + _rava_parser_expect(parser, RAVA_TOKEN_RPAREN, "Expected ')' after for update"); - node->data.for_stmt.body = _rava_parser_parse_statement(parser); + node->data.for_stmt.body = _rava_parser_parse_statement(parser); + return node; + } + } + + if (_rava_parser_match(parser, RAVA_TOKEN_KEYWORD_SWITCH)) { + RavaASTNode_t *node = rava_ast_node_create(RAVA_AST_SWITCH_STMT, + parser->current_token->line, + parser->current_token->column); + + _rava_parser_expect(parser, RAVA_TOKEN_LPAREN, "Expected '(' after 'switch'"); + node->data.switch_stmt.expression = _rava_parser_parse_expression(parser); + _rava_parser_expect(parser, RAVA_TOKEN_RPAREN, "Expected ')' after switch expression"); + _rava_parser_expect(parser, RAVA_TOKEN_LBRACE, "Expected '{' after switch"); + + while (!_rava_parser_check(parser, RAVA_TOKEN_RBRACE) && + !_rava_parser_check(parser, RAVA_TOKEN_EOF)) { + + if (_rava_parser_match(parser, RAVA_TOKEN_KEYWORD_CASE)) { + RavaASTNode_t *case_node = rava_ast_node_create(RAVA_AST_CASE_STMT, + parser->current_token->line, + parser->current_token->column); + case_node->data.case_stmt.is_default = false; + case_node->data.case_stmt.value = _rava_parser_parse_expression(parser); + _rava_parser_expect(parser, RAVA_TOKEN_COLON, "Expected ':' after case value"); + + while (!_rava_parser_check(parser, RAVA_TOKEN_KEYWORD_CASE) && + !_rava_parser_check(parser, RAVA_TOKEN_KEYWORD_DEFAULT) && + !_rava_parser_check(parser, RAVA_TOKEN_RBRACE) && + !_rava_parser_check(parser, RAVA_TOKEN_EOF)) { + RavaASTNode_t *stmt = _rava_parser_parse_statement(parser); + if (stmt) { + rava_ast_node_add_child(case_node, stmt); + } + } + + rava_ast_node_add_child(node, case_node); + + } else if (_rava_parser_match(parser, RAVA_TOKEN_KEYWORD_DEFAULT)) { + RavaASTNode_t *default_node = rava_ast_node_create(RAVA_AST_CASE_STMT, + parser->current_token->line, + parser->current_token->column); + default_node->data.case_stmt.is_default = true; + default_node->data.case_stmt.value = NULL; + _rava_parser_expect(parser, RAVA_TOKEN_COLON, "Expected ':' after default"); + + while (!_rava_parser_check(parser, RAVA_TOKEN_KEYWORD_CASE) && + !_rava_parser_check(parser, RAVA_TOKEN_KEYWORD_DEFAULT) && + !_rava_parser_check(parser, RAVA_TOKEN_RBRACE) && + !_rava_parser_check(parser, RAVA_TOKEN_EOF)) { + RavaASTNode_t *stmt = _rava_parser_parse_statement(parser); + if (stmt) { + rava_ast_node_add_child(default_node, stmt); + } + } + + rava_ast_node_add_child(node, default_node); + } else { + break; + } + } + + _rava_parser_expect(parser, RAVA_TOKEN_RBRACE, "Expected '}' at end of switch"); return node; } @@ -165,6 +294,65 @@ RavaASTNode_t* _rava_parser_parse_statement(RavaParser_t *parser) { return node; } + if (_rava_parser_match(parser, RAVA_TOKEN_KEYWORD_THROW)) { + RavaASTNode_t *node = rava_ast_node_create(RAVA_AST_THROW_STMT, + parser->current_token->line, + parser->current_token->column); + node->data.throw_stmt.expression = _rava_parser_parse_expression(parser); + _rava_parser_expect(parser, RAVA_TOKEN_SEMICOLON, "Expected ';' after throw"); + return node; + } + + if (_rava_parser_match(parser, RAVA_TOKEN_KEYWORD_TRY)) { + RavaASTNode_t *node = rava_ast_node_create(RAVA_AST_TRY_STMT, + parser->current_token->line, + parser->current_token->column); + + node->data.try_stmt.try_block = _rava_parser_parse_block(parser); + node->data.try_stmt.catch_clauses = NULL; + node->data.try_stmt.catch_count = 0; + node->data.try_stmt.finally_block = NULL; + + size_t capacity = 4; + node->data.try_stmt.catch_clauses = malloc(capacity * sizeof(RavaASTNode_t*)); + + while (_rava_parser_match(parser, RAVA_TOKEN_KEYWORD_CATCH)) { + RavaASTNode_t *catch_node = rava_ast_node_create(RAVA_AST_CATCH_CLAUSE, + parser->current_token->line, + parser->current_token->column); + + _rava_parser_expect(parser, RAVA_TOKEN_LPAREN, "Expected '(' after catch"); + + if (_rava_parser_check(parser, RAVA_TOKEN_IDENTIFIER)) { + catch_node->data.catch_clause.exception_type = strdup(parser->current_token->lexeme); + _rava_parser_advance(parser); + } + + if (_rava_parser_check(parser, RAVA_TOKEN_IDENTIFIER)) { + catch_node->data.catch_clause.exception_name = strdup(parser->current_token->lexeme); + _rava_parser_advance(parser); + } + + _rava_parser_expect(parser, RAVA_TOKEN_RPAREN, "Expected ')' after catch parameter"); + + catch_node->data.catch_clause.body = _rava_parser_parse_block(parser); + + if (node->data.try_stmt.catch_count >= capacity) { + capacity *= 2; + node->data.try_stmt.catch_clauses = realloc( + node->data.try_stmt.catch_clauses, + capacity * sizeof(RavaASTNode_t*)); + } + node->data.try_stmt.catch_clauses[node->data.try_stmt.catch_count++] = catch_node; + } + + if (_rava_parser_match(parser, RAVA_TOKEN_KEYWORD_FINALLY)) { + node->data.try_stmt.finally_block = _rava_parser_parse_block(parser); + } + + return node; + } + bool is_type_decl = false; if (_rava_parser_check(parser, RAVA_TOKEN_KEYWORD_INT) || _rava_parser_check(parser, RAVA_TOKEN_KEYWORD_BOOLEAN) || @@ -194,7 +382,11 @@ RavaASTNode_t* _rava_parser_parse_statement(RavaParser_t *parser) { } if (_rava_parser_match(parser, RAVA_TOKEN_ASSIGN)) { - var_decl->data.var_decl.initializer = _rava_parser_parse_expression(parser); + if (_rava_parser_check(parser, RAVA_TOKEN_LBRACE)) { + var_decl->data.var_decl.initializer = _rava_parser_parse_array_initializer(parser); + } else { + var_decl->data.var_decl.initializer = _rava_parser_parse_expression(parser); + } } else { var_decl->data.var_decl.initializer = NULL; } diff --git a/runtime/runtime.c b/runtime/runtime.c index b685adb..b31d7c5 100644 --- a/runtime/runtime.c +++ b/runtime/runtime.c @@ -9,6 +9,8 @@ #include #include #include +#include +#include #define STACK_ENSURE_CAPACITY(stack) do { \ if ((stack)->top >= (stack)->capacity) { \ @@ -461,6 +463,34 @@ static void rava_static_field_table_set(RavaStaticFieldTable_t *table, table->count++; } +static RavaExceptionStack_t* rava_exception_stack_create() { + RavaExceptionStack_t *stack = calloc(1, sizeof(RavaExceptionStack_t)); + stack->capacity = 16; + stack->handlers = calloc(stack->capacity, sizeof(RavaExceptionHandler_t)); + stack->count = 0; + return stack; +} + +static void rava_exception_stack_destroy(RavaExceptionStack_t *stack) { + if (!stack) return; + free(stack->handlers); + free(stack); +} + +static void rava_exception_stack_push(RavaExceptionStack_t *stack, RavaExceptionHandler_t handler) { + if (stack->count >= stack->capacity) { + stack->capacity *= 2; + stack->handlers = realloc(stack->handlers, stack->capacity * sizeof(RavaExceptionHandler_t)); + } + stack->handlers[stack->count++] = handler; +} + +static bool rava_exception_stack_pop(RavaExceptionStack_t *stack, RavaExceptionHandler_t *handler) { + if (stack->count == 0) return false; + *handler = stack->handlers[--stack->count]; + return true; +} + RavaVM_t* rava_vm_create(RavaProgram_t *program) { RavaVM_t *vm = calloc(1, sizeof(RavaVM_t)); vm->program = program; @@ -469,6 +499,9 @@ RavaVM_t* rava_vm_create(RavaProgram_t *program) { vm->method_cache = rava_methodcache_create(); vm->error_message = NULL; vm->had_error = false; + vm->has_exception = false; + vm->exception_value = rava_value_null(); + vm->exception_stack = rava_exception_stack_create(); return vm; } @@ -479,6 +512,7 @@ void rava_vm_destroy(RavaVM_t *vm) { if (vm->method_cache) { rava_methodcache_destroy((MethodCache_t*)vm->method_cache); } + rava_exception_stack_destroy(vm->exception_stack); free(vm->error_message); free(vm); } @@ -732,14 +766,14 @@ static bool _rava_vm_execute_instruction(RavaVM_t *vm, RavaCallFrame_t *frame, R case RAVA_OP_AND: { RavaValue_t b = rava_stack_pop(stack); RavaValue_t a = rava_stack_pop(stack); - rava_stack_push(stack, rava_value_boolean(rava_value_as_boolean(a) && rava_value_as_boolean(b))); + rava_stack_push(stack, rava_value_int(rava_value_as_int(a) & rava_value_as_int(b))); break; } case RAVA_OP_OR: { RavaValue_t b = rava_stack_pop(stack); RavaValue_t a = rava_stack_pop(stack); - rava_stack_push(stack, rava_value_boolean(rava_value_as_boolean(a) || rava_value_as_boolean(b))); + rava_stack_push(stack, rava_value_int(rava_value_as_int(a) | rava_value_as_int(b))); break; } @@ -900,10 +934,95 @@ static bool _rava_vm_execute_instruction(RavaVM_t *vm, RavaCallFrame_t *frame, R break; } + case RAVA_OP_CALL_SUPER: { + RavaValue_t args[16]; + for (int i = instr->operand.call.arg_count - 1; i >= 0; i--) { + args[i] = rava_stack_pop(stack); + } + RavaValue_t obj_val = rava_stack_pop(stack); + const char *super_class = instr->operand.call.class_name; + + RavaMethod_t *method = _rava_vm_find_method_cached(vm, super_class, instr->operand.call.method_name); + if (!method) { + vm->had_error = true; + vm->error_message = malloc(256); + snprintf(vm->error_message, 256, "Super method not found: %s.%s", + super_class, instr->operand.call.method_name); + return false; + } + + RavaCallFrame_t *new_frame = rava_call_frame_create(method); + new_frame->has_this = true; + new_frame->this_ref = obj_val; + + for (int i = 0; i < instr->operand.call.arg_count; i++) { + new_frame->locals[i] = args[i]; + } + + rava_call_stack_push(vm->call_stack, new_frame); + + while (new_frame->pc < new_frame->method->instructions->count) { + RavaInstruction_t *next_instr = &new_frame->method->instructions->instructions[new_frame->pc]; + + if (next_instr->opcode == RAVA_OP_RETURN || next_instr->opcode == RAVA_OP_RETURN_VOID) { + RavaValue_t result = rava_value_int(0); + if (next_instr->opcode == RAVA_OP_RETURN && !rava_stack_is_empty(new_frame->operand_stack)) { + result = rava_stack_pop(new_frame->operand_stack); + } + + rava_call_stack_pop(vm->call_stack); + rava_call_frame_destroy(new_frame); + + if (next_instr->opcode == RAVA_OP_RETURN) { + rava_stack_push(stack, result); + } + break; + } + + new_frame->pc++; + if (!_rava_vm_execute_instruction(vm, new_frame, next_instr)) { + return false; + } + } + break; + } + case RAVA_OP_RETURN: case RAVA_OP_RETURN_VOID: return true; + case RAVA_OP_THROW: { + RavaValue_t exception = rava_stack_pop(stack); + vm->has_exception = true; + vm->exception_value = exception; + RavaExceptionHandler_t handler; + if (rava_exception_stack_pop(vm->exception_stack, &handler)) { + locals[handler.exception_local] = exception; + pc = label_table_lookup(method->label_table, handler.catch_label); + vm->has_exception = false; + } else { + return false; + } + break; + } + + case RAVA_OP_TRY_BEGIN: { + RavaExceptionHandler_t handler; + handler.catch_label = instr->operand.try_handler.catch_label; + handler.finally_label = instr->operand.try_handler.finally_label; + handler.end_label = instr->operand.try_handler.end_label; + handler.exception_local = instr->operand.try_handler.exception_local; + handler.stack_depth = stack->top; + rava_exception_stack_push(vm->exception_stack, handler); + break; + } + + case RAVA_OP_TRY_END: { + RavaExceptionHandler_t handler; + rava_exception_stack_pop(vm->exception_stack, &handler); + break; + } + case RAVA_OP_POP: rava_stack_pop(stack); break; @@ -1101,9 +1220,143 @@ static bool _rava_vm_execute_instruction(RavaVM_t *vm, RavaCallFrame_t *frame, R break; } - case RAVA_OP_STRING_SUBSTRING: - case RAVA_OP_STRING_COMPARETO: + case RAVA_OP_STRING_SUBSTRING: { + RavaValue_t end_val = rava_stack_pop(stack); + RavaValue_t start_val = rava_stack_pop(stack); + RavaValue_t str_val = rava_stack_pop(stack); + if (str_val.type == RAVA_VAL_STRING && str_val.data.string_val) { + size_t len = strlen(str_val.data.string_val); + size_t start = (size_t)rava_value_as_int(start_val); + size_t end = (size_t)rava_value_as_int(end_val); + if (start > len) start = len; + if (end > len) end = len; + if (start > end) start = end; + size_t sub_len = end - start; + char *sub = malloc(sub_len + 1); + strncpy(sub, str_val.data.string_val + start, sub_len); + sub[sub_len] = '\0'; + rava_stack_push(stack, rava_value_string(sub)); + } else { + rava_stack_push(stack, rava_value_string("")); + } break; + } + + case RAVA_OP_STRING_COMPARETO: { + RavaValue_t b = rava_stack_pop(stack); + RavaValue_t a = rava_stack_pop(stack); + if (a.type == RAVA_VAL_STRING && b.type == RAVA_VAL_STRING && + a.data.string_val && b.data.string_val) { + rava_stack_push(stack, rava_value_int(strcmp(a.data.string_val, b.data.string_val))); + } else { + rava_stack_push(stack, rava_value_int(0)); + } + break; + } + + case RAVA_OP_STRING_INDEXOF: { + RavaValue_t needle_val = rava_stack_pop(stack); + RavaValue_t str_val = rava_stack_pop(stack); + if (str_val.type == RAVA_VAL_STRING && str_val.data.string_val && + needle_val.type == RAVA_VAL_STRING && needle_val.data.string_val) { + const char *found = strstr(str_val.data.string_val, needle_val.data.string_val); + rava_stack_push(stack, rava_value_int(found ? (int32_t)(found - str_val.data.string_val) : -1)); + } else { + rava_stack_push(stack, rava_value_int(-1)); + } + break; + } + + case RAVA_OP_STRING_CONTAINS: { + RavaValue_t needle_val = rava_stack_pop(stack); + RavaValue_t str_val = rava_stack_pop(stack); + if (str_val.type == RAVA_VAL_STRING && str_val.data.string_val && + needle_val.type == RAVA_VAL_STRING && needle_val.data.string_val) { + rava_stack_push(stack, rava_value_boolean(strstr(str_val.data.string_val, needle_val.data.string_val) != NULL)); + } else { + rava_stack_push(stack, rava_value_boolean(false)); + } + break; + } + + case RAVA_OP_STRING_STARTSWITH: { + RavaValue_t prefix_val = rava_stack_pop(stack); + RavaValue_t str_val = rava_stack_pop(stack); + if (str_val.type == RAVA_VAL_STRING && str_val.data.string_val && + prefix_val.type == RAVA_VAL_STRING && prefix_val.data.string_val) { + size_t plen = strlen(prefix_val.data.string_val); + rava_stack_push(stack, rava_value_boolean(strncmp(str_val.data.string_val, prefix_val.data.string_val, plen) == 0)); + } else { + rava_stack_push(stack, rava_value_boolean(false)); + } + break; + } + + case RAVA_OP_STRING_ENDSWITH: { + RavaValue_t suffix_val = rava_stack_pop(stack); + RavaValue_t str_val = rava_stack_pop(stack); + if (str_val.type == RAVA_VAL_STRING && str_val.data.string_val && + suffix_val.type == RAVA_VAL_STRING && suffix_val.data.string_val) { + size_t slen = strlen(str_val.data.string_val); + size_t suflen = strlen(suffix_val.data.string_val); + if (suflen <= slen) { + rava_stack_push(stack, rava_value_boolean(strcmp(str_val.data.string_val + slen - suflen, suffix_val.data.string_val) == 0)); + } else { + rava_stack_push(stack, rava_value_boolean(false)); + } + } else { + rava_stack_push(stack, rava_value_boolean(false)); + } + break; + } + + case RAVA_OP_STRING_TOLOWERCASE: { + RavaValue_t str_val = rava_stack_pop(stack); + if (str_val.type == RAVA_VAL_STRING && str_val.data.string_val) { + size_t len = strlen(str_val.data.string_val); + char *lower = malloc(len + 1); + for (size_t i = 0; i <= len; i++) { + lower[i] = (char)tolower((unsigned char)str_val.data.string_val[i]); + } + rava_stack_push(stack, rava_value_string(lower)); + } else { + rava_stack_push(stack, rava_value_string("")); + } + break; + } + + case RAVA_OP_STRING_TOUPPERCASE: { + RavaValue_t str_val = rava_stack_pop(stack); + if (str_val.type == RAVA_VAL_STRING && str_val.data.string_val) { + size_t len = strlen(str_val.data.string_val); + char *upper = malloc(len + 1); + for (size_t i = 0; i <= len; i++) { + upper[i] = (char)toupper((unsigned char)str_val.data.string_val[i]); + } + rava_stack_push(stack, rava_value_string(upper)); + } else { + rava_stack_push(stack, rava_value_string("")); + } + break; + } + + case RAVA_OP_STRING_TRIM: { + RavaValue_t str_val = rava_stack_pop(stack); + if (str_val.type == RAVA_VAL_STRING && str_val.data.string_val) { + const char *start = str_val.data.string_val; + while (*start && isspace((unsigned char)*start)) start++; + const char *end = str_val.data.string_val + strlen(str_val.data.string_val); + while (end > start && isspace((unsigned char)*(end - 1))) end--; + size_t len = (size_t)(end - start); + char *trimmed = malloc(len + 1); + strncpy(trimmed, start, len); + trimmed[len] = '\0'; + rava_stack_push(stack, rava_value_string(trimmed)); + } else { + rava_stack_push(stack, rava_value_string("")); + } + break; + } case RAVA_OP_FILE_READ: { RavaValue_t path_val = rava_stack_pop(stack); @@ -1194,6 +1447,170 @@ static bool _rava_vm_execute_instruction(RavaVM_t *vm, RavaCallFrame_t *frame, R break; } + case RAVA_OP_MATH_ABS: { + RavaValue_t val = rava_stack_pop(stack); + if (val.type == RAVA_VAL_DOUBLE) { + rava_stack_push(stack, rava_value_double(fabs(val.data.double_val))); + } else if (val.type == RAVA_VAL_LONG) { + int64_t v = val.data.long_val; + rava_stack_push(stack, rava_value_long(v < 0 ? -v : v)); + } else { + int32_t v = rava_value_as_int(val); + rava_stack_push(stack, rava_value_int(v < 0 ? -v : v)); + } + break; + } + + case RAVA_OP_MATH_SQRT: { + RavaValue_t val = rava_stack_pop(stack); + double d = (val.type == RAVA_VAL_DOUBLE) ? val.data.double_val : (double)rava_value_as_int(val); + rava_stack_push(stack, rava_value_double(sqrt(d))); + break; + } + + case RAVA_OP_MATH_POW: { + RavaValue_t exp = rava_stack_pop(stack); + RavaValue_t base = rava_stack_pop(stack); + double b = (base.type == RAVA_VAL_DOUBLE) ? base.data.double_val : (double)rava_value_as_int(base); + double e = (exp.type == RAVA_VAL_DOUBLE) ? exp.data.double_val : (double)rava_value_as_int(exp); + rava_stack_push(stack, rava_value_double(pow(b, e))); + break; + } + + case RAVA_OP_MATH_MIN: { + RavaValue_t b = rava_stack_pop(stack); + RavaValue_t a = rava_stack_pop(stack); + if (a.type == RAVA_VAL_DOUBLE || b.type == RAVA_VAL_DOUBLE) { + double da = (a.type == RAVA_VAL_DOUBLE) ? a.data.double_val : (double)rava_value_as_int(a); + double db = (b.type == RAVA_VAL_DOUBLE) ? b.data.double_val : (double)rava_value_as_int(b); + rava_stack_push(stack, rava_value_double(da < db ? da : db)); + } else { + int32_t ia = rava_value_as_int(a); + int32_t ib = rava_value_as_int(b); + rava_stack_push(stack, rava_value_int(ia < ib ? ia : ib)); + } + break; + } + + case RAVA_OP_MATH_MAX: { + RavaValue_t b = rava_stack_pop(stack); + RavaValue_t a = rava_stack_pop(stack); + if (a.type == RAVA_VAL_DOUBLE || b.type == RAVA_VAL_DOUBLE) { + double da = (a.type == RAVA_VAL_DOUBLE) ? a.data.double_val : (double)rava_value_as_int(a); + double db = (b.type == RAVA_VAL_DOUBLE) ? b.data.double_val : (double)rava_value_as_int(b); + rava_stack_push(stack, rava_value_double(da > db ? da : db)); + } else { + int32_t ia = rava_value_as_int(a); + int32_t ib = rava_value_as_int(b); + rava_stack_push(stack, rava_value_int(ia > ib ? ia : ib)); + } + break; + } + + case RAVA_OP_MATH_FLOOR: { + RavaValue_t val = rava_stack_pop(stack); + double d = (val.type == RAVA_VAL_DOUBLE) ? val.data.double_val : (double)rava_value_as_int(val); + rava_stack_push(stack, rava_value_double(floor(d))); + break; + } + + case RAVA_OP_MATH_CEIL: { + RavaValue_t val = rava_stack_pop(stack); + double d = (val.type == RAVA_VAL_DOUBLE) ? val.data.double_val : (double)rava_value_as_int(val); + rava_stack_push(stack, rava_value_double(ceil(d))); + break; + } + + case RAVA_OP_MATH_ROUND: { + RavaValue_t val = rava_stack_pop(stack); + double d = (val.type == RAVA_VAL_DOUBLE) ? val.data.double_val : (double)rava_value_as_int(val); + rava_stack_push(stack, rava_value_long((int64_t)round(d))); + break; + } + + case RAVA_OP_MATH_SIN: { + RavaValue_t val = rava_stack_pop(stack); + double d = (val.type == RAVA_VAL_DOUBLE) ? val.data.double_val : (double)rava_value_as_int(val); + rava_stack_push(stack, rava_value_double(sin(d))); + break; + } + + case RAVA_OP_MATH_COS: { + RavaValue_t val = rava_stack_pop(stack); + double d = (val.type == RAVA_VAL_DOUBLE) ? val.data.double_val : (double)rava_value_as_int(val); + rava_stack_push(stack, rava_value_double(cos(d))); + break; + } + + case RAVA_OP_MATH_TAN: { + RavaValue_t val = rava_stack_pop(stack); + double d = (val.type == RAVA_VAL_DOUBLE) ? val.data.double_val : (double)rava_value_as_int(val); + rava_stack_push(stack, rava_value_double(tan(d))); + break; + } + + case RAVA_OP_MATH_LOG: { + RavaValue_t val = rava_stack_pop(stack); + double d = (val.type == RAVA_VAL_DOUBLE) ? val.data.double_val : (double)rava_value_as_int(val); + rava_stack_push(stack, rava_value_double(log(d))); + break; + } + + case RAVA_OP_MATH_EXP: { + RavaValue_t val = rava_stack_pop(stack); + double d = (val.type == RAVA_VAL_DOUBLE) ? val.data.double_val : (double)rava_value_as_int(val); + rava_stack_push(stack, rava_value_double(exp(d))); + break; + } + + case RAVA_OP_MATH_RANDOM: { + rava_stack_push(stack, rava_value_double((double)rand() / (double)RAND_MAX)); + break; + } + + case RAVA_OP_CAST: { + RavaValue_t val = rava_stack_pop(stack); + RavaType_t *target_type = instr->operand.var.type; + if (target_type) { + switch (target_type->kind) { + case RAVA_TYPE_INT: + if (val.type == RAVA_VAL_DOUBLE) { + rava_stack_push(stack, rava_value_int((int32_t)val.data.double_val)); + } else if (val.type == RAVA_VAL_LONG) { + rava_stack_push(stack, rava_value_int((int32_t)val.data.long_val)); + } else { + rava_stack_push(stack, val); + } + break; + case RAVA_TYPE_LONG: + if (val.type == RAVA_VAL_DOUBLE) { + rava_stack_push(stack, rava_value_long((int64_t)val.data.double_val)); + } else if (val.type == RAVA_VAL_INT) { + rava_stack_push(stack, rava_value_long((int64_t)rava_value_as_int(val))); + } else { + rava_stack_push(stack, val); + } + break; + case RAVA_TYPE_DOUBLE: + case RAVA_TYPE_FLOAT: + if (val.type == RAVA_VAL_INT) { + rava_stack_push(stack, rava_value_double((double)rava_value_as_int(val))); + } else if (val.type == RAVA_VAL_LONG) { + rava_stack_push(stack, rava_value_double((double)val.data.long_val)); + } else { + rava_stack_push(stack, val); + } + break; + default: + rava_stack_push(stack, val); + break; + } + } else { + rava_stack_push(stack, val); + } + break; + } + default: break; } @@ -1214,21 +1631,28 @@ static bool _rava_vm_execute_fast(RavaVM_t *vm, RavaCallFrame_t *frame) { &&op_and, &&op_or, &&op_xor, &&op_not, &&op_shl, &&op_shr, &&op_ushr, &&op_eq, &&op_ne, &&op_lt, &&op_le, &&op_gt, &&op_ge, &&op_jump, &&op_jump_if_true, &&op_jump_if_false, &&op_label, - &&op_call, &&op_call_static, &&op_call_virtual, &&op_call_native, + &&op_call, &&op_call_static, &&op_call_virtual, &&op_call_super, &&op_call_native, &&op_return, &&op_return_void, &&op_new, &&op_new_array, &&op_array_length, &&op_get_field, &&op_put_field, &&op_cast, &&op_instanceof, - &&op_throw, &&op_pop, &&op_dup, + &&op_throw, &&op_try_begin, &&op_try_end, &&op_pop, &&op_dup, &&op_print, &&op_println, &&op_string_length, &&op_string_charat, &&op_string_substring, &&op_string_equals, &&op_string_compareto, + &&op_string_indexof, &&op_string_contains, &&op_string_startswith, + &&op_string_endswith, &&op_string_tolowercase, &&op_string_touppercase, + &&op_string_trim, &&op_load_this, &&op_file_read, &&op_file_write, &&op_file_exists, &&op_file_delete, &&op_current_time_millis, &&op_nano_time, &&op_inc_local, &&op_dec_local, &&op_load_local_const_add, &&op_load_local_const_lt_jumpfalse, &&op_load_local_const_le_jumpfalse, &&op_load_two_locals, - &&op_add_local_to_local, &&op_load_local_lt_local_jumpfalse + &&op_add_local_to_local, &&op_load_local_lt_local_jumpfalse, + &&op_math_abs, &&op_math_sqrt, &&op_math_pow, &&op_math_min, &&op_math_max, + &&op_math_floor, &&op_math_ceil, &&op_math_round, + &&op_math_sin, &&op_math_cos, &&op_math_tan, &&op_math_log, &&op_math_exp, + &&op_math_random }; RavaStack_t *stack = frame->operand_stack; @@ -1693,6 +2117,39 @@ op_call_virtual: { DISPATCH(); } +op_call_super: { + frame->pc = pc; + const char *super_class = instr->operand.call.class_name; + RavaMethod_t *target_method = _rava_vm_find_method_cached(vm, super_class, instr->operand.call.method_name); + if (!target_method) { + vm->had_error = true; + vm->error_message = malloc(256); + snprintf(vm->error_message, 256, "Super method not found: %s.%s", + super_class, instr->operand.call.method_name); + goto done; + } + RavaCallFrame_t *new_frame = rava_call_frame_create(target_method); + new_frame->has_this = true; + RavaValue_t args[16]; + for (int i = instr->operand.call.arg_count - 1; i >= 0; i--) { + args[i] = STACK_POP(stack); + } + new_frame->this_ref = STACK_POP(stack); + for (int i = 0; i < instr->operand.call.arg_count; i++) { + new_frame->locals[i] = args[i]; + } + rava_call_stack_push(vm->call_stack, new_frame); + if (!_rava_vm_execute_fast(vm, new_frame)) { + goto done; + } + if (!rava_stack_is_empty(new_frame->operand_stack)) { + STACK_PUSH(stack, rava_stack_pop(new_frame->operand_stack)); + } + rava_call_stack_pop(vm->call_stack); + rava_call_frame_destroy(new_frame); + DISPATCH(); +} + op_call_native: DISPATCH(); @@ -1745,10 +2202,105 @@ op_put_field: { DISPATCH(); } -op_cast: -op_instanceof: -op_throw: +op_cast: { + RavaValue_t val = STACK_POP(stack); + RavaType_t *target_type = instr->operand.var.type; + if (target_type) { + switch (target_type->kind) { + case RAVA_TYPE_INT: + if (val.type == RAVA_VAL_DOUBLE) { + STACK_PUSH_INT(stack, (int32_t)val.data.double_val); + } else if (val.type == RAVA_VAL_LONG) { + STACK_PUSH_INT(stack, (int32_t)val.data.long_val); + } else { + STACK_PUSH(stack, val); + } + break; + case RAVA_TYPE_LONG: + if (val.type == RAVA_VAL_DOUBLE) { + STACK_PUSH_LONG(stack, (int64_t)val.data.double_val); + } else if (val.type == RAVA_VAL_INT) { + STACK_PUSH_LONG(stack, (int64_t)rava_value_as_int(val)); + } else { + STACK_PUSH(stack, val); + } + break; + case RAVA_TYPE_DOUBLE: { + RavaValue_t r; r.type = RAVA_VAL_DOUBLE; + if (val.type == RAVA_VAL_INT) { + r.data.double_val = (double)rava_value_as_int(val); + } else if (val.type == RAVA_VAL_LONG) { + r.data.double_val = (double)val.data.long_val; + } else { + r.data.double_val = val.data.double_val; + } + STACK_PUSH(stack, r); + break; + } + case RAVA_TYPE_FLOAT: { + RavaValue_t r; r.type = RAVA_VAL_DOUBLE; + if (val.type == RAVA_VAL_INT) { + r.data.double_val = (double)rava_value_as_int(val); + } else if (val.type == RAVA_VAL_LONG) { + r.data.double_val = (double)val.data.long_val; + } else { + r.data.double_val = val.data.double_val; + } + STACK_PUSH(stack, r); + break; + } + default: + STACK_PUSH(stack, val); + break; + } + } else { + STACK_PUSH(stack, val); + } DISPATCH(); +} + +op_instanceof: { + RavaValue_t val = STACK_POP(stack); + bool result = false; + if (val.type == RAVA_VAL_OBJECT && val.data.object_val) { + result = strcmp(val.data.object_val->class_name, instr->operand.string_value) == 0; + } + STACK_PUSH(stack, rava_value_boolean(result)); + DISPATCH(); +} + +op_throw: { + RavaValue_t exception = STACK_POP(stack); + vm->has_exception = true; + vm->exception_value = exception; + RavaExceptionHandler_t handler; + if (rava_exception_stack_pop(vm->exception_stack, &handler)) { + frame->locals[handler.exception_local] = exception; + pc = rava_labeltable_lookup(label_table, handler.catch_label); + vm->has_exception = false; + DISPATCH(); + } else { + vm->had_error = true; + goto done; + } +} + +op_try_begin: { + RavaExceptionHandler_t handler; + handler.catch_label = instr->operand.try_handler.catch_label; + handler.finally_label = instr->operand.try_handler.finally_label; + handler.end_label = instr->operand.try_handler.end_label; + handler.exception_local = instr->operand.try_handler.exception_local; + handler.stack_depth = stack->top; + rava_exception_stack_push(vm->exception_stack, handler); + DISPATCH(); +} + +op_try_end: { + RavaExceptionHandler_t handler; + rava_exception_stack_pop(vm->exception_stack, &handler); + DISPATCH(); +} op_pop: (void)STACK_POP(stack); @@ -1866,6 +2418,110 @@ op_string_compareto: { DISPATCH(); } +op_string_indexof: { + RavaValue_t needle = STACK_POP(stack); + RavaValue_t str = STACK_POP(stack); + if (str.type == RAVA_VAL_STRING && str.data.string_val && + needle.type == RAVA_VAL_STRING && needle.data.string_val) { + const char *found = strstr(str.data.string_val, needle.data.string_val); + STACK_PUSH_INT(stack, found ? (int32_t)(found - str.data.string_val) : -1); + } else { + STACK_PUSH_INT(stack, -1); + } + DISPATCH(); +} + +op_string_contains: { + RavaValue_t needle = STACK_POP(stack); + RavaValue_t str = STACK_POP(stack); + if (str.type == RAVA_VAL_STRING && str.data.string_val && + needle.type == RAVA_VAL_STRING && needle.data.string_val) { + STACK_PUSH_BOOL(stack, strstr(str.data.string_val, needle.data.string_val) != NULL); + } else { + STACK_PUSH_BOOL(stack, false); + } + DISPATCH(); +} + +op_string_startswith: { + RavaValue_t prefix = STACK_POP(stack); + RavaValue_t str = STACK_POP(stack); + if (str.type == RAVA_VAL_STRING && str.data.string_val && + prefix.type == RAVA_VAL_STRING && prefix.data.string_val) { + size_t plen = strlen(prefix.data.string_val); + STACK_PUSH_BOOL(stack, strncmp(str.data.string_val, prefix.data.string_val, plen) == 0); + } else { + STACK_PUSH_BOOL(stack, false); + } + DISPATCH(); +} + +op_string_endswith: { + RavaValue_t suffix = STACK_POP(stack); + RavaValue_t str = STACK_POP(stack); + if (str.type == RAVA_VAL_STRING && str.data.string_val && + suffix.type == RAVA_VAL_STRING && suffix.data.string_val) { + size_t slen = strlen(str.data.string_val); + size_t suflen = strlen(suffix.data.string_val); + if (suflen <= slen) { + STACK_PUSH_BOOL(stack, strcmp(str.data.string_val + slen - suflen, suffix.data.string_val) == 0); + } else { + STACK_PUSH_BOOL(stack, false); + } + } else { + STACK_PUSH_BOOL(stack, false); + } + DISPATCH(); +} + +op_string_tolowercase: { + RavaValue_t str = STACK_POP(stack); + if (str.type == RAVA_VAL_STRING && str.data.string_val) { + size_t len = strlen(str.data.string_val); + char *lower = malloc(len + 1); + for (size_t i = 0; i <= len; i++) { + lower[i] = (char)tolower((unsigned char)str.data.string_val[i]); + } + STACK_PUSH(stack, rava_value_string(lower)); + } else { + STACK_PUSH(stack, rava_value_string("")); + } + DISPATCH(); +} + +op_string_touppercase: { + RavaValue_t str = STACK_POP(stack); + if (str.type == RAVA_VAL_STRING && str.data.string_val) { + size_t len = strlen(str.data.string_val); + char *upper = malloc(len + 1); + for (size_t i = 0; i <= len; i++) { + upper[i] = (char)toupper((unsigned char)str.data.string_val[i]); + } + STACK_PUSH(stack, rava_value_string(upper)); + } else { + STACK_PUSH(stack, rava_value_string("")); + } + DISPATCH(); +} + +op_string_trim: { + RavaValue_t str = STACK_POP(stack); + if (str.type == RAVA_VAL_STRING && str.data.string_val) { + const char *start = str.data.string_val; + while (*start && isspace((unsigned char)*start)) start++; + const char *end = str.data.string_val + strlen(str.data.string_val); + while (end > start && isspace((unsigned char)*(end - 1))) end--; + size_t len = (size_t)(end - start); + char *trimmed = malloc(len + 1); + strncpy(trimmed, start, len); + trimmed[len] = '\0'; + STACK_PUSH(stack, rava_value_string(trimmed)); + } else { + STACK_PUSH(stack, rava_value_string("")); + } + DISPATCH(); +} + op_load_this: if (frame->has_this) { STACK_PUSH(stack, frame->this_ref); @@ -2050,6 +2706,140 @@ op_load_local_lt_local_jumpfalse: { DISPATCH(); } +op_math_abs: { + RavaValue_t val = STACK_POP(stack); + if (val.type == RAVA_VAL_DOUBLE) { + RavaValue_t r; r.type = RAVA_VAL_DOUBLE; r.data.double_val = fabs(val.data.double_val); + STACK_PUSH(stack, r); + } else if (val.type == RAVA_VAL_LONG) { + int64_t v = val.data.long_val; + STACK_PUSH_LONG(stack, v < 0 ? -v : v); + } else { + int32_t v = rava_value_as_int(val); + STACK_PUSH_INT(stack, v < 0 ? -v : v); + } + DISPATCH(); +} + +op_math_sqrt: { + RavaValue_t val = STACK_POP(stack); + double d = (val.type == RAVA_VAL_DOUBLE) ? val.data.double_val : (double)rava_value_as_int(val); + RavaValue_t r; r.type = RAVA_VAL_DOUBLE; r.data.double_val = sqrt(d); + STACK_PUSH(stack, r); + DISPATCH(); +} + +op_math_pow: { + RavaValue_t exp = STACK_POP(stack); + RavaValue_t base = STACK_POP(stack); + double b = (base.type == RAVA_VAL_DOUBLE) ? base.data.double_val : (double)rava_value_as_int(base); + double e = (exp.type == RAVA_VAL_DOUBLE) ? exp.data.double_val : (double)rava_value_as_int(exp); + RavaValue_t r; r.type = RAVA_VAL_DOUBLE; r.data.double_val = pow(b, e); + STACK_PUSH(stack, r); + DISPATCH(); +} + +op_math_min: { + RavaValue_t b = STACK_POP(stack); + RavaValue_t a = STACK_POP(stack); + if (a.type == RAVA_VAL_DOUBLE || b.type == RAVA_VAL_DOUBLE) { + double da = (a.type == RAVA_VAL_DOUBLE) ? a.data.double_val : (double)rava_value_as_int(a); + double db = (b.type == RAVA_VAL_DOUBLE) ? b.data.double_val : (double)rava_value_as_int(b); + RavaValue_t r; r.type = RAVA_VAL_DOUBLE; r.data.double_val = da < db ? da : db; + STACK_PUSH(stack, r); + } else { + int32_t ia = rava_value_as_int(a); + int32_t ib = rava_value_as_int(b); + STACK_PUSH_INT(stack, ia < ib ? ia : ib); + } + DISPATCH(); +} + +op_math_max: { + RavaValue_t b = STACK_POP(stack); + RavaValue_t a = STACK_POP(stack); + if (a.type == RAVA_VAL_DOUBLE || b.type == RAVA_VAL_DOUBLE) { + double da = (a.type == RAVA_VAL_DOUBLE) ? a.data.double_val : (double)rava_value_as_int(a); + double db = (b.type == RAVA_VAL_DOUBLE) ? b.data.double_val : (double)rava_value_as_int(b); + RavaValue_t r; r.type = RAVA_VAL_DOUBLE; r.data.double_val = da > db ? da : db; + STACK_PUSH(stack, r); + } else { + int32_t ia = rava_value_as_int(a); + int32_t ib = rava_value_as_int(b); + STACK_PUSH_INT(stack, ia > ib ? ia : ib); + } + DISPATCH(); +} + +op_math_floor: { + RavaValue_t val = STACK_POP(stack); + double d = (val.type == RAVA_VAL_DOUBLE) ? val.data.double_val : (double)rava_value_as_int(val); + RavaValue_t r; r.type = RAVA_VAL_DOUBLE; r.data.double_val = floor(d); + STACK_PUSH(stack, r); + DISPATCH(); +} + +op_math_ceil: { + RavaValue_t val = STACK_POP(stack); + double d = (val.type == RAVA_VAL_DOUBLE) ? val.data.double_val : (double)rava_value_as_int(val); + RavaValue_t r; r.type = RAVA_VAL_DOUBLE; r.data.double_val = ceil(d); + STACK_PUSH(stack, r); + DISPATCH(); +} + +op_math_round: { + RavaValue_t val = STACK_POP(stack); + double d = (val.type == RAVA_VAL_DOUBLE) ? val.data.double_val : (double)rava_value_as_int(val); + STACK_PUSH_LONG(stack, (int64_t)round(d)); + DISPATCH(); +} + +op_math_sin: { + RavaValue_t val = STACK_POP(stack); + double d = (val.type == RAVA_VAL_DOUBLE) ? val.data.double_val : (double)rava_value_as_int(val); + RavaValue_t r; r.type = RAVA_VAL_DOUBLE; r.data.double_val = sin(d); + STACK_PUSH(stack, r); + DISPATCH(); +} + +op_math_cos: { + RavaValue_t val = STACK_POP(stack); + double d = (val.type == RAVA_VAL_DOUBLE) ? val.data.double_val : (double)rava_value_as_int(val); + RavaValue_t r; r.type = RAVA_VAL_DOUBLE; r.data.double_val = cos(d); + STACK_PUSH(stack, r); + DISPATCH(); +} + +op_math_tan: { + RavaValue_t val = STACK_POP(stack); + double d = (val.type == RAVA_VAL_DOUBLE) ? val.data.double_val : (double)rava_value_as_int(val); + RavaValue_t r; r.type = RAVA_VAL_DOUBLE; r.data.double_val = tan(d); + STACK_PUSH(stack, r); + DISPATCH(); +} + +op_math_log: { + RavaValue_t val = STACK_POP(stack); + double d = (val.type == RAVA_VAL_DOUBLE) ? val.data.double_val : (double)rava_value_as_int(val); + RavaValue_t r; r.type = RAVA_VAL_DOUBLE; r.data.double_val = log(d); + STACK_PUSH(stack, r); + DISPATCH(); +} + +op_math_exp: { + RavaValue_t val = STACK_POP(stack); + double d = (val.type == RAVA_VAL_DOUBLE) ? val.data.double_val : (double)rava_value_as_int(val); + RavaValue_t r; r.type = RAVA_VAL_DOUBLE; r.data.double_val = exp(d); + STACK_PUSH(stack, r); + DISPATCH(); +} + +op_math_random: { + RavaValue_t r; r.type = RAVA_VAL_DOUBLE; r.data.double_val = (double)rand() / (double)RAND_MAX; + STACK_PUSH(stack, r); + DISPATCH(); +} + done: frame->pc = pc; return !vm->had_error; @@ -2068,21 +2858,28 @@ static bool _rava_vm_execute_ultrafast(RavaVM_t *vm, RavaMethod_t *entry_method) &&uf_and, &&uf_or, &&uf_xor, &&uf_not, &&uf_shl, &&uf_shr, &&uf_ushr, &&uf_eq, &&uf_ne, &&uf_lt, &&uf_le, &&uf_gt, &&uf_ge, &&uf_jump, &&uf_jump_if_true, &&uf_jump_if_false, &&uf_label, - &&uf_call, &&uf_call_static, &&uf_call_virtual, &&uf_call_native, + &&uf_call, &&uf_call_static, &&uf_call_virtual, &&uf_call_super, &&uf_call_native, &&uf_return, &&uf_return_void, &&uf_new, &&uf_new_array, &&uf_array_length, &&uf_get_field, &&uf_put_field, &&uf_cast, &&uf_instanceof, - &&uf_throw, &&uf_pop, &&uf_dup, + &&uf_throw, &&uf_try_begin, &&uf_try_end, &&uf_pop, &&uf_dup, &&uf_print, &&uf_println, &&uf_string_length, &&uf_string_charat, &&uf_string_substring, &&uf_string_equals, &&uf_string_compareto, + &&uf_string_indexof, &&uf_string_contains, &&uf_string_startswith, + &&uf_string_endswith, &&uf_string_tolowercase, &&uf_string_touppercase, + &&uf_string_trim, &&uf_load_this, &&uf_file_read, &&uf_file_write, &&uf_file_exists, &&uf_file_delete, &&uf_current_time_millis, &&uf_nano_time, &&uf_inc_local, &&uf_dec_local, &&uf_load_local_const_add, &&uf_load_local_const_lt_jumpfalse, &&uf_load_local_const_le_jumpfalse, &&uf_load_two_locals, - &&uf_add_local_to_local, &&uf_load_local_lt_local_jumpfalse + &&uf_add_local_to_local, &&uf_load_local_lt_local_jumpfalse, + &&uf_math_abs, &&uf_math_sqrt, &&uf_math_pow, &&uf_math_min, &&uf_math_max, + &&uf_math_floor, &&uf_math_ceil, &&uf_math_round, + &&uf_math_sin, &&uf_math_cos, &&uf_math_tan, &&uf_math_log, &&uf_math_exp, + &&uf_math_random }; rava_fastframe_reset(); @@ -2219,14 +3016,14 @@ uf_neg: { uf_and: { RavaNanboxValue_t b = UF_POP(); RavaNanboxValue_t a = UF_POP(); - UF_PUSH(rava_nanbox_bool(rava_nanbox_to_bool(a) && rava_nanbox_to_bool(b))); + UF_PUSH(rava_nanbox_long(rava_nanbox_to_long(a) & rava_nanbox_to_long(b))); UF_DISPATCH(); } uf_or: { RavaNanboxValue_t b = UF_POP(); RavaNanboxValue_t a = UF_POP(); - UF_PUSH(rava_nanbox_bool(rava_nanbox_to_bool(a) || rava_nanbox_to_bool(b))); + UF_PUSH(rava_nanbox_long(rava_nanbox_to_long(a) | rava_nanbox_to_long(b))); UF_DISPATCH(); } @@ -2408,6 +3205,41 @@ uf_call_virtual: { UF_DISPATCH(); } +uf_call_super: { + int arg_count = instr->operand.call.arg_count; + RavaNanboxValue_t args[16]; + for (int i = arg_count - 1; i >= 0; i--) { + args[i] = UF_POP(); + } + RavaNanboxValue_t obj_val = UF_POP(); + const char *super_class = instr->operand.call.class_name; + RavaMethod_t *target = _rava_vm_find_method_cached(vm, super_class, instr->operand.call.method_name); + if (!target) { + vm->had_error = true; + goto uf_done; + } + if (!target->label_table) { + rava_optimize_superinstructions(target); + target->label_table = rava_labeltable_create(target->instructions); + } + frame->pc = pc; + FastFrame_t *new_frame = rava_fastframe_push(target, target->local_count); + if (!new_frame) { + vm->had_error = true; + goto uf_done; + } + new_frame->has_this = true; + new_frame->this_ref = obj_val; + for (int i = 0; i < arg_count; i++) { + new_frame->locals[i] = args[i]; + } + frame = new_frame; + instructions = target->instructions->instructions; + instr_count = target->instructions->count; + pc = 0; + UF_DISPATCH(); +} + uf_call_native: UF_DISPATCH(); @@ -2522,6 +3354,113 @@ uf_store_static: { UF_DISPATCH(); } +uf_string_indexof: { + RavaNanboxValue_t needle = UF_POP(); + RavaNanboxValue_t s = UF_POP(); + const char *str = rava_nanbox_as_string(s); + const char *nstr = rava_nanbox_as_string(needle); + if (str && nstr) { + const char *found = strstr(str, nstr); + UF_PUSH(rava_nanbox_int(found ? (int32_t)(found - str) : -1)); + } else { + UF_PUSH(rava_nanbox_int(-1)); + } + UF_DISPATCH(); +} + +uf_string_contains: { + RavaNanboxValue_t needle = UF_POP(); + RavaNanboxValue_t s = UF_POP(); + const char *str = rava_nanbox_as_string(s); + const char *nstr = rava_nanbox_as_string(needle); + UF_PUSH(rava_nanbox_bool(str && nstr && strstr(str, nstr) != NULL)); + UF_DISPATCH(); +} + +uf_string_startswith: { + RavaNanboxValue_t prefix = UF_POP(); + RavaNanboxValue_t s = UF_POP(); + const char *str = rava_nanbox_as_string(s); + const char *pstr = rava_nanbox_as_string(prefix); + if (str && pstr) { + size_t plen = strlen(pstr); + UF_PUSH(rava_nanbox_bool(strncmp(str, pstr, plen) == 0)); + } else { + UF_PUSH(rava_nanbox_bool(false)); + } + UF_DISPATCH(); +} + +uf_string_endswith: { + RavaNanboxValue_t suffix = UF_POP(); + RavaNanboxValue_t s = UF_POP(); + const char *str = rava_nanbox_as_string(s); + const char *sstr = rava_nanbox_as_string(suffix); + if (str && sstr) { + size_t slen = strlen(str); + size_t suflen = strlen(sstr); + if (suflen <= slen) { + UF_PUSH(rava_nanbox_bool(strcmp(str + slen - suflen, sstr) == 0)); + } else { + UF_PUSH(rava_nanbox_bool(false)); + } + } else { + UF_PUSH(rava_nanbox_bool(false)); + } + UF_DISPATCH(); +} + +uf_string_tolowercase: { + RavaNanboxValue_t s = UF_POP(); + const char *str = rava_nanbox_as_string(s); + if (str) { + size_t len = strlen(str); + char *lower = malloc(len + 1); + for (size_t i = 0; i <= len; i++) { + lower[i] = (char)tolower((unsigned char)str[i]); + } + UF_PUSH(rava_nanbox_string(lower)); + } else { + UF_PUSH(rava_nanbox_string("")); + } + UF_DISPATCH(); +} + +uf_string_touppercase: { + RavaNanboxValue_t s = UF_POP(); + const char *str = rava_nanbox_as_string(s); + if (str) { + size_t len = strlen(str); + char *upper = malloc(len + 1); + for (size_t i = 0; i <= len; i++) { + upper[i] = (char)toupper((unsigned char)str[i]); + } + UF_PUSH(rava_nanbox_string(upper)); + } else { + UF_PUSH(rava_nanbox_string("")); + } + UF_DISPATCH(); +} + +uf_string_trim: { + RavaNanboxValue_t s = UF_POP(); + const char *str = rava_nanbox_as_string(s); + if (str) { + const char *start = str; + while (*start && isspace((unsigned char)*start)) start++; + const char *end = str + strlen(str); + while (end > start && isspace((unsigned char)*(end - 1))) end--; + size_t len = (size_t)(end - start); + char *trimmed = malloc(len + 1); + strncpy(trimmed, start, len); + trimmed[len] = '\0'; + UF_PUSH(rava_nanbox_string(trimmed)); + } else { + UF_PUSH(rava_nanbox_string("")); + } + UF_DISPATCH(); +} + uf_load_this: if (frame->has_this) { UF_PUSH(frame->this_ref); @@ -2637,10 +3576,95 @@ uf_string_compareto: { UF_DISPATCH(); } -uf_cast: -uf_instanceof: -uf_throw: +uf_cast: { + RavaNanboxValue_t val = UF_POP(); + RavaType_t *target_type = instr->operand.var.type; + if (target_type) { + switch (target_type->kind) { + case RAVA_TYPE_INT: + if (rava_nanbox_is_double(val)) { + UF_PUSH(rava_nanbox_int((int32_t)rava_nanbox_to_double(val))); + } else if (rava_nanbox_is_long(val)) { + UF_PUSH(rava_nanbox_int((int32_t)rava_nanbox_to_long(val))); + } else { + UF_PUSH(val); + } + break; + case RAVA_TYPE_LONG: + if (rava_nanbox_is_double(val)) { + UF_PUSH(rava_nanbox_long((int64_t)rava_nanbox_to_double(val))); + } else if (rava_nanbox_is_int(val)) { + UF_PUSH(rava_nanbox_long((int64_t)rava_nanbox_to_int(val))); + } else { + UF_PUSH(val); + } + break; + case RAVA_TYPE_DOUBLE: + case RAVA_TYPE_FLOAT: + if (rava_nanbox_is_int(val)) { + UF_PUSH(rava_nanbox_double((double)rava_nanbox_to_int(val))); + } else if (rava_nanbox_is_long(val)) { + UF_PUSH(rava_nanbox_double((double)rava_nanbox_to_long(val))); + } else { + UF_PUSH(val); + } + break; + default: + UF_PUSH(val); + break; + } + } else { + UF_PUSH(val); + } UF_DISPATCH(); +} + +uf_instanceof: { + RavaNanboxValue_t val = UF_POP(); + bool result = false; + if (rava_nanbox_is_object(val)) { + RavaObject_t *obj = rava_nanbox_as_object(val); + if (obj) { + result = strcmp(obj->class_name, instr->operand.string_value) == 0; + } + } + UF_PUSH(rava_nanbox_bool(result)); + UF_DISPATCH(); +} + +uf_throw: { + RavaNanboxValue_t exception = UF_POP(); + vm->has_exception = true; + vm->exception_value = rava_nanbox_to_value(exception); + RavaExceptionHandler_t handler; + if (rava_exception_stack_pop(vm->exception_stack, &handler)) { + frame->locals[handler.exception_local] = exception; + LabelTable_t *lt = (LabelTable_t*)frame->method->label_table; + pc = rava_labeltable_lookup(lt, handler.catch_label); + vm->has_exception = false; + UF_DISPATCH(); + } else { + vm->had_error = true; + goto uf_done; + } +} + +uf_try_begin: { + RavaExceptionHandler_t handler; + handler.catch_label = instr->operand.try_handler.catch_label; + handler.finally_label = instr->operand.try_handler.finally_label; + handler.end_label = instr->operand.try_handler.end_label; + handler.exception_local = instr->operand.try_handler.exception_local; + handler.stack_depth = frame->stack_top; + rava_exception_stack_push(vm->exception_stack, handler); + UF_DISPATCH(); +} + +uf_try_end: { + RavaExceptionHandler_t handler; + rava_exception_stack_pop(vm->exception_stack, &handler); + UF_DISPATCH(); +} uf_file_read: uf_file_write: @@ -2758,6 +3782,125 @@ uf_load_local_lt_local_jumpfalse: { UF_DISPATCH(); } +uf_math_abs: { + RavaNanboxValue_t val = UF_POP(); + if (rava_nanbox_is_double(val)) { + double d = rava_nanbox_to_double(val); + UF_PUSH(rava_nanbox_double(fabs(d))); + } else { + int64_t v = rava_nanbox_to_long(val); + UF_PUSH(rava_nanbox_long(v < 0 ? -v : v)); + } + UF_DISPATCH(); +} + +uf_math_sqrt: { + RavaNanboxValue_t val = UF_POP(); + double d = rava_nanbox_is_double(val) ? rava_nanbox_to_double(val) : (double)rava_nanbox_to_long(val); + UF_PUSH(rava_nanbox_double(sqrt(d))); + UF_DISPATCH(); +} + +uf_math_pow: { + RavaNanboxValue_t exp = UF_POP(); + RavaNanboxValue_t base = UF_POP(); + double b = rava_nanbox_is_double(base) ? rava_nanbox_to_double(base) : (double)rava_nanbox_to_long(base); + double e = rava_nanbox_is_double(exp) ? rava_nanbox_to_double(exp) : (double)rava_nanbox_to_long(exp); + UF_PUSH(rava_nanbox_double(pow(b, e))); + UF_DISPATCH(); +} + +uf_math_min: { + RavaNanboxValue_t b = UF_POP(); + RavaNanboxValue_t a = UF_POP(); + if (rava_nanbox_is_double(a) || rava_nanbox_is_double(b)) { + double da = rava_nanbox_is_double(a) ? rava_nanbox_to_double(a) : (double)rava_nanbox_to_long(a); + double db = rava_nanbox_is_double(b) ? rava_nanbox_to_double(b) : (double)rava_nanbox_to_long(b); + UF_PUSH(rava_nanbox_double(da < db ? da : db)); + } else { + int64_t ia = rava_nanbox_to_long(a); + int64_t ib = rava_nanbox_to_long(b); + UF_PUSH(rava_nanbox_long(ia < ib ? ia : ib)); + } + UF_DISPATCH(); +} + +uf_math_max: { + RavaNanboxValue_t b = UF_POP(); + RavaNanboxValue_t a = UF_POP(); + if (rava_nanbox_is_double(a) || rava_nanbox_is_double(b)) { + double da = rava_nanbox_is_double(a) ? rava_nanbox_to_double(a) : (double)rava_nanbox_to_long(a); + double db = rava_nanbox_is_double(b) ? rava_nanbox_to_double(b) : (double)rava_nanbox_to_long(b); + UF_PUSH(rava_nanbox_double(da > db ? da : db)); + } else { + int64_t ia = rava_nanbox_to_long(a); + int64_t ib = rava_nanbox_to_long(b); + UF_PUSH(rava_nanbox_long(ia > ib ? ia : ib)); + } + UF_DISPATCH(); +} + +uf_math_floor: { + RavaNanboxValue_t val = UF_POP(); + double d = rava_nanbox_is_double(val) ? rava_nanbox_to_double(val) : (double)rava_nanbox_to_long(val); + UF_PUSH(rava_nanbox_double(floor(d))); + UF_DISPATCH(); +} + +uf_math_ceil: { + RavaNanboxValue_t val = UF_POP(); + double d = rava_nanbox_is_double(val) ? rava_nanbox_to_double(val) : (double)rava_nanbox_to_long(val); + UF_PUSH(rava_nanbox_double(ceil(d))); + UF_DISPATCH(); +} + +uf_math_round: { + RavaNanboxValue_t val = UF_POP(); + double d = rava_nanbox_is_double(val) ? rava_nanbox_to_double(val) : (double)rava_nanbox_to_long(val); + UF_PUSH(rava_nanbox_long((int64_t)round(d))); + UF_DISPATCH(); +} + +uf_math_sin: { + RavaNanboxValue_t val = UF_POP(); + double d = rava_nanbox_is_double(val) ? rava_nanbox_to_double(val) : (double)rava_nanbox_to_long(val); + UF_PUSH(rava_nanbox_double(sin(d))); + UF_DISPATCH(); +} + +uf_math_cos: { + RavaNanboxValue_t val = UF_POP(); + double d = rava_nanbox_is_double(val) ? rava_nanbox_to_double(val) : (double)rava_nanbox_to_long(val); + UF_PUSH(rava_nanbox_double(cos(d))); + UF_DISPATCH(); +} + +uf_math_tan: { + RavaNanboxValue_t val = UF_POP(); + double d = rava_nanbox_is_double(val) ? rava_nanbox_to_double(val) : (double)rava_nanbox_to_long(val); + UF_PUSH(rava_nanbox_double(tan(d))); + UF_DISPATCH(); +} + +uf_math_log: { + RavaNanboxValue_t val = UF_POP(); + double d = rava_nanbox_is_double(val) ? rava_nanbox_to_double(val) : (double)rava_nanbox_to_long(val); + UF_PUSH(rava_nanbox_double(log(d))); + UF_DISPATCH(); +} + +uf_math_exp: { + RavaNanboxValue_t val = UF_POP(); + double d = rava_nanbox_is_double(val) ? rava_nanbox_to_double(val) : (double)rava_nanbox_to_long(val); + UF_PUSH(rava_nanbox_double(exp(d))); + UF_DISPATCH(); +} + +uf_math_random: { + UF_PUSH(rava_nanbox_double((double)rand() / (double)RAND_MAX)); + UF_DISPATCH(); +} + uf_done: rava_fastframe_reset(); return !vm->had_error; diff --git a/runtime/runtime.h b/runtime/runtime.h index 1782c39..b8ea80e 100644 --- a/runtime/runtime.h +++ b/runtime/runtime.h @@ -88,6 +88,20 @@ typedef struct { struct MethodCache_s; +typedef struct { + int catch_label; + int finally_label; + int end_label; + int exception_local; + size_t stack_depth; +} RavaExceptionHandler_t; + +typedef struct { + RavaExceptionHandler_t *handlers; + size_t count; + size_t capacity; +} RavaExceptionStack_t; + typedef struct { RavaProgram_t *program; RavaCallStack_t *call_stack; @@ -95,6 +109,9 @@ typedef struct { struct MethodCache_s *method_cache; char *error_message; bool had_error; + bool has_exception; + RavaValue_t exception_value; + RavaExceptionStack_t *exception_stack; } RavaVM_t; RavaValue_t rava_value_int(int32_t value); diff --git a/semantic/semantic.c b/semantic/semantic.c index 14f3500..97cdeee 100644 --- a/semantic/semantic.c +++ b/semantic/semantic.c @@ -125,11 +125,13 @@ static bool _rava_semantic_analyze_method(RavaSemanticAnalyzer_t *analyzer, Rava static bool _rava_semantic_analyze_field(RavaSemanticAnalyzer_t *analyzer, RavaASTNode_t *field_node) { if (field_node->type != RAVA_AST_FIELD_DECL) return false; - char *field_name = field_node->data.var_decl.name; - RavaType_t *field_type = _rava_semantic_resolve_type(analyzer, field_node->data.var_decl.type); + char *field_name = field_node->data.field_decl.name; + RavaType_t *field_type = _rava_semantic_resolve_type(analyzer, field_node->data.field_decl.type); RavaSymbol_t *field_symbol = rava_symbol_create(RAVA_SYMBOL_FIELD, field_name, field_type); field_symbol->declaration = field_node; + field_symbol->modifiers = field_node->data.field_decl.modifiers; + field_symbol->modifiers_count = field_node->data.field_decl.modifiers_count; if (!rava_symbol_table_define(analyzer->symbol_table, field_symbol)) { char error_msg[256]; @@ -139,8 +141,8 @@ static bool _rava_semantic_analyze_field(RavaSemanticAnalyzer_t *analyzer, RavaA return false; } - if (field_node->data.var_decl.initializer) { - RavaType_t *init_type = _rava_semantic_check_expression(analyzer, field_node->data.var_decl.initializer); + if (field_node->data.field_decl.initializer) { + RavaType_t *init_type = _rava_semantic_check_expression(analyzer, field_node->data.field_decl.initializer); if (init_type && !rava_type_is_assignable_to(init_type, field_type)) { char error_msg[256]; snprintf(error_msg, sizeof(error_msg), @@ -299,6 +301,20 @@ static RavaType_t* _rava_semantic_check_expression(RavaSemanticAnalyzer_t *analy return rava_type_create_primitive(RAVA_TYPE_LONG); } } + if (member->data.member_access.object->type == RAVA_AST_IDENTIFIER_EXPR && + strcmp(member->data.member_access.object->data.identifier.name, "Math") == 0) { + if (strcmp(method, "abs") == 0 || strcmp(method, "min") == 0 || strcmp(method, "max") == 0) { + return rava_type_create_primitive(RAVA_TYPE_INT); + } else if (strcmp(method, "round") == 0) { + return rava_type_create_primitive(RAVA_TYPE_LONG); + } else if (strcmp(method, "sqrt") == 0 || strcmp(method, "pow") == 0 || + strcmp(method, "floor") == 0 || strcmp(method, "ceil") == 0 || + strcmp(method, "sin") == 0 || strcmp(method, "cos") == 0 || + strcmp(method, "tan") == 0 || strcmp(method, "log") == 0 || + strcmp(method, "exp") == 0 || strcmp(method, "random") == 0) { + return rava_type_create_primitive(RAVA_TYPE_DOUBLE); + } + } if (strcmp(method, "length") == 0) { return rava_type_create_primitive(RAVA_TYPE_INT); } else if (strcmp(method, "charAt") == 0) {