Compare commits

...

2 Commits

Author SHA1 Message Date
1afd91c1c7 Update.
Some checks failed
CI / Optimization Infrastructure Tests (push) Failing after 13s
CI / Unit Tests (push) Failing after 29s
CI / Integration Tests (push) Has been skipped
CI / Performance Benchmark (push) Has been skipped
2025-12-04 16:49:20 +01:00
e1ddf91281 Power up./plot.py 2025-12-04 06:14:22 +01:00
22 changed files with 1972 additions and 250 deletions

View File

@ -17,7 +17,7 @@ SEMANTIC_OBJECTS = $(SEMANTIC_SOURCES:.c=.o)
IR_SOURCES = ir/ir.c ir/ir_gen.c IR_SOURCES = ir/ir.c ir/ir_gen.c
IR_OBJECTS = $(IR_SOURCES:.c=.o) IR_OBJECTS = $(IR_SOURCES:.c=.o)
RUNTIME_SOURCES = runtime/runtime.c runtime/labeltable.c runtime/methodcache.c runtime/fastframe.c runtime/superinst.c RUNTIME_SOURCES = runtime/runtime.c runtime/runtime_array.c runtime/runtime_object.c runtime/runtime_collections.c runtime/labeltable.c runtime/methodcache.c runtime/fastframe.c runtime/superinst.c
RUNTIME_OBJECTS = $(RUNTIME_SOURCES:.c=.o) RUNTIME_OBJECTS = $(RUNTIME_SOURCES:.c=.o)
PHASE0_SOURCES = runtime/fastframe.c runtime/labeltable.c runtime/methodcache.c PHASE0_SOURCES = runtime/fastframe.c runtime/labeltable.c runtime/methodcache.c
@ -98,7 +98,16 @@ TEST_MULTIDIM_ARRAYS_OBJECTS = $(TEST_MULTIDIM_ARRAYS_SOURCES:.c=.o)
TEST_STATIC_INIT_SOURCES = tests/test_static_init.c TEST_STATIC_INIT_SOURCES = tests/test_static_init.c
TEST_STATIC_INIT_OBJECTS = $(TEST_STATIC_INIT_SOURCES:.c=.o) TEST_STATIC_INIT_OBJECTS = $(TEST_STATIC_INIT_SOURCES:.c=.o)
all: test_lexer test_parser test_semantic test_ir test_runtime test_strings test_arrays test_objects test_instance_methods test_fileio test_dowhile test_switch test_math test_string_methods test_static test_interfaces test_exceptions test_ternary test_bitwise test_enhanced_for test_array_init test_instanceof test_shortcircuit test_multidim_arrays test_static_init TEST_NEGATIVE_SOURCES = tests/test_negative.c
TEST_NEGATIVE_OBJECTS = $(TEST_NEGATIVE_SOURCES:.c=.o)
TEST_ENUMS_SOURCES = tests/test_enums.c
TEST_ENUMS_OBJECTS = $(TEST_ENUMS_SOURCES:.c=.o)
TEST_COLLECTIONS_SOURCES = tests/test_collections.c
TEST_COLLECTIONS_OBJECTS = $(TEST_COLLECTIONS_SOURCES:.c=.o)
all: test_lexer test_parser test_semantic test_ir test_runtime test_strings test_arrays test_objects test_instance_methods test_fileio test_dowhile test_switch test_math test_string_methods test_static test_interfaces test_exceptions test_ternary test_bitwise test_enhanced_for test_array_init test_instanceof test_shortcircuit test_multidim_arrays test_static_init test_negative test_enums test_collections
test_lexer: $(LEXER_OBJECTS) $(TEST_LEXER_OBJECTS) test_lexer: $(LEXER_OBJECTS) $(TEST_LEXER_OBJECTS)
$(CC) $(CFLAGS) -o $@ $^ $(LDFLAGS) $(CC) $(CFLAGS) -o $@ $^ $(LDFLAGS)
@ -175,6 +184,15 @@ test_multidim_arrays: $(LEXER_OBJECTS) $(PARSER_OBJECTS) $(TYPES_OBJECTS) $(SEMA
test_static_init: $(LEXER_OBJECTS) $(PARSER_OBJECTS) $(TYPES_OBJECTS) $(SEMANTIC_OBJECTS) $(IR_OBJECTS) $(RUNTIME_OBJECTS) $(TEST_STATIC_INIT_OBJECTS) test_static_init: $(LEXER_OBJECTS) $(PARSER_OBJECTS) $(TYPES_OBJECTS) $(SEMANTIC_OBJECTS) $(IR_OBJECTS) $(RUNTIME_OBJECTS) $(TEST_STATIC_INIT_OBJECTS)
$(CC) $(CFLAGS) -o $@ $^ $(LDFLAGS) $(CC) $(CFLAGS) -o $@ $^ $(LDFLAGS)
test_negative: $(LEXER_OBJECTS) $(PARSER_OBJECTS) $(TYPES_OBJECTS) $(SEMANTIC_OBJECTS) $(IR_OBJECTS) $(RUNTIME_OBJECTS) $(TEST_NEGATIVE_OBJECTS)
$(CC) $(CFLAGS) -o $@ $^ $(LDFLAGS)
test_enums: $(LEXER_OBJECTS) $(PARSER_OBJECTS) $(TYPES_OBJECTS) $(SEMANTIC_OBJECTS) $(IR_OBJECTS) $(RUNTIME_OBJECTS) $(TEST_ENUMS_OBJECTS)
$(CC) $(CFLAGS) -o $@ $^ $(LDFLAGS)
test_collections: $(LEXER_OBJECTS) $(PARSER_OBJECTS) $(TYPES_OBJECTS) $(SEMANTIC_OBJECTS) $(IR_OBJECTS) $(RUNTIME_OBJECTS) $(TEST_COLLECTIONS_OBJECTS)
$(CC) $(CFLAGS) -o $@ $^ $(LDFLAGS)
%.o: %.c %.o: %.c
$(CC) $(CFLAGS) -c $< -o $@ $(CC) $(CFLAGS) -c $< -o $@
@ -240,8 +258,8 @@ clean:
$(PHASE0_OBJECTS) \ $(PHASE0_OBJECTS) \
$(TEST_LEXER_OBJECTS) $(TEST_PARSER_OBJECTS) $(TEST_SEMANTIC_OBJECTS) $(TEST_IR_OBJECTS) $(TEST_RUNTIME_OBJECTS) \ $(TEST_LEXER_OBJECTS) $(TEST_PARSER_OBJECTS) $(TEST_SEMANTIC_OBJECTS) $(TEST_IR_OBJECTS) $(TEST_RUNTIME_OBJECTS) \
$(TEST_STRINGS_OBJECTS) $(TEST_ARRAYS_OBJECTS) $(TEST_OBJECTS_OBJECTS) $(TEST_INSTANCE_OBJECTS) $(TEST_FILEIO_OBJECTS) \ $(TEST_STRINGS_OBJECTS) $(TEST_ARRAYS_OBJECTS) $(TEST_OBJECTS_OBJECTS) $(TEST_INSTANCE_OBJECTS) $(TEST_FILEIO_OBJECTS) \
$(TEST_DOWHILE_OBJECTS) $(TEST_SWITCH_OBJECTS) $(TEST_MATH_OBJECTS) $(TEST_STRING_METHODS_OBJECTS) $(TEST_STATIC_OBJECTS) $(TEST_INTERFACES_OBJECTS) $(TEST_EXCEPTIONS_OBJECTS) $(TEST_TERNARY_OBJECTS) $(TEST_BITWISE_OBJECTS) $(TEST_ENHANCED_FOR_OBJECTS) $(TEST_ARRAY_INIT_OBJECTS) $(TEST_INSTANCEOF_OBJECTS) $(TEST_SHORTCIRCUIT_OBJECTS) $(TEST_MULTIDIM_ARRAYS_OBJECTS) $(TEST_STATIC_INIT_OBJECTS) $(TEST_BENCHMARK_OBJECTS) \ $(TEST_DOWHILE_OBJECTS) $(TEST_SWITCH_OBJECTS) $(TEST_MATH_OBJECTS) $(TEST_STRING_METHODS_OBJECTS) $(TEST_STATIC_OBJECTS) $(TEST_INTERFACES_OBJECTS) $(TEST_EXCEPTIONS_OBJECTS) $(TEST_TERNARY_OBJECTS) $(TEST_BITWISE_OBJECTS) $(TEST_ENHANCED_FOR_OBJECTS) $(TEST_ARRAY_INIT_OBJECTS) $(TEST_INSTANCEOF_OBJECTS) $(TEST_SHORTCIRCUIT_OBJECTS) $(TEST_MULTIDIM_ARRAYS_OBJECTS) $(TEST_STATIC_INIT_OBJECTS) $(TEST_NEGATIVE_OBJECTS) $(TEST_ENUMS_OBJECTS) $(TEST_COLLECTIONS_OBJECTS) $(TEST_BENCHMARK_OBJECTS) \
test_lexer test_parser test_semantic test_ir test_runtime test_strings test_arrays test_objects test_instance_methods test_fileio test_dowhile test_switch test_math test_string_methods test_static test_interfaces test_exceptions test_ternary test_bitwise test_enhanced_for test_array_init test_instanceof test_shortcircuit test_multidim_arrays test_static_init test_benchmark \ test_lexer test_parser test_semantic test_ir test_runtime test_strings test_arrays test_objects test_instance_methods test_fileio test_dowhile test_switch test_math test_string_methods test_static test_interfaces test_exceptions test_ternary test_bitwise test_enhanced_for test_array_init test_instanceof test_shortcircuit test_multidim_arrays test_static_init test_negative test_enums test_collections test_benchmark \
test_nanbox test_fastframe test_labeltable test_methodcache test_benchmark_pgo *.gcda */*.gcda 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 test .PHONY: all clean benchmark test_phase0 pgo test_benchmark_pgo_gen pgo_run test_benchmark_pgo test
@ -253,5 +271,6 @@ test: all
./test_fileio && ./test_dowhile && ./test_switch && ./test_math && ./test_string_methods && \ ./test_fileio && ./test_dowhile && ./test_switch && ./test_math && ./test_string_methods && \
./test_static && ./test_interfaces && ./test_exceptions && ./test_ternary && \ ./test_static && ./test_interfaces && ./test_exceptions && ./test_ternary && \
./test_bitwise && ./test_enhanced_for && ./test_array_init && ./test_instanceof && \ ./test_bitwise && ./test_enhanced_for && ./test_array_init && ./test_instanceof && \
./test_shortcircuit && ./test_multidim_arrays && ./test_static_init && \ ./test_shortcircuit && ./test_multidim_arrays && ./test_static_init && ./test_negative && \
./test_enums && \
echo "" && echo "=== All Tests Passed ===" echo "" && echo "=== All Tests Passed ==="

52
ir/ir.c
View File

@ -1,6 +1,7 @@
#define _POSIX_C_SOURCE 200809L #define _POSIX_C_SOURCE 200809L
#include "ir.h" #include "ir.h"
#include "../runtime/labeltable.h" #include "../runtime/labeltable.h"
#include "../utils/safe_alloc.h"
#include <stdlib.h> #include <stdlib.h>
#include <string.h> #include <string.h>
#include <stdio.h> #include <stdio.h>
@ -23,8 +24,10 @@ void rava_instruction_list_destroy(RavaInstructionList_t *list) {
void rava_instruction_list_add(RavaInstructionList_t *list, RavaInstruction_t instr) { void rava_instruction_list_add(RavaInstructionList_t *list, RavaInstruction_t instr) {
if (list->count >= list->capacity) { if (list->count >= list->capacity) {
list->capacity *= 2; list->capacity *= 2;
list->instructions = realloc(list->instructions, RavaInstruction_t *new_instrs = rava_safe_realloc(list->instructions,
sizeof(RavaInstruction_t) * list->capacity); sizeof(RavaInstruction_t) * list->capacity);
if (!new_instrs) return;
list->instructions = new_instrs;
} }
list->instructions[list->count++] = instr; list->instructions[list->count++] = instr;
} }
@ -89,7 +92,9 @@ void rava_class_destroy(RavaClass_t *class) {
void rava_class_add_method(RavaClass_t *class, RavaMethod_t *method) { void rava_class_add_method(RavaClass_t *class, RavaMethod_t *method) {
if (class->method_count >= class->method_capacity) { if (class->method_count >= class->method_capacity) {
size_t new_capacity = class->method_capacity == 0 ? 4 : class->method_capacity * 2; size_t new_capacity = class->method_capacity == 0 ? 4 : class->method_capacity * 2;
class->methods = realloc(class->methods, sizeof(RavaMethod_t*) * new_capacity); RavaMethod_t **new_methods = rava_safe_realloc(class->methods, sizeof(RavaMethod_t*) * new_capacity);
if (!new_methods) return;
class->methods = new_methods;
class->method_capacity = new_capacity; class->method_capacity = new_capacity;
} }
uint32_t h = _method_hash(method->name); uint32_t h = _method_hash(method->name);
@ -117,7 +122,9 @@ void rava_program_destroy(RavaProgram_t *program) {
void rava_program_add_class(RavaProgram_t *program, RavaClass_t *class) { void rava_program_add_class(RavaProgram_t *program, RavaClass_t *class) {
if (program->class_count >= program->class_capacity) { if (program->class_count >= program->class_capacity) {
size_t new_capacity = program->class_capacity == 0 ? 4 : program->class_capacity * 2; size_t new_capacity = program->class_capacity == 0 ? 4 : program->class_capacity * 2;
program->classes = realloc(program->classes, sizeof(RavaClass_t*) * new_capacity); RavaClass_t **new_classes = rava_safe_realloc(program->classes, sizeof(RavaClass_t*) * new_capacity);
if (!new_classes) return;
program->classes = new_classes;
program->class_capacity = new_capacity; program->class_capacity = new_capacity;
} }
program->classes[program->class_count++] = class; program->classes[program->class_count++] = class;
@ -181,6 +188,26 @@ static void _compute_max_stack(RavaMethod_t *method) {
method->max_stack = max_depth + 16; method->max_stack = max_depth + 16;
} }
static void _mark_simple_methods(RavaMethod_t *method) {
if (!method || !method->instructions) return;
method->is_leaf = true;
method->is_simple = (method->instructions->count < 20);
for (size_t i = 0; i < method->instructions->count; i++) {
RavaOpCode_e op = method->instructions->instructions[i].opcode;
if (op == RAVA_OP_CALL || op == RAVA_OP_CALL_STATIC ||
op == RAVA_OP_CALL_RECURSIVE || op == RAVA_OP_CALL_VIRTUAL) {
method->is_leaf = false;
method->is_simple = false;
}
if (op == RAVA_OP_JUMP || op == RAVA_OP_JUMP_IF_TRUE ||
op == RAVA_OP_JUMP_IF_FALSE) {
method->is_simple = false;
}
}
}
void rava_program_prebuild_label_tables(RavaProgram_t *program) { void rava_program_prebuild_label_tables(RavaProgram_t *program) {
if (!program) return; if (!program) return;
for (size_t i = 0; i < program->class_count; i++) { for (size_t i = 0; i < program->class_count; i++) {
@ -193,6 +220,7 @@ void rava_program_prebuild_label_tables(RavaProgram_t *program) {
if (method->max_stack == 0) { if (method->max_stack == 0) {
_compute_max_stack(method); _compute_max_stack(method);
} }
_mark_simple_methods(method);
} }
} }
} }
@ -222,6 +250,7 @@ static const char* _rava_opcode_name(RavaOpCode_e opcode) {
case RAVA_OP_CALL: return "CALL"; case RAVA_OP_CALL: return "CALL";
case RAVA_OP_CALL_STATIC: return "CALL_STATIC"; case RAVA_OP_CALL_STATIC: return "CALL_STATIC";
case RAVA_OP_CALL_RECURSIVE: return "CALL_RECURSIVE"; case RAVA_OP_CALL_RECURSIVE: return "CALL_RECURSIVE";
case RAVA_OP_CALL_INLINE: return "CALL_INLINE";
case RAVA_OP_RETURN: return "RETURN"; case RAVA_OP_RETURN: return "RETURN";
case RAVA_OP_RETURN_VOID: return "RETURN_VOID"; case RAVA_OP_RETURN_VOID: return "RETURN_VOID";
case RAVA_OP_NEW: return "NEW"; case RAVA_OP_NEW: return "NEW";
@ -229,11 +258,28 @@ static const char* _rava_opcode_name(RavaOpCode_e opcode) {
case RAVA_OP_NEW_ARRAY_OF_ARRAYS: return "NEW_ARRAY_OF_ARRAYS"; case RAVA_OP_NEW_ARRAY_OF_ARRAYS: return "NEW_ARRAY_OF_ARRAYS";
case RAVA_OP_ARRAY_LENGTH: return "ARRAY_LENGTH"; case RAVA_OP_ARRAY_LENGTH: return "ARRAY_LENGTH";
case RAVA_OP_LOAD_ARRAY: return "LOAD_ARRAY"; case RAVA_OP_LOAD_ARRAY: return "LOAD_ARRAY";
case RAVA_OP_LOAD_ARRAY_UNCHECKED: return "LOAD_ARRAY_UNCHECKED";
case RAVA_OP_STORE_ARRAY: return "STORE_ARRAY"; case RAVA_OP_STORE_ARRAY: return "STORE_ARRAY";
case RAVA_OP_STORE_ARRAY_UNCHECKED: return "STORE_ARRAY_UNCHECKED";
case RAVA_OP_POP: return "POP"; case RAVA_OP_POP: return "POP";
case RAVA_OP_DUP: return "DUP"; case RAVA_OP_DUP: return "DUP";
case RAVA_OP_PRINT: return "PRINT"; case RAVA_OP_PRINT: return "PRINT";
case RAVA_OP_PRINTLN: return "PRINTLN"; case RAVA_OP_PRINTLN: return "PRINTLN";
case RAVA_OP_ARRAYLIST_NEW: return "ARRAYLIST_NEW";
case RAVA_OP_ARRAYLIST_ADD: return "ARRAYLIST_ADD";
case RAVA_OP_ARRAYLIST_GET: return "ARRAYLIST_GET";
case RAVA_OP_ARRAYLIST_SET: return "ARRAYLIST_SET";
case RAVA_OP_ARRAYLIST_SIZE: return "ARRAYLIST_SIZE";
case RAVA_OP_ARRAYLIST_REMOVE: return "ARRAYLIST_REMOVE";
case RAVA_OP_ARRAYLIST_CLEAR: return "ARRAYLIST_CLEAR";
case RAVA_OP_ARRAYLIST_ISEMPTY: return "ARRAYLIST_ISEMPTY";
case RAVA_OP_HASHMAP_NEW: return "HASHMAP_NEW";
case RAVA_OP_HASHMAP_PUT: return "HASHMAP_PUT";
case RAVA_OP_HASHMAP_GET: return "HASHMAP_GET";
case RAVA_OP_HASHMAP_REMOVE: return "HASHMAP_REMOVE";
case RAVA_OP_HASHMAP_SIZE: return "HASHMAP_SIZE";
case RAVA_OP_HASHMAP_CONTAINSKEY: return "HASHMAP_CONTAINSKEY";
case RAVA_OP_HASHMAP_CLEAR: return "HASHMAP_CLEAR";
default: return "UNKNOWN"; default: return "UNKNOWN";
} }
} }

25
ir/ir.h
View File

@ -17,11 +17,13 @@ typedef enum {
RAVA_OP_LOAD_FIELD, RAVA_OP_LOAD_FIELD,
RAVA_OP_LOAD_STATIC, RAVA_OP_LOAD_STATIC,
RAVA_OP_LOAD_ARRAY, RAVA_OP_LOAD_ARRAY,
RAVA_OP_LOAD_ARRAY_UNCHECKED,
RAVA_OP_STORE_LOCAL, RAVA_OP_STORE_LOCAL,
RAVA_OP_STORE_FIELD, RAVA_OP_STORE_FIELD,
RAVA_OP_STORE_STATIC, RAVA_OP_STORE_STATIC,
RAVA_OP_STORE_ARRAY, RAVA_OP_STORE_ARRAY,
RAVA_OP_STORE_ARRAY_UNCHECKED,
RAVA_OP_ADD, RAVA_OP_ADD,
RAVA_OP_SUB, RAVA_OP_SUB,
@ -54,6 +56,7 @@ typedef enum {
RAVA_OP_CALL, RAVA_OP_CALL,
RAVA_OP_CALL_STATIC, RAVA_OP_CALL_STATIC,
RAVA_OP_CALL_RECURSIVE, RAVA_OP_CALL_RECURSIVE,
RAVA_OP_CALL_INLINE,
RAVA_OP_CALL_VIRTUAL, RAVA_OP_CALL_VIRTUAL,
RAVA_OP_CALL_SUPER, RAVA_OP_CALL_SUPER,
RAVA_OP_CALL_NATIVE, RAVA_OP_CALL_NATIVE,
@ -124,7 +127,24 @@ typedef enum {
RAVA_OP_MATH_TAN, RAVA_OP_MATH_TAN,
RAVA_OP_MATH_LOG, RAVA_OP_MATH_LOG,
RAVA_OP_MATH_EXP, RAVA_OP_MATH_EXP,
RAVA_OP_MATH_RANDOM RAVA_OP_MATH_RANDOM,
RAVA_OP_ARRAYLIST_NEW,
RAVA_OP_ARRAYLIST_ADD,
RAVA_OP_ARRAYLIST_GET,
RAVA_OP_ARRAYLIST_SET,
RAVA_OP_ARRAYLIST_SIZE,
RAVA_OP_ARRAYLIST_REMOVE,
RAVA_OP_ARRAYLIST_CLEAR,
RAVA_OP_ARRAYLIST_ISEMPTY,
RAVA_OP_HASHMAP_NEW,
RAVA_OP_HASHMAP_PUT,
RAVA_OP_HASHMAP_GET,
RAVA_OP_HASHMAP_REMOVE,
RAVA_OP_HASHMAP_SIZE,
RAVA_OP_HASHMAP_CONTAINSKEY,
RAVA_OP_HASHMAP_CLEAR
} RavaOpCode_e; } RavaOpCode_e;
typedef union { typedef union {
@ -196,6 +216,8 @@ typedef struct {
int max_stack; int max_stack;
RavaInstructionList_t *instructions; RavaInstructionList_t *instructions;
struct LabelTable_s *label_table; struct LabelTable_s *label_table;
bool is_leaf;
bool is_simple;
} RavaMethod_t; } RavaMethod_t;
#define RAVA_METHOD_HASH_SIZE 16 #define RAVA_METHOD_HASH_SIZE 16
@ -207,6 +229,7 @@ typedef struct {
size_t method_count; size_t method_count;
size_t method_capacity; size_t method_capacity;
int method_hash[RAVA_METHOD_HASH_SIZE]; int method_hash[RAVA_METHOD_HASH_SIZE];
bool is_enum;
} RavaClass_t; } RavaClass_t;
typedef struct { typedef struct {

View File

@ -245,7 +245,20 @@ static void _rava_ir_gen_expression(RavaIRGenerator_t *gen, RavaASTNode_t *expr)
_rava_ir_gen_expression(gen, expr->data.assign.target->data.array_access.array); _rava_ir_gen_expression(gen, expr->data.assign.target->data.array_access.array);
_rava_ir_gen_expression(gen, expr->data.assign.target->data.array_access.index); _rava_ir_gen_expression(gen, expr->data.assign.target->data.array_access.index);
_rava_ir_gen_expression(gen, expr->data.assign.value); _rava_ir_gen_expression(gen, expr->data.assign.value);
instr.opcode = RAVA_OP_STORE_ARRAY;
bool use_unchecked = false;
if (gen->loop_context && gen->loop_context->has_bounds_check) {
RavaASTNode_t *index_node = expr->data.assign.target->data.array_access.index;
if (index_node->type == RAVA_AST_IDENTIFIER_EXPR) {
const char *index_name = index_node->data.identifier.name;
if (gen->loop_context->loop_var_name &&
strcmp(index_name, gen->loop_context->loop_var_name) == 0) {
use_unchecked = true;
}
}
}
instr.opcode = use_unchecked ? RAVA_OP_STORE_ARRAY_UNCHECKED : RAVA_OP_STORE_ARRAY;
_rava_ir_emit(gen, instr); _rava_ir_emit(gen, instr);
} else if (expr->data.assign.target->type == RAVA_AST_MEMBER_ACCESS_EXPR) { } else if (expr->data.assign.target->type == RAVA_AST_MEMBER_ACCESS_EXPR) {
RavaASTNode_t *target_member = expr->data.assign.target; RavaASTNode_t *target_member = expr->data.assign.target;
@ -302,12 +315,25 @@ static void _rava_ir_gen_expression(RavaIRGenerator_t *gen, RavaASTNode_t *expr)
_rava_ir_emit(gen, instr); _rava_ir_emit(gen, instr);
break; break;
case RAVA_AST_ARRAY_ACCESS_EXPR: case RAVA_AST_ARRAY_ACCESS_EXPR: {
_rava_ir_gen_expression(gen, expr->data.array_access.array); _rava_ir_gen_expression(gen, expr->data.array_access.array);
_rava_ir_gen_expression(gen, expr->data.array_access.index); _rava_ir_gen_expression(gen, expr->data.array_access.index);
instr.opcode = RAVA_OP_LOAD_ARRAY;
bool use_unchecked = false;
if (gen->loop_context && gen->loop_context->has_bounds_check) {
if (expr->data.array_access.index->type == RAVA_AST_IDENTIFIER_EXPR) {
const char *index_name = expr->data.array_access.index->data.identifier.name;
if (gen->loop_context->loop_var_name &&
strcmp(index_name, gen->loop_context->loop_var_name) == 0) {
use_unchecked = true;
}
}
}
instr.opcode = use_unchecked ? RAVA_OP_LOAD_ARRAY_UNCHECKED : RAVA_OP_LOAD_ARRAY;
_rava_ir_emit(gen, instr); _rava_ir_emit(gen, instr);
break; break;
}
case RAVA_AST_NEW_EXPR: case RAVA_AST_NEW_EXPR:
if (expr->data.new_expr.type && expr->data.new_expr.type->data.type.is_array) { if (expr->data.new_expr.type && expr->data.new_expr.type->data.type.is_array) {
@ -400,8 +426,16 @@ static void _rava_ir_gen_expression(RavaIRGenerator_t *gen, RavaASTNode_t *expr)
_rava_ir_emit(gen, instr); _rava_ir_emit(gen, instr);
} }
} else if (expr->data.new_expr.type) { } else if (expr->data.new_expr.type) {
const char *type_name = expr->data.new_expr.type->data.type.type_name;
if (strcmp(type_name, "ArrayList") == 0) {
instr.opcode = RAVA_OP_ARRAYLIST_NEW;
_rava_ir_emit(gen, instr);
} else if (strcmp(type_name, "HashMap") == 0) {
instr.opcode = RAVA_OP_HASHMAP_NEW;
_rava_ir_emit(gen, instr);
} else {
instr.opcode = RAVA_OP_NEW; instr.opcode = RAVA_OP_NEW;
instr.operand.call.class_name = strdup(expr->data.new_expr.type->data.type.type_name); instr.operand.call.class_name = strdup(type_name);
instr.operand.call.arg_count = expr->data.new_expr.arguments_count; instr.operand.call.arg_count = expr->data.new_expr.arguments_count;
_rava_ir_emit(gen, instr); _rava_ir_emit(gen, instr);
instr.opcode = RAVA_OP_DUP; instr.opcode = RAVA_OP_DUP;
@ -413,6 +447,7 @@ static void _rava_ir_gen_expression(RavaIRGenerator_t *gen, RavaASTNode_t *expr)
instr.operand.call.method_name = strdup("<init>"); instr.operand.call.method_name = strdup("<init>");
_rava_ir_emit(gen, instr); _rava_ir_emit(gen, instr);
} }
}
break; break;
case RAVA_AST_CALL_EXPR: { case RAVA_AST_CALL_EXPR: {
@ -450,7 +485,17 @@ static void _rava_ir_gen_expression(RavaIRGenerator_t *gen, RavaASTNode_t *expr)
bool is_math_log = false; bool is_math_log = false;
bool is_math_exp = false; bool is_math_exp = false;
bool is_math_random = false; bool is_math_random = false;
bool is_arraylist_add = false;
bool is_arraylist_get = false;
bool is_arraylist_set = false;
bool is_arraylist_size = false;
bool is_arraylist_remove = false;
bool is_arraylist_clear = false;
bool is_arraylist_isempty = false;
bool is_hashmap_put = false;
bool is_hashmap_containskey = false;
RavaASTNode_t *string_object = NULL; RavaASTNode_t *string_object = NULL;
RavaASTNode_t *collection_object = NULL;
if (expr->data.call.callee->type == RAVA_AST_MEMBER_ACCESS_EXPR) { if (expr->data.call.callee->type == RAVA_AST_MEMBER_ACCESS_EXPR) {
RavaASTNode_t *member = expr->data.call.callee; RavaASTNode_t *member = expr->data.call.callee;
@ -555,6 +600,33 @@ static void _rava_ir_gen_expression(RavaIRGenerator_t *gen, RavaASTNode_t *expr)
} else if (strcmp(member->data.member_access.member, "trim") == 0 && expr->data.call.arguments_count == 0) { } else if (strcmp(member->data.member_access.member, "trim") == 0 && expr->data.call.arguments_count == 0) {
is_string_trim = true; is_string_trim = true;
string_object = member->data.member_access.object; string_object = member->data.member_access.object;
} else if (strcmp(member->data.member_access.member, "add") == 0 && expr->data.call.arguments_count == 1) {
is_arraylist_add = true;
collection_object = member->data.member_access.object;
} else if (strcmp(member->data.member_access.member, "get") == 0 && expr->data.call.arguments_count == 1) {
is_arraylist_get = true;
collection_object = member->data.member_access.object;
} else if (strcmp(member->data.member_access.member, "set") == 0 && expr->data.call.arguments_count == 2) {
is_arraylist_set = true;
collection_object = member->data.member_access.object;
} else if (strcmp(member->data.member_access.member, "size") == 0 && expr->data.call.arguments_count == 0 && !is_string_length) {
is_arraylist_size = true;
collection_object = member->data.member_access.object;
} else if (strcmp(member->data.member_access.member, "remove") == 0 && expr->data.call.arguments_count == 1) {
is_arraylist_remove = true;
collection_object = member->data.member_access.object;
} else if (strcmp(member->data.member_access.member, "clear") == 0 && expr->data.call.arguments_count == 0) {
is_arraylist_clear = true;
collection_object = member->data.member_access.object;
} else if (strcmp(member->data.member_access.member, "isEmpty") == 0 && expr->data.call.arguments_count == 0) {
is_arraylist_isempty = true;
collection_object = member->data.member_access.object;
} else if (strcmp(member->data.member_access.member, "put") == 0 && expr->data.call.arguments_count == 2) {
is_hashmap_put = true;
collection_object = member->data.member_access.object;
} else if (strcmp(member->data.member_access.member, "containsKey") == 0 && expr->data.call.arguments_count == 1) {
is_hashmap_containskey = true;
collection_object = member->data.member_access.object;
} }
} }
@ -696,6 +768,50 @@ static void _rava_ir_gen_expression(RavaIRGenerator_t *gen, RavaASTNode_t *expr)
} else if (is_math_random) { } else if (is_math_random) {
instr.opcode = RAVA_OP_MATH_RANDOM; instr.opcode = RAVA_OP_MATH_RANDOM;
_rava_ir_emit(gen, instr); _rava_ir_emit(gen, instr);
} else if (is_arraylist_add) {
_rava_ir_gen_expression(gen, collection_object);
_rava_ir_gen_expression(gen, expr->data.call.arguments[0]);
instr.opcode = RAVA_OP_ARRAYLIST_ADD;
_rava_ir_emit(gen, instr);
} else if (is_arraylist_get) {
_rava_ir_gen_expression(gen, collection_object);
_rava_ir_gen_expression(gen, expr->data.call.arguments[0]);
instr.opcode = RAVA_OP_ARRAYLIST_GET;
_rava_ir_emit(gen, instr);
} else if (is_arraylist_set) {
_rava_ir_gen_expression(gen, collection_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_ARRAYLIST_SET;
_rava_ir_emit(gen, instr);
} else if (is_arraylist_size) {
_rava_ir_gen_expression(gen, collection_object);
instr.opcode = RAVA_OP_ARRAYLIST_SIZE;
_rava_ir_emit(gen, instr);
} else if (is_arraylist_remove) {
_rava_ir_gen_expression(gen, collection_object);
_rava_ir_gen_expression(gen, expr->data.call.arguments[0]);
instr.opcode = RAVA_OP_ARRAYLIST_REMOVE;
_rava_ir_emit(gen, instr);
} else if (is_arraylist_clear) {
_rava_ir_gen_expression(gen, collection_object);
instr.opcode = RAVA_OP_ARRAYLIST_CLEAR;
_rava_ir_emit(gen, instr);
} else if (is_arraylist_isempty) {
_rava_ir_gen_expression(gen, collection_object);
instr.opcode = RAVA_OP_ARRAYLIST_ISEMPTY;
_rava_ir_emit(gen, instr);
} else if (is_hashmap_put) {
_rava_ir_gen_expression(gen, collection_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_HASHMAP_PUT;
_rava_ir_emit(gen, instr);
} else if (is_hashmap_containskey) {
_rava_ir_gen_expression(gen, collection_object);
_rava_ir_gen_expression(gen, expr->data.call.arguments[0]);
instr.opcode = RAVA_OP_HASHMAP_CONTAINSKEY;
_rava_ir_emit(gen, instr);
} else if (is_println || is_print) { } else if (is_println || is_print) {
for (size_t i = 0; i < expr->data.call.arguments_count; i++) { for (size_t i = 0; i < expr->data.call.arguments_count; i++) {
_rava_ir_gen_expression(gen, expr->data.call.arguments[i]); _rava_ir_gen_expression(gen, expr->data.call.arguments[i]);
@ -886,7 +1002,14 @@ static void _rava_ir_gen_statement(RavaIRGenerator_t *gen, RavaASTNode_t *stmt)
int start_label = rava_instruction_list_new_label(gen->current_method->instructions); int start_label = rava_instruction_list_new_label(gen->current_method->instructions);
int end_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 }; RavaLoopContext_t loop_ctx = {
.break_label = end_label,
.continue_label = start_label,
.parent = gen->loop_context,
.loop_var_name = NULL,
.loop_var_index = -1,
.has_bounds_check = false
};
gen->loop_context = &loop_ctx; gen->loop_context = &loop_ctx;
instr.opcode = RAVA_OP_LABEL; instr.opcode = RAVA_OP_LABEL;
@ -917,7 +1040,14 @@ static void _rava_ir_gen_statement(RavaIRGenerator_t *gen, RavaASTNode_t *stmt)
int start_label = rava_instruction_list_new_label(gen->current_method->instructions); int start_label = rava_instruction_list_new_label(gen->current_method->instructions);
int end_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 }; RavaLoopContext_t loop_ctx = {
.break_label = end_label,
.continue_label = start_label,
.parent = gen->loop_context,
.loop_var_name = NULL,
.loop_var_index = -1,
.has_bounds_check = false
};
gen->loop_context = &loop_ctx; gen->loop_context = &loop_ctx;
instr.opcode = RAVA_OP_LABEL; instr.opcode = RAVA_OP_LABEL;
@ -941,6 +1071,33 @@ static void _rava_ir_gen_statement(RavaIRGenerator_t *gen, RavaASTNode_t *stmt)
} }
case RAVA_AST_FOR_STMT: { case RAVA_AST_FOR_STMT: {
char *loop_var_name = NULL;
int loop_var_index = -1;
bool has_bounds_check = false;
if (stmt->data.for_stmt.init && stmt->data.for_stmt.init->type == RAVA_AST_VAR_DECL) {
RavaASTNode_t *var_decl = stmt->data.for_stmt.init;
loop_var_name = var_decl->data.var_decl.name;
loop_var_index = (int)gen->next_local;
if (var_decl->data.var_decl.initializer &&
var_decl->data.var_decl.initializer->type == RAVA_AST_LITERAL_EXPR &&
var_decl->data.var_decl.initializer->data.literal.value.int_value == 0) {
if (stmt->data.for_stmt.condition &&
stmt->data.for_stmt.condition->type == RAVA_AST_BINARY_EXPR &&
(stmt->data.for_stmt.condition->data.binary.op == RAVA_BINOP_LT ||
stmt->data.for_stmt.condition->data.binary.op == RAVA_BINOP_LE)) {
RavaASTNode_t *left = stmt->data.for_stmt.condition->data.binary.left;
if (left->type == RAVA_AST_IDENTIFIER_EXPR &&
strcmp(left->data.identifier.name, loop_var_name) == 0) {
has_bounds_check = true;
}
}
}
}
if (stmt->data.for_stmt.init) { if (stmt->data.for_stmt.init) {
if (stmt->data.for_stmt.init->type == RAVA_AST_VAR_DECL) { if (stmt->data.for_stmt.init->type == RAVA_AST_VAR_DECL) {
_rava_ir_gen_statement(gen, stmt->data.for_stmt.init); _rava_ir_gen_statement(gen, stmt->data.for_stmt.init);
@ -955,7 +1112,14 @@ static void _rava_ir_gen_statement(RavaIRGenerator_t *gen, RavaASTNode_t *stmt)
int continue_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); 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 }; RavaLoopContext_t loop_ctx = {
.break_label = end_label,
.continue_label = continue_label,
.parent = gen->loop_context,
.loop_var_name = loop_var_name,
.loop_var_index = loop_var_index,
.has_bounds_check = has_bounds_check
};
gen->loop_context = &loop_ctx; gen->loop_context = &loop_ctx;
instr.opcode = RAVA_OP_LABEL; instr.opcode = RAVA_OP_LABEL;
@ -1012,7 +1176,14 @@ static void _rava_ir_gen_statement(RavaIRGenerator_t *gen, RavaASTNode_t *stmt)
int continue_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); 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 }; RavaLoopContext_t loop_ctx = {
.break_label = end_label,
.continue_label = continue_label,
.parent = gen->loop_context,
.loop_var_name = NULL,
.loop_var_index = (int)idx_local,
.has_bounds_check = true
};
gen->loop_context = &loop_ctx; gen->loop_context = &loop_ctx;
instr.opcode = RAVA_OP_LABEL; instr.opcode = RAVA_OP_LABEL;
@ -1113,7 +1284,14 @@ static void _rava_ir_gen_statement(RavaIRGenerator_t *gen, RavaASTNode_t *stmt)
case RAVA_AST_SWITCH_STMT: { case RAVA_AST_SWITCH_STMT: {
int end_label = rava_instruction_list_new_label(gen->current_method->instructions); 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 }; RavaLoopContext_t switch_ctx = {
.break_label = end_label,
.continue_label = -1,
.parent = gen->loop_context,
.loop_var_name = NULL,
.loop_var_index = -1,
.has_bounds_check = false
};
gen->loop_context = &switch_ctx; gen->loop_context = &switch_ctx;
size_t case_count = stmt->children_count; size_t case_count = stmt->children_count;
@ -1400,6 +1578,54 @@ static void _rava_ir_gen_class(RavaIRGenerator_t *gen, RavaASTNode_t *class_node
gen->current_class = NULL; gen->current_class = NULL;
} }
static void _rava_ir_gen_enum(RavaIRGenerator_t *gen, RavaASTNode_t *enum_node) {
if (enum_node->type != RAVA_AST_ENUM_DECL) return;
RavaClass_t *class = rava_class_create(enum_node->data.enum_decl.name);
class->is_enum = true;
gen->current_class = class;
rava_symbol_table_enter_scope(gen->analyzer->symbol_table, enum_node->data.enum_decl.name);
if (enum_node->data.enum_decl.constants_count > 0) {
RavaMethod_t *clinit = rava_method_create("<clinit>", NULL);
gen->current_method = clinit;
gen->next_local = 0;
_rava_ir_clear_locals(gen);
RavaInstruction_t instr = {0};
for (size_t i = 0; i < enum_node->data.enum_decl.constants_count; i++) {
instr.opcode = RAVA_OP_LOAD_CONST;
instr.operand.int_value = (int32_t)i;
_rava_ir_emit(gen, instr);
instr.opcode = RAVA_OP_STORE_STATIC;
instr.operand.field.class_name = strdup(enum_node->data.enum_decl.name);
instr.operand.field.field_name = strdup(enum_node->data.enum_decl.constants[i]);
_rava_ir_emit(gen, instr);
}
instr.opcode = RAVA_OP_RETURN_VOID;
_rava_ir_emit(gen, instr);
clinit->local_count = gen->next_local;
rava_class_add_method(gen->current_class, clinit);
gen->current_method = NULL;
}
for (size_t i = 0; i < enum_node->children_count; i++) {
RavaASTNode_t *child = enum_node->children[i];
if (child->type == RAVA_AST_METHOD_DECL) {
_rava_ir_gen_method(gen, child);
}
}
rava_symbol_table_exit_scope(gen->analyzer->symbol_table);
rava_program_add_class(gen->program, class);
gen->current_class = NULL;
}
RavaProgram_t* rava_ir_generate(RavaIRGenerator_t *generator, RavaASTNode_t *root) { RavaProgram_t* rava_ir_generate(RavaIRGenerator_t *generator, RavaASTNode_t *root) {
if (!generator || !root) return NULL; if (!generator || !root) return NULL;
@ -1408,6 +1634,8 @@ RavaProgram_t* rava_ir_generate(RavaIRGenerator_t *generator, RavaASTNode_t *roo
RavaASTNode_t *child = root->children[i]; RavaASTNode_t *child = root->children[i];
if (child->type == RAVA_AST_CLASS_DECL) { if (child->type == RAVA_AST_CLASS_DECL) {
_rava_ir_gen_class(generator, child); _rava_ir_gen_class(generator, child);
} else if (child->type == RAVA_AST_ENUM_DECL) {
_rava_ir_gen_enum(generator, child);
} }
} }
} }

View File

@ -15,6 +15,9 @@ typedef struct RavaLoopContext_t {
int break_label; int break_label;
int continue_label; int continue_label;
struct RavaLoopContext_t *parent; struct RavaLoopContext_t *parent;
char *loop_var_name;
int loop_var_index;
bool has_bounds_check;
} RavaLoopContext_t; } RavaLoopContext_t;
typedef struct { typedef struct {

View File

@ -1,5 +1,6 @@
#define _POSIX_C_SOURCE 200809L #define _POSIX_C_SOURCE 200809L
#include "lexer.h" #include "lexer.h"
#include "../utils/safe_alloc.h"
#include <stdlib.h> #include <stdlib.h>
#include <string.h> #include <string.h>
#include <ctype.h> #include <ctype.h>
@ -73,7 +74,12 @@ RavaToken_t* rava_lexer_parse_string(RavaLexer_t *lexer) {
if (length + 1 >= capacity) { if (length + 1 >= capacity) {
capacity *= 2; capacity *= 2;
str = realloc(str, capacity); char *new_str = rava_safe_realloc(str, capacity);
if (!new_str) {
lexer->error_message = strdup("Out of memory");
return _rava_lexer_create_token(lexer, RAVA_TOKEN_ERROR);
}
str = new_str;
} }
str[length++] = c; str[length++] = c;
} }

View File

@ -1,4 +1,5 @@
#include "lexer.h" #include "lexer.h"
#include "../utils/safe_alloc.h"
#include <stdlib.h> #include <stdlib.h>
#include <string.h> #include <string.h>
#include <ctype.h> #include <ctype.h>
@ -11,6 +12,7 @@ extern RavaToken_t* rava_lexer_parse_number(RavaLexer_t *lexer);
RavaLexer_t* rava_lexer_create(const char *source) { RavaLexer_t* rava_lexer_create(const char *source) {
RavaLexer_t *lexer = malloc(sizeof(RavaLexer_t)); RavaLexer_t *lexer = malloc(sizeof(RavaLexer_t));
if (!lexer) return NULL;
lexer->source = source; lexer->source = source;
lexer->source_length = strlen(source); lexer->source_length = strlen(source);
lexer->current = 0; lexer->current = 0;
@ -116,9 +118,14 @@ void _rava_lexer_skip_whitespace(RavaLexer_t *lexer) {
RavaToken_t* _rava_lexer_create_token(RavaLexer_t *lexer, RavaTokenType_e type) { RavaToken_t* _rava_lexer_create_token(RavaLexer_t *lexer, RavaTokenType_e type) {
RavaToken_t *token = malloc(sizeof(RavaToken_t)); RavaToken_t *token = malloc(sizeof(RavaToken_t));
if (!token) return NULL;
token->type = type; token->type = type;
size_t length = lexer->current - lexer->start; size_t length = lexer->current - lexer->start;
token->lexeme = malloc(length + 1); token->lexeme = malloc(length + 1);
if (!token->lexeme) {
free(token);
return NULL;
}
memcpy(token->lexeme, lexer->source + lexer->start, length); memcpy(token->lexeme, lexer->source + lexer->start, length);
token->lexeme[length] = '\0'; token->lexeme[length] = '\0';
token->line = lexer->line; token->line = lexer->line;
@ -312,8 +319,10 @@ RavaToken_t* rava_lexer_next_token(RavaLexer_t *lexer) {
return rava_lexer_parse_character(lexer); return rava_lexer_parse_character(lexer);
default: default:
lexer->error_message = malloc(100); lexer->error_message = malloc(RAVA_ERROR_BUFFER_SIZE);
snprintf(lexer->error_message, 100, "Unexpected character '%c'", c); if (lexer->error_message) {
snprintf(lexer->error_message, RAVA_ERROR_BUFFER_SIZE, "Unexpected character '%c'", c);
}
return _rava_lexer_create_token(lexer, RAVA_TOKEN_ERROR); return _rava_lexer_create_token(lexer, RAVA_TOKEN_ERROR);
} }
} }

View File

@ -1,11 +1,13 @@
#define _POSIX_C_SOURCE 200809L #define _POSIX_C_SOURCE 200809L
#include "parser.h" #include "parser.h"
#include "../utils/safe_alloc.h"
#include <stdlib.h> #include <stdlib.h>
#include <string.h> #include <string.h>
#include <stdio.h> #include <stdio.h>
RavaASTNode_t* rava_ast_node_create(RavaASTNodeType_e type, int line, int column) { RavaASTNode_t* rava_ast_node_create(RavaASTNodeType_e type, int line, int column) {
RavaASTNode_t *node = calloc(1, sizeof(RavaASTNode_t)); RavaASTNode_t *node = calloc(1, sizeof(RavaASTNode_t));
if (!node) return NULL;
node->type = type; node->type = type;
node->line = line; node->line = line;
node->column = column; node->column = column;
@ -33,6 +35,14 @@ void rava_ast_node_destroy(RavaASTNode_t *node) {
free(node->data.class_decl.modifiers); free(node->data.class_decl.modifiers);
rava_ast_node_destroy(node->data.class_decl.type); rava_ast_node_destroy(node->data.class_decl.type);
break; break;
case RAVA_AST_ENUM_DECL:
free(node->data.enum_decl.name);
free(node->data.enum_decl.modifiers);
for (size_t i = 0; i < node->data.enum_decl.constants_count; i++) {
free(node->data.enum_decl.constants[i]);
}
free(node->data.enum_decl.constants);
break;
case RAVA_AST_METHOD_DECL: case RAVA_AST_METHOD_DECL:
free(node->data.method_decl.name); free(node->data.method_decl.name);
free(node->data.method_decl.modifiers); free(node->data.method_decl.modifiers);
@ -81,7 +91,9 @@ void rava_ast_node_add_child(RavaASTNode_t *parent, RavaASTNode_t *child) {
if (parent->children_count >= parent->children_capacity) { if (parent->children_count >= parent->children_capacity) {
size_t new_capacity = parent->children_capacity == 0 ? 4 : parent->children_capacity * 2; size_t new_capacity = parent->children_capacity == 0 ? 4 : parent->children_capacity * 2;
parent->children = realloc(parent->children, sizeof(RavaASTNode_t*) * new_capacity); RavaASTNode_t **new_children = rava_safe_realloc(parent->children, sizeof(RavaASTNode_t*) * new_capacity);
if (!new_children) return;
parent->children = new_children;
parent->children_capacity = new_capacity; parent->children_capacity = new_capacity;
} }
@ -91,6 +103,7 @@ void rava_ast_node_add_child(RavaASTNode_t *parent, RavaASTNode_t *child) {
RavaParser_t* rava_parser_create(RavaLexer_t *lexer) { RavaParser_t* rava_parser_create(RavaLexer_t *lexer) {
RavaParser_t *parser = malloc(sizeof(RavaParser_t)); RavaParser_t *parser = malloc(sizeof(RavaParser_t));
if (!parser) return NULL;
parser->lexer = lexer; parser->lexer = lexer;
parser->current_token = rava_lexer_next_token(lexer); parser->current_token = rava_lexer_next_token(lexer);
parser->peek_token = rava_lexer_next_token(lexer); parser->peek_token = rava_lexer_next_token(lexer);
@ -134,9 +147,11 @@ bool _rava_parser_expect(RavaParser_t *parser, RavaTokenType_e type, const char
parser->had_error = true; parser->had_error = true;
if (parser->error_message) free(parser->error_message); if (parser->error_message) free(parser->error_message);
parser->error_message = malloc(256); parser->error_message = malloc(RAVA_ERROR_BUFFER_SIZE);
snprintf(parser->error_message, 256, "%s at line %d, column %d", if (parser->error_message) {
snprintf(parser->error_message, RAVA_ERROR_BUFFER_SIZE, "%s at line %d, column %d",
message, parser->current_token->line, parser->current_token->column); message, parser->current_token->line, parser->current_token->column);
}
return false; return false;
} }

View File

@ -170,6 +170,14 @@ struct RavaASTNode_t {
size_t modifiers_count; size_t modifiers_count;
} interface_decl; } interface_decl;
struct {
char *name;
char **constants;
size_t constants_count;
RavaModifier_e *modifiers;
size_t modifiers_count;
} enum_decl;
struct { struct {
char *name; char *name;
RavaASTNode_t *return_type; RavaASTNode_t *return_type;

View File

@ -1,5 +1,6 @@
#define _POSIX_C_SOURCE 200809L #define _POSIX_C_SOURCE 200809L
#include "parser.h" #include "parser.h"
#include "../utils/safe_alloc.h"
#include <stdlib.h> #include <stdlib.h>
#include <string.h> #include <string.h>
@ -96,13 +97,22 @@ RavaASTNode_t* _rava_parser_parse_class_declaration(RavaParser_t *parser) {
if (_rava_parser_match(parser, RAVA_TOKEN_KEYWORD_IMPLEMENTS)) { if (_rava_parser_match(parser, RAVA_TOKEN_KEYWORD_IMPLEMENTS)) {
size_t capacity = 4; size_t capacity = 4;
class_decl->data.class_decl.interfaces = malloc(capacity * sizeof(char*)); class_decl->data.class_decl.interfaces = malloc(capacity * sizeof(char*));
if (!class_decl->data.class_decl.interfaces) {
parser->had_error = true;
return NULL;
}
do { do {
if (_rava_parser_check(parser, RAVA_TOKEN_IDENTIFIER)) { if (_rava_parser_check(parser, RAVA_TOKEN_IDENTIFIER)) {
if (class_decl->data.class_decl.interfaces_count >= capacity) { if (class_decl->data.class_decl.interfaces_count >= capacity) {
capacity *= 2; capacity *= 2;
class_decl->data.class_decl.interfaces = realloc( char **new_interfaces = rava_safe_realloc(
class_decl->data.class_decl.interfaces, class_decl->data.class_decl.interfaces,
capacity * sizeof(char*)); capacity * sizeof(char*));
if (!new_interfaces) {
parser->had_error = true;
return NULL;
}
class_decl->data.class_decl.interfaces = new_interfaces;
} }
class_decl->data.class_decl.interfaces[class_decl->data.class_decl.interfaces_count++] = class_decl->data.class_decl.interfaces[class_decl->data.class_decl.interfaces_count++] =
strdup(parser->current_token->lexeme); strdup(parser->current_token->lexeme);
@ -259,6 +269,112 @@ static RavaASTNode_t* _rava_parser_parse_interface_declaration(RavaParser_t *par
return interface_decl; return interface_decl;
} }
static RavaASTNode_t* _rava_parser_parse_enum_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_ENUM, "Expected 'enum' keyword");
RavaASTNode_t *enum_decl = rava_ast_node_create(RAVA_AST_ENUM_DECL,
parser->current_token->line,
parser->current_token->column);
enum_decl->data.enum_decl.modifiers = modifiers;
enum_decl->data.enum_decl.modifiers_count = modifiers_count;
enum_decl->data.enum_decl.constants = NULL;
enum_decl->data.enum_decl.constants_count = 0;
if (_rava_parser_check(parser, RAVA_TOKEN_IDENTIFIER)) {
enum_decl->data.enum_decl.name = strdup(parser->current_token->lexeme);
_rava_parser_advance(parser);
}
_rava_parser_expect(parser, RAVA_TOKEN_LBRACE, "Expected '{' after enum name");
size_t capacity = 8;
enum_decl->data.enum_decl.constants = malloc(capacity * sizeof(char*));
if (!enum_decl->data.enum_decl.constants) {
parser->had_error = true;
return NULL;
}
while (!_rava_parser_check(parser, RAVA_TOKEN_RBRACE) &&
!_rava_parser_check(parser, RAVA_TOKEN_SEMICOLON) &&
!_rava_parser_check(parser, RAVA_TOKEN_EOF)) {
if (_rava_parser_check(parser, RAVA_TOKEN_IDENTIFIER)) {
if (enum_decl->data.enum_decl.constants_count >= capacity) {
capacity *= 2;
char **new_constants = rava_safe_realloc(
enum_decl->data.enum_decl.constants,
capacity * sizeof(char*));
if (!new_constants) {
parser->had_error = true;
return NULL;
}
enum_decl->data.enum_decl.constants = new_constants;
}
enum_decl->data.enum_decl.constants[enum_decl->data.enum_decl.constants_count++] =
strdup(parser->current_token->lexeme);
_rava_parser_advance(parser);
}
if (!_rava_parser_match(parser, RAVA_TOKEN_COMMA)) {
break;
}
}
if (_rava_parser_match(parser, RAVA_TOKEN_SEMICOLON)) {
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(enum_decl, method);
} else {
RavaASTNode_t *field = rava_ast_node_create(RAVA_AST_FIELD_DECL,
parser->current_token->line,
parser->current_token->column);
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.field_decl.initializer = _rava_parser_parse_expression(parser);
} else {
field->data.field_decl.initializer = NULL;
}
_rava_parser_expect(parser, RAVA_TOKEN_SEMICOLON, "Expected ';' after field");
rava_ast_node_add_child(enum_decl, field);
}
} else {
free(member_modifiers);
}
}
}
_rava_parser_expect(parser, RAVA_TOKEN_RBRACE, "Expected '}' after enum body");
return enum_decl;
}
RavaASTNode_t* rava_parser_parse(RavaParser_t *parser) { RavaASTNode_t* rava_parser_parse(RavaParser_t *parser) {
RavaASTNode_t *root = rava_ast_node_create(RAVA_AST_COMPILATION_UNIT, 1, 1); RavaASTNode_t *root = rava_ast_node_create(RAVA_AST_COMPILATION_UNIT, 1, 1);
@ -283,6 +399,11 @@ RavaASTNode_t* rava_parser_parse(RavaParser_t *parser) {
parser->current_token = saved; parser->current_token = saved;
free(modifiers); free(modifiers);
decl = _rava_parser_parse_class_declaration(parser); decl = _rava_parser_parse_class_declaration(parser);
} else if (_rava_parser_check(parser, RAVA_TOKEN_KEYWORD_ENUM)) {
RavaToken_t *saved = parser->current_token;
parser->current_token = saved;
free(modifiers);
decl = _rava_parser_parse_enum_declaration(parser);
} else { } else {
free(modifiers); free(modifiers);
break; break;

View File

@ -1,5 +1,6 @@
#define _POSIX_C_SOURCE 200809L #define _POSIX_C_SOURCE 200809L
#include "parser.h" #include "parser.h"
#include "../utils/safe_alloc.h"
#include <stdlib.h> #include <stdlib.h>
#include <string.h> #include <string.h>
@ -97,6 +98,10 @@ static RavaASTNode_t* _rava_parser_parse_primary(RavaParser_t *parser) {
if (_rava_parser_match(parser, RAVA_TOKEN_LBRACKET)) { if (_rava_parser_match(parser, RAVA_TOKEN_LBRACKET)) {
size_t args_capacity = 4; size_t args_capacity = 4;
node->data.new_expr.arguments = malloc(sizeof(RavaASTNode_t*) * args_capacity); node->data.new_expr.arguments = malloc(sizeof(RavaASTNode_t*) * args_capacity);
if (!node->data.new_expr.arguments) {
parser->had_error = true;
return NULL;
}
node->data.new_expr.arguments_count = 0; node->data.new_expr.arguments_count = 0;
if (!_rava_parser_check(parser, RAVA_TOKEN_RBRACKET)) { if (!_rava_parser_check(parser, RAVA_TOKEN_RBRACKET)) {
@ -108,8 +113,13 @@ static RavaASTNode_t* _rava_parser_parse_primary(RavaParser_t *parser) {
while (_rava_parser_match(parser, RAVA_TOKEN_LBRACKET)) { while (_rava_parser_match(parser, RAVA_TOKEN_LBRACKET)) {
if (node->data.new_expr.arguments_count >= args_capacity) { if (node->data.new_expr.arguments_count >= args_capacity) {
args_capacity *= 2; args_capacity *= 2;
node->data.new_expr.arguments = realloc(node->data.new_expr.arguments, RavaASTNode_t **new_args = rava_safe_realloc(node->data.new_expr.arguments,
sizeof(RavaASTNode_t*) * args_capacity); sizeof(RavaASTNode_t*) * args_capacity);
if (!new_args) {
parser->had_error = true;
return NULL;
}
node->data.new_expr.arguments = new_args;
} }
if (!_rava_parser_check(parser, RAVA_TOKEN_RBRACKET)) { if (!_rava_parser_check(parser, RAVA_TOKEN_RBRACKET)) {
node->data.new_expr.arguments[node->data.new_expr.arguments_count++] = node->data.new_expr.arguments[node->data.new_expr.arguments_count++] =
@ -129,14 +139,23 @@ static RavaASTNode_t* _rava_parser_parse_primary(RavaParser_t *parser) {
size_t args_capacity = 4; size_t args_capacity = 4;
node->data.new_expr.arguments = malloc(sizeof(RavaASTNode_t*) * args_capacity); node->data.new_expr.arguments = malloc(sizeof(RavaASTNode_t*) * args_capacity);
if (!node->data.new_expr.arguments) {
parser->had_error = true;
return NULL;
}
node->data.new_expr.arguments_count = 0; node->data.new_expr.arguments_count = 0;
if (!_rava_parser_check(parser, RAVA_TOKEN_RPAREN)) { if (!_rava_parser_check(parser, RAVA_TOKEN_RPAREN)) {
do { do {
if (node->data.new_expr.arguments_count >= args_capacity) { if (node->data.new_expr.arguments_count >= args_capacity) {
args_capacity *= 2; args_capacity *= 2;
node->data.new_expr.arguments = realloc(node->data.new_expr.arguments, RavaASTNode_t **new_args = rava_safe_realloc(node->data.new_expr.arguments,
sizeof(RavaASTNode_t*) * args_capacity); sizeof(RavaASTNode_t*) * args_capacity);
if (!new_args) {
parser->had_error = true;
return NULL;
}
node->data.new_expr.arguments = new_args;
} }
node->data.new_expr.arguments[node->data.new_expr.arguments_count++] = node->data.new_expr.arguments[node->data.new_expr.arguments_count++] =
_rava_parser_parse_expression(parser); _rava_parser_parse_expression(parser);
@ -173,14 +192,23 @@ static RavaASTNode_t* _rava_parser_parse_postfix(RavaParser_t *parser) {
size_t args_capacity = 4; size_t args_capacity = 4;
call->data.call.arguments = malloc(sizeof(RavaASTNode_t*) * args_capacity); call->data.call.arguments = malloc(sizeof(RavaASTNode_t*) * args_capacity);
if (!call->data.call.arguments) {
parser->had_error = true;
return NULL;
}
call->data.call.arguments_count = 0; call->data.call.arguments_count = 0;
if (!_rava_parser_check(parser, RAVA_TOKEN_RPAREN)) { if (!_rava_parser_check(parser, RAVA_TOKEN_RPAREN)) {
do { do {
if (call->data.call.arguments_count >= args_capacity) { if (call->data.call.arguments_count >= args_capacity) {
args_capacity *= 2; args_capacity *= 2;
call->data.call.arguments = realloc(call->data.call.arguments, RavaASTNode_t **new_args = rava_safe_realloc(call->data.call.arguments,
sizeof(RavaASTNode_t*) * args_capacity); sizeof(RavaASTNode_t*) * args_capacity);
if (!new_args) {
parser->had_error = true;
return NULL;
}
call->data.call.arguments = new_args;
} }
call->data.call.arguments[call->data.call.arguments_count++] = call->data.call.arguments[call->data.call.arguments_count++] =
_rava_parser_parse_expression(parser); _rava_parser_parse_expression(parser);
@ -576,14 +604,23 @@ RavaASTNode_t* _rava_parser_parse_array_initializer(RavaParser_t *parser) {
size_t capacity = 8; size_t capacity = 8;
node->data.array_init.elements = malloc(sizeof(RavaASTNode_t*) * capacity); node->data.array_init.elements = malloc(sizeof(RavaASTNode_t*) * capacity);
if (!node->data.array_init.elements) {
parser->had_error = true;
return NULL;
}
node->data.array_init.elements_count = 0; node->data.array_init.elements_count = 0;
if (!_rava_parser_check(parser, RAVA_TOKEN_RBRACE)) { if (!_rava_parser_check(parser, RAVA_TOKEN_RBRACE)) {
do { do {
if (node->data.array_init.elements_count >= capacity) { if (node->data.array_init.elements_count >= capacity) {
capacity *= 2; capacity *= 2;
node->data.array_init.elements = realloc(node->data.array_init.elements, RavaASTNode_t **new_elements = rava_safe_realloc(node->data.array_init.elements,
sizeof(RavaASTNode_t*) * capacity); sizeof(RavaASTNode_t*) * capacity);
if (!new_elements) {
parser->had_error = true;
return NULL;
}
node->data.array_init.elements = new_elements;
} }
node->data.array_init.elements[node->data.array_init.elements_count++] = node->data.array_init.elements[node->data.array_init.elements_count++] =
_rava_parser_parse_expression(parser); _rava_parser_parse_expression(parser);

View File

@ -12,6 +12,7 @@ static const char* _rava_ast_node_type_name(RavaASTNodeType_e type) {
switch (type) { switch (type) {
case RAVA_AST_COMPILATION_UNIT: return "CompilationUnit"; case RAVA_AST_COMPILATION_UNIT: return "CompilationUnit";
case RAVA_AST_CLASS_DECL: return "ClassDecl"; case RAVA_AST_CLASS_DECL: return "ClassDecl";
case RAVA_AST_ENUM_DECL: return "EnumDecl";
case RAVA_AST_METHOD_DECL: return "MethodDecl"; case RAVA_AST_METHOD_DECL: return "MethodDecl";
case RAVA_AST_FIELD_DECL: return "FieldDecl"; case RAVA_AST_FIELD_DECL: return "FieldDecl";
case RAVA_AST_CONSTRUCTOR_DECL: return "ConstructorDecl"; case RAVA_AST_CONSTRUCTOR_DECL: return "ConstructorDecl";
@ -53,6 +54,9 @@ void rava_ast_print(RavaASTNode_t *node, int depth) {
case RAVA_AST_CLASS_DECL: case RAVA_AST_CLASS_DECL:
printf(": %s\n", node->data.class_decl.name); printf(": %s\n", node->data.class_decl.name);
break; break;
case RAVA_AST_ENUM_DECL:
printf(": %s\n", node->data.enum_decl.name);
break;
case RAVA_AST_METHOD_DECL: case RAVA_AST_METHOD_DECL:
printf(": %s\n", node->data.method_decl.name); printf(": %s\n", node->data.method_decl.name);
break; break;

View File

@ -12,6 +12,9 @@
#define RAVA_MAX_LOCALS_FIXED 64 #define RAVA_MAX_LOCALS_FIXED 64
#define RAVA_MAX_STACK_FIXED 512 #define RAVA_MAX_STACK_FIXED 512
#define RAVA_INLINE_FRAME_LOCALS 8
#define RAVA_INLINE_FRAME_STACK 16
typedef struct { typedef struct {
RavaMethod_t* method; RavaMethod_t* method;
RavaNanboxValue_t locals[RAVA_MAX_LOCALS_FIXED]; RavaNanboxValue_t locals[RAVA_MAX_LOCALS_FIXED];
@ -22,6 +25,12 @@ typedef struct {
RavaNanboxValue_t this_ref; RavaNanboxValue_t this_ref;
} FastFrame_t; } FastFrame_t;
typedef struct {
RavaNanboxValue_t locals[RAVA_INLINE_FRAME_LOCALS];
RavaNanboxValue_t stack[RAVA_INLINE_FRAME_STACK];
int sp;
} RavaInlineFrame_t;
extern FastFrame_t rava_frame_pool[RAVA_MAX_CALL_DEPTH]; extern FastFrame_t rava_frame_pool[RAVA_MAX_CALL_DEPTH];
extern size_t rava_frame_depth; extern size_t rava_frame_depth;

File diff suppressed because it is too large Load Diff

View File

@ -17,7 +17,9 @@ typedef enum {
RAVA_VAL_NULL, RAVA_VAL_NULL,
RAVA_VAL_OBJECT, RAVA_VAL_OBJECT,
RAVA_VAL_ARRAY, RAVA_VAL_ARRAY,
RAVA_VAL_STRING RAVA_VAL_STRING,
RAVA_VAL_ARRAYLIST,
RAVA_VAL_HASHMAP
} RavaValueType_e; } RavaValueType_e;
typedef struct { typedef struct {
@ -28,6 +30,8 @@ typedef struct {
typedef struct RavaObject_t RavaObject_t; typedef struct RavaObject_t RavaObject_t;
typedef struct RavaValue_t RavaValue_t; typedef struct RavaValue_t RavaValue_t;
typedef struct RavaArrayList_t RavaArrayList_t;
typedef struct RavaHashMap_t RavaHashMap_t;
#define RAVA_OBJECT_HASH_SIZE 32 #define RAVA_OBJECT_HASH_SIZE 32
@ -52,9 +56,36 @@ struct RavaValue_t {
RavaObject_t *object_val; RavaObject_t *object_val;
RavaArray_t *array_val; RavaArray_t *array_val;
char *string_val; char *string_val;
RavaArrayList_t *arraylist_val;
RavaHashMap_t *hashmap_val;
} data; } data;
}; };
#define RAVA_COLLECTION_ARRAYLIST 1
#define RAVA_COLLECTION_HASHMAP 2
struct RavaArrayList_t {
int collection_type;
RavaValue_t *data;
size_t size;
size_t capacity;
};
#define RAVA_HASHMAP_BUCKET_SIZE 32
typedef struct {
char *key;
RavaValue_t value;
bool occupied;
} RavaHashMapEntry_t;
struct RavaHashMap_t {
int collection_type;
RavaHashMapEntry_t *buckets;
size_t bucket_count;
size_t size;
};
typedef struct { typedef struct {
RavaValue_t *values; RavaValue_t *values;
size_t capacity; size_t capacity;
@ -119,7 +150,7 @@ typedef struct {
int current; int current;
} RavaStringPool_t; } RavaStringPool_t;
#define RAVA_INTERN_TABLE_SIZE 256 #define RAVA_INTERN_TABLE_SIZE 1024
typedef struct { typedef struct {
char *strings[RAVA_INTERN_TABLE_SIZE]; char *strings[RAVA_INTERN_TABLE_SIZE];
@ -197,6 +228,20 @@ static inline RavaValue_t rava_value_object(RavaObject_t *obj) {
return val; return val;
} }
static inline RavaValue_t rava_value_arraylist(RavaArrayList_t *list) {
RavaValue_t val;
val.type = RAVA_VAL_ARRAYLIST;
val.data.arraylist_val = list;
return val;
}
static inline RavaValue_t rava_value_hashmap(RavaHashMap_t *map) {
RavaValue_t val;
val.type = RAVA_VAL_HASHMAP;
val.data.hashmap_val = map;
return val;
}
RavaValue_t rava_value_string(const char *str); RavaValue_t rava_value_string(const char *str);
int32_t rava_value_as_int(RavaValue_t value); int32_t rava_value_as_int(RavaValue_t value);
@ -209,6 +254,10 @@ RavaArray_t* rava_array_create(RavaValueType_e element_type, size_t length);
void rava_array_destroy(RavaArray_t *array); void rava_array_destroy(RavaArray_t *array);
void rava_array_set_int(RavaArray_t *array, size_t index, int32_t value); void rava_array_set_int(RavaArray_t *array, size_t index, int32_t value);
int32_t rava_array_get_int(RavaArray_t *array, size_t index); int32_t rava_array_get_int(RavaArray_t *array, size_t index);
void rava_array_set_long(RavaArray_t *array, size_t index, int64_t value);
int64_t rava_array_get_long(RavaArray_t *array, size_t index);
void rava_array_set_double(RavaArray_t *array, size_t index, double value);
double rava_array_get_double(RavaArray_t *array, size_t index);
void rava_array_set_value(RavaArray_t *array, size_t index, RavaValue_t value); void rava_array_set_value(RavaArray_t *array, size_t index, RavaValue_t value);
RavaValue_t rava_array_get_value(RavaArray_t *array, size_t index); RavaValue_t rava_array_get_value(RavaArray_t *array, size_t index);
size_t rava_array_length(RavaArray_t *array); size_t rava_array_length(RavaArray_t *array);
@ -217,6 +266,28 @@ RavaObject_t* rava_object_create(const char *class_name);
void rava_object_destroy(RavaObject_t *obj); void rava_object_destroy(RavaObject_t *obj);
void rava_object_set_field(RavaObject_t *obj, const char *name, RavaValue_t value); void rava_object_set_field(RavaObject_t *obj, const char *name, RavaValue_t value);
RavaValue_t rava_object_get_field(RavaObject_t *obj, const char *name); RavaValue_t rava_object_get_field(RavaObject_t *obj, const char *name);
int rava_object_get_field_index(RavaObject_t *obj, const char *name);
RavaValue_t rava_object_get_field_by_index(RavaObject_t *obj, int index);
void rava_object_set_field_by_index(RavaObject_t *obj, int index, RavaValue_t value);
RavaArrayList_t* rava_arraylist_create(void);
void rava_arraylist_destroy(RavaArrayList_t *list);
void rava_arraylist_add(RavaArrayList_t *list, RavaValue_t value);
RavaValue_t rava_arraylist_get(RavaArrayList_t *list, size_t index);
void rava_arraylist_set(RavaArrayList_t *list, size_t index, RavaValue_t value);
size_t rava_arraylist_size(RavaArrayList_t *list);
RavaValue_t rava_arraylist_remove(RavaArrayList_t *list, size_t index);
void rava_arraylist_clear(RavaArrayList_t *list);
bool rava_arraylist_isempty(RavaArrayList_t *list);
RavaHashMap_t* rava_hashmap_create(void);
void rava_hashmap_destroy(RavaHashMap_t *map);
void rava_hashmap_put(RavaHashMap_t *map, const char *key, RavaValue_t value);
RavaValue_t rava_hashmap_get(RavaHashMap_t *map, const char *key);
RavaValue_t rava_hashmap_remove(RavaHashMap_t *map, const char *key);
size_t rava_hashmap_size(RavaHashMap_t *map);
bool rava_hashmap_containskey(RavaHashMap_t *map, const char *key);
void rava_hashmap_clear(RavaHashMap_t *map);
RavaStack_t* rava_stack_create(size_t capacity); RavaStack_t* rava_stack_create(size_t capacity);
void rava_stack_destroy(RavaStack_t *stack); void rava_stack_destroy(RavaStack_t *stack);

101
runtime/runtime_array.c Normal file
View File

@ -0,0 +1,101 @@
#define _POSIX_C_SOURCE 200809L
#include "runtime.h"
#include <stdlib.h>
#include <stdio.h>
#define RAVA_MAX_ARRAY_LENGTH 1000000
RavaArray_t* rava_array_create(RavaValueType_e element_type, size_t length) {
if (length > RAVA_MAX_ARRAY_LENGTH) {
fprintf(stderr, "Warning: Array size %zu exceeds maximum %d, clamping\n",
length, RAVA_MAX_ARRAY_LENGTH);
length = RAVA_MAX_ARRAY_LENGTH;
}
RavaArray_t *array = malloc(sizeof(RavaArray_t));
if (!array) return NULL;
array->element_type = element_type;
array->length = length;
array->data = NULL;
switch (element_type) {
case RAVA_VAL_INT:
array->data = calloc(length, sizeof(int32_t));
break;
case RAVA_VAL_LONG:
array->data = calloc(length, sizeof(int64_t));
break;
case RAVA_VAL_DOUBLE:
array->data = calloc(length, sizeof(double));
break;
case RAVA_VAL_BOOLEAN:
array->data = calloc(length, sizeof(bool));
break;
case RAVA_VAL_ARRAY:
case RAVA_VAL_OBJECT:
array->data = calloc(length, sizeof(RavaValue_t));
break;
default:
array->data = calloc(length, sizeof(void*));
break;
}
if (!array->data && length > 0) {
free(array);
return NULL;
}
return array;
}
void rava_array_destroy(RavaArray_t *array) {
if (!array) return;
free(array->data);
free(array);
}
void rava_array_set_int(RavaArray_t *array, size_t index, int32_t value) {
if (!array || !array->data || index >= array->length) return;
((int32_t*)array->data)[index] = value;
}
int32_t rava_array_get_int(RavaArray_t *array, size_t index) {
if (!array || !array->data || index >= array->length) return 0;
return ((int32_t*)array->data)[index];
}
void rava_array_set_long(RavaArray_t *array, size_t index, int64_t value) {
if (!array || !array->data || index >= array->length) return;
((int64_t*)array->data)[index] = value;
}
int64_t rava_array_get_long(RavaArray_t *array, size_t index) {
if (!array || !array->data || index >= array->length) return 0;
return ((int64_t*)array->data)[index];
}
void rava_array_set_double(RavaArray_t *array, size_t index, double value) {
if (!array || !array->data || index >= array->length) return;
((double*)array->data)[index] = value;
}
double rava_array_get_double(RavaArray_t *array, size_t index) {
if (!array || !array->data || index >= array->length) return 0.0;
return ((double*)array->data)[index];
}
void rava_array_set_value(RavaArray_t *array, size_t index, RavaValue_t value) {
if (!array || !array->data || index >= array->length) return;
((RavaValue_t*)array->data)[index] = value;
}
RavaValue_t rava_array_get_value(RavaArray_t *array, size_t index) {
if (!array || !array->data || index >= array->length) return rava_value_null();
return ((RavaValue_t*)array->data)[index];
}
size_t rava_array_length(RavaArray_t *array) {
if (!array) return 0;
return array->length;
}

View File

@ -0,0 +1,202 @@
#define _POSIX_C_SOURCE 200809L
#include "runtime.h"
#include <stdlib.h>
#include <string.h>
#define ARRAYLIST_INITIAL_CAPACITY 16
RavaArrayList_t* rava_arraylist_create(void) {
RavaArrayList_t *list = calloc(1, sizeof(RavaArrayList_t));
list->collection_type = RAVA_COLLECTION_ARRAYLIST;
list->data = calloc(ARRAYLIST_INITIAL_CAPACITY, sizeof(RavaValue_t));
list->size = 0;
list->capacity = ARRAYLIST_INITIAL_CAPACITY;
return list;
}
void rava_arraylist_destroy(RavaArrayList_t *list) {
if (!list) return;
free(list->data);
free(list);
}
void rava_arraylist_add(RavaArrayList_t *list, RavaValue_t value) {
if (list->size >= list->capacity) {
list->capacity *= 2;
list->data = realloc(list->data, list->capacity * sizeof(RavaValue_t));
}
list->data[list->size++] = value;
}
RavaValue_t rava_arraylist_get(RavaArrayList_t *list, size_t index) {
if (index >= list->size) {
return rava_value_null();
}
return list->data[index];
}
void rava_arraylist_set(RavaArrayList_t *list, size_t index, RavaValue_t value) {
if (index < list->size) {
list->data[index] = value;
}
}
size_t rava_arraylist_size(RavaArrayList_t *list) {
return list->size;
}
RavaValue_t rava_arraylist_remove(RavaArrayList_t *list, size_t index) {
if (index >= list->size) {
return rava_value_null();
}
RavaValue_t removed = list->data[index];
for (size_t i = index; i < list->size - 1; i++) {
list->data[i] = list->data[i + 1];
}
list->size--;
return removed;
}
void rava_arraylist_clear(RavaArrayList_t *list) {
list->size = 0;
}
bool rava_arraylist_isempty(RavaArrayList_t *list) {
return list->size == 0;
}
static unsigned int _rava_hash_string(const char *str) {
unsigned int hash = 5381;
int c;
while ((c = *str++)) {
hash = ((hash << 5) + hash) + c;
}
return hash;
}
RavaHashMap_t* rava_hashmap_create(void) {
RavaHashMap_t *map = calloc(1, sizeof(RavaHashMap_t));
map->collection_type = RAVA_COLLECTION_HASHMAP;
map->bucket_count = RAVA_HASHMAP_BUCKET_SIZE;
map->buckets = calloc(map->bucket_count, sizeof(RavaHashMapEntry_t));
map->size = 0;
return map;
}
void rava_hashmap_destroy(RavaHashMap_t *map) {
if (!map) return;
for (size_t i = 0; i < map->bucket_count; i++) {
if (map->buckets[i].occupied) {
free(map->buckets[i].key);
}
}
free(map->buckets);
free(map);
}
static void _rava_hashmap_resize(RavaHashMap_t *map) {
size_t old_count = map->bucket_count;
RavaHashMapEntry_t *old_buckets = map->buckets;
map->bucket_count *= 2;
map->buckets = calloc(map->bucket_count, sizeof(RavaHashMapEntry_t));
map->size = 0;
for (size_t i = 0; i < old_count; i++) {
if (old_buckets[i].occupied) {
rava_hashmap_put(map, old_buckets[i].key, old_buckets[i].value);
free(old_buckets[i].key);
}
}
free(old_buckets);
}
void rava_hashmap_put(RavaHashMap_t *map, const char *key, RavaValue_t value) {
if (map->size >= map->bucket_count * 7 / 10) {
_rava_hashmap_resize(map);
}
unsigned int hash = _rava_hash_string(key);
size_t index = hash % map->bucket_count;
while (map->buckets[index].occupied) {
if (strcmp(map->buckets[index].key, key) == 0) {
map->buckets[index].value = value;
return;
}
index = (index + 1) % map->bucket_count;
}
map->buckets[index].key = strdup(key);
map->buckets[index].value = value;
map->buckets[index].occupied = true;
map->size++;
}
RavaValue_t rava_hashmap_get(RavaHashMap_t *map, const char *key) {
unsigned int hash = _rava_hash_string(key);
size_t index = hash % map->bucket_count;
size_t start = index;
while (map->buckets[index].occupied) {
if (strcmp(map->buckets[index].key, key) == 0) {
return map->buckets[index].value;
}
index = (index + 1) % map->bucket_count;
if (index == start) break;
}
return rava_value_null();
}
RavaValue_t rava_hashmap_remove(RavaHashMap_t *map, const char *key) {
unsigned int hash = _rava_hash_string(key);
size_t index = hash % map->bucket_count;
size_t start = index;
while (map->buckets[index].occupied) {
if (strcmp(map->buckets[index].key, key) == 0) {
RavaValue_t removed = map->buckets[index].value;
free(map->buckets[index].key);
map->buckets[index].key = NULL;
map->buckets[index].occupied = false;
map->size--;
return removed;
}
index = (index + 1) % map->bucket_count;
if (index == start) break;
}
return rava_value_null();
}
size_t rava_hashmap_size(RavaHashMap_t *map) {
return map->size;
}
bool rava_hashmap_containskey(RavaHashMap_t *map, const char *key) {
unsigned int hash = _rava_hash_string(key);
size_t index = hash % map->bucket_count;
size_t start = index;
while (map->buckets[index].occupied) {
if (strcmp(map->buckets[index].key, key) == 0) {
return true;
}
index = (index + 1) % map->bucket_count;
if (index == start) break;
}
return false;
}
void rava_hashmap_clear(RavaHashMap_t *map) {
for (size_t i = 0; i < map->bucket_count; i++) {
if (map->buckets[i].occupied) {
free(map->buckets[i].key);
map->buckets[i].key = NULL;
map->buckets[i].occupied = false;
}
}
map->size = 0;
}

133
runtime/runtime_object.c Normal file
View File

@ -0,0 +1,133 @@
#define _POSIX_C_SOURCE 200809L
#include "runtime.h"
#include "../utils/safe_alloc.h"
#include <stdlib.h>
#include <string.h>
static inline uint32_t _rava_field_hash(const char *name) {
uint32_t hash = 5381;
while (*name) {
hash = ((hash << 5) + hash) ^ (uint32_t)*name++;
}
return hash;
}
RavaObject_t* rava_object_create(const char *class_name) {
RavaObject_t *obj = calloc(1, sizeof(RavaObject_t));
if (!obj) return NULL;
obj->class_name = strdup(class_name);
obj->field_capacity = 8;
obj->field_names = calloc(obj->field_capacity, sizeof(char*));
obj->field_values = calloc(obj->field_capacity, sizeof(RavaValue_t));
if (!obj->field_names || !obj->field_values) {
free(obj->field_names);
free(obj->field_values);
free(obj->class_name);
free(obj);
return NULL;
}
obj->field_count = 0;
for (int i = 0; i < RAVA_OBJECT_HASH_SIZE; i++) {
obj->field_hash[i] = -1;
}
return obj;
}
void rava_object_destroy(RavaObject_t *obj) {
if (!obj) return;
free(obj->class_name);
for (size_t i = 0; i < obj->field_count; i++) {
free(obj->field_names[i]);
}
free(obj->field_names);
free(obj->field_values);
free(obj);
}
void rava_object_set_field(RavaObject_t *obj, const char *name, RavaValue_t value) {
if (!obj || !name) return;
uint32_t hash = _rava_field_hash(name);
for (size_t probe = 0; probe < RAVA_OBJECT_HASH_SIZE; probe++) {
uint32_t idx = (hash + probe) & (RAVA_OBJECT_HASH_SIZE - 1);
int field_idx = obj->field_hash[idx];
if (field_idx == -1) {
if (obj->field_count >= obj->field_capacity) {
size_t new_cap = obj->field_capacity * 2;
char **new_names = rava_safe_realloc(obj->field_names, new_cap * sizeof(char*));
RavaValue_t *new_values = rava_safe_realloc(obj->field_values, new_cap * sizeof(RavaValue_t));
if (!new_names || !new_values) return;
obj->field_names = new_names;
obj->field_values = new_values;
obj->field_capacity = new_cap;
}
obj->field_names[obj->field_count] = strdup(name);
obj->field_values[obj->field_count] = value;
obj->field_hash[idx] = (int)obj->field_count;
obj->field_count++;
return;
}
if ((size_t)field_idx < obj->field_count &&
strcmp(obj->field_names[field_idx], name) == 0) {
obj->field_values[field_idx] = value;
return;
}
}
}
RavaValue_t rava_object_get_field(RavaObject_t *obj, const char *name) {
if (!obj || !name) return rava_value_null();
uint32_t hash = _rava_field_hash(name);
for (size_t probe = 0; probe < RAVA_OBJECT_HASH_SIZE; probe++) {
uint32_t idx = (hash + probe) & (RAVA_OBJECT_HASH_SIZE - 1);
int field_idx = obj->field_hash[idx];
if (field_idx == -1) {
return rava_value_null();
}
if ((size_t)field_idx < obj->field_count &&
strcmp(obj->field_names[field_idx], name) == 0) {
return obj->field_values[field_idx];
}
}
return rava_value_null();
}
int rava_object_get_field_index(RavaObject_t *obj, const char *name) {
if (!obj || !name) return -1;
uint32_t hash = _rava_field_hash(name);
for (size_t probe = 0; probe < RAVA_OBJECT_HASH_SIZE; probe++) {
uint32_t idx = (hash + probe) & (RAVA_OBJECT_HASH_SIZE - 1);
int field_idx = obj->field_hash[idx];
if (field_idx == -1) return -1;
if ((size_t)field_idx < obj->field_count &&
strcmp(obj->field_names[field_idx], name) == 0) {
return field_idx;
}
}
return -1;
}
RavaValue_t rava_object_get_field_by_index(RavaObject_t *obj, int index) {
if (!obj || index < 0 || (size_t)index >= obj->field_count) {
return rava_value_null();
}
return obj->field_values[index];
}
void rava_object_set_field_by_index(RavaObject_t *obj, int index, RavaValue_t value) {
if (!obj || index < 0 || (size_t)index >= obj->field_count) return;
obj->field_values[index] = value;
}

View File

@ -1,4 +1,5 @@
#include "superinst.h" #include "superinst.h"
#include "fastframe.h"
#include <string.h> #include <string.h>
static void optimize_inc_dec_local(RavaInstruction_t *instrs, size_t count) { static void optimize_inc_dec_local(RavaInstruction_t *instrs, size_t count) {
@ -135,12 +136,148 @@ static void optimize_local_lt_local_jump(RavaInstruction_t *instrs, size_t count
} }
} }
static int is_power_of_two(int64_t n) {
return n > 0 && (n & (n - 1)) == 0;
}
static int log2_int(int64_t n) {
int result = 0;
while (n > 1) {
n >>= 1;
result++;
}
return result;
}
static void optimize_strength_reduction(RavaInstruction_t *instrs, size_t count) {
for (size_t i = 0; i + 2 < count; i++) {
if (instrs[i+1].opcode == RAVA_OP_LOAD_CONST) {
int64_t const_val = instrs[i+1].operand.int_value;
if (instrs[i+2].opcode == RAVA_OP_MUL && is_power_of_two(const_val)) {
int shift_amount = log2_int(const_val);
instrs[i+1].operand.int_value = shift_amount;
instrs[i+2].opcode = RAVA_OP_SHL;
}
else if (instrs[i+2].opcode == RAVA_OP_DIV && is_power_of_two(const_val)) {
int shift_amount = log2_int(const_val);
instrs[i+1].operand.int_value = shift_amount;
instrs[i+2].opcode = RAVA_OP_SHR;
}
else if (instrs[i+2].opcode == RAVA_OP_MOD && const_val == 2) {
instrs[i+1].operand.int_value = 1;
instrs[i+2].opcode = RAVA_OP_AND;
}
}
}
}
static void optimize_constant_folding(RavaInstruction_t *instrs, size_t count) {
for (size_t i = 0; i + 2 < count; i++) {
if (instrs[i].opcode == RAVA_OP_LOAD_CONST &&
instrs[i+1].opcode == RAVA_OP_LOAD_CONST) {
int64_t val1 = instrs[i].operand.int_value;
int64_t val2 = instrs[i+1].operand.int_value;
int64_t result = 0;
int can_fold = 1;
switch (instrs[i+2].opcode) {
case RAVA_OP_ADD:
result = val1 + val2;
break;
case RAVA_OP_SUB:
result = val1 - val2;
break;
case RAVA_OP_MUL:
result = val1 * val2;
break;
case RAVA_OP_DIV:
if (val2 != 0) {
result = val1 / val2;
} else {
can_fold = 0;
}
break;
case RAVA_OP_MOD:
if (val2 != 0) {
result = val1 % val2;
} else {
can_fold = 0;
}
break;
case RAVA_OP_AND:
result = val1 & val2;
break;
case RAVA_OP_OR:
result = val1 | val2;
break;
case RAVA_OP_XOR:
result = val1 ^ val2;
break;
case RAVA_OP_SHL:
result = val1 << val2;
break;
case RAVA_OP_SHR:
result = val1 >> val2;
break;
case RAVA_OP_EQ:
result = val1 == val2;
break;
case RAVA_OP_NE:
result = val1 != val2;
break;
case RAVA_OP_LT:
result = val1 < val2;
break;
case RAVA_OP_LE:
result = val1 <= val2;
break;
case RAVA_OP_GT:
result = val1 > val2;
break;
case RAVA_OP_GE:
result = val1 >= val2;
break;
default:
can_fold = 0;
break;
}
if (can_fold) {
instrs[i].operand.int_value = result;
instrs[i+1].opcode = RAVA_OP_NOP;
instrs[i+2].opcode = RAVA_OP_NOP;
}
}
}
}
static void optimize_inline_calls(RavaInstruction_t *instrs, size_t count) {
for (size_t i = 0; i < count; i++) {
if (instrs[i].opcode == RAVA_OP_CALL_STATIC ||
instrs[i].opcode == RAVA_OP_CALL_RECURSIVE) {
RavaMethod_t *target = (RavaMethod_t*)instrs[i].operand.call.cached_method;
if (target && target->is_simple && target->is_leaf &&
target->local_count <= RAVA_INLINE_FRAME_LOCALS &&
target->max_stack <= RAVA_INLINE_FRAME_STACK) {
instrs[i].opcode = RAVA_OP_CALL_INLINE;
}
}
}
}
void rava_optimize_superinstructions(RavaMethod_t* method) { void rava_optimize_superinstructions(RavaMethod_t* method) {
if (!method || !method->instructions) return; if (!method || !method->instructions) return;
RavaInstruction_t *instrs = method->instructions->instructions; RavaInstruction_t *instrs = method->instructions->instructions;
size_t count = method->instructions->count; size_t count = method->instructions->count;
optimize_constant_folding(instrs, count);
optimize_inline_calls(instrs, count);
optimize_strength_reduction(instrs, count);
optimize_add_local_to_local(instrs, count); optimize_add_local_to_local(instrs, count);
optimize_local_lt_local_jump(instrs, count); optimize_local_lt_local_jump(instrs, count);
optimize_inc_dec_local(instrs, count); optimize_inc_dec_local(instrs, count);

View File

@ -1,5 +1,6 @@
#define _POSIX_C_SOURCE 200809L #define _POSIX_C_SOURCE 200809L
#include "semantic.h" #include "semantic.h"
#include "../utils/safe_alloc.h"
#include <stdlib.h> #include <stdlib.h>
#include <string.h> #include <string.h>
#include <stdio.h> #include <stdio.h>
@ -10,7 +11,12 @@ static RavaType_t* _rava_semantic_check_expression(RavaSemanticAnalyzer_t *analy
RavaSemanticAnalyzer_t* rava_semantic_analyzer_create() { RavaSemanticAnalyzer_t* rava_semantic_analyzer_create() {
RavaSemanticAnalyzer_t *analyzer = calloc(1, sizeof(RavaSemanticAnalyzer_t)); RavaSemanticAnalyzer_t *analyzer = calloc(1, sizeof(RavaSemanticAnalyzer_t));
if (!analyzer) return NULL;
analyzer->symbol_table = rava_symbol_table_create(); analyzer->symbol_table = rava_symbol_table_create();
if (!analyzer->symbol_table) {
free(analyzer);
return NULL;
}
analyzer->error_message = NULL; analyzer->error_message = NULL;
analyzer->had_error = false; analyzer->had_error = false;
analyzer->error_count = 0; analyzer->error_count = 0;
@ -29,8 +35,9 @@ static void _rava_semantic_error(RavaSemanticAnalyzer_t *analyzer, const char *m
analyzer->error_count++; analyzer->error_count++;
if (analyzer->error_message) free(analyzer->error_message); if (analyzer->error_message) free(analyzer->error_message);
analyzer->error_message = malloc(512); analyzer->error_message = malloc(RAVA_ERROR_BUFFER_SIZE);
snprintf(analyzer->error_message, 512, "Semantic error at line %d, column %d: %s", if (!analyzer->error_message) return;
snprintf(analyzer->error_message, RAVA_ERROR_BUFFER_SIZE, "Semantic error at line %d, column %d: %s",
line, col, message); line, col, message);
} }
@ -75,6 +82,41 @@ static bool _rava_semantic_analyze_class(RavaSemanticAnalyzer_t *analyzer, RavaA
return !analyzer->had_error; return !analyzer->had_error;
} }
static bool _rava_semantic_analyze_enum(RavaSemanticAnalyzer_t *analyzer, RavaASTNode_t *enum_node) {
if (enum_node->type != RAVA_AST_ENUM_DECL) return false;
char *enum_name = enum_node->data.enum_decl.name;
RavaType_t *enum_type = rava_type_create_class(enum_name);
RavaSymbol_t *enum_symbol = rava_symbol_create(RAVA_SYMBOL_ENUM, enum_name, enum_type);
enum_symbol->modifiers = enum_node->data.enum_decl.modifiers;
enum_symbol->modifiers_count = enum_node->data.enum_decl.modifiers_count;
enum_symbol->declaration = enum_node;
if (!rava_symbol_table_define(analyzer->symbol_table, enum_symbol)) {
_rava_semantic_error(analyzer, "Enum already defined", enum_node->line, enum_node->column);
rava_symbol_destroy(enum_symbol);
return false;
}
rava_symbol_table_enter_scope(analyzer->symbol_table, enum_name);
for (size_t i = 0; i < enum_node->data.enum_decl.constants_count; i++) {
char *const_name = enum_node->data.enum_decl.constants[i];
RavaType_t *const_type = rava_type_create_class(enum_name);
RavaSymbol_t *const_symbol = rava_symbol_create(RAVA_SYMBOL_FIELD, const_name, const_type);
rava_symbol_table_define(analyzer->symbol_table, const_symbol);
}
for (size_t i = 0; i < enum_node->children_count; i++) {
_rava_semantic_analyze_node(analyzer, enum_node->children[i]);
}
rava_symbol_table_exit_scope(analyzer->symbol_table);
return !analyzer->had_error;
}
static bool _rava_semantic_analyze_method(RavaSemanticAnalyzer_t *analyzer, RavaASTNode_t *method_node) { static bool _rava_semantic_analyze_method(RavaSemanticAnalyzer_t *analyzer, RavaASTNode_t *method_node) {
if (method_node->type != RAVA_AST_METHOD_DECL) return false; if (method_node->type != RAVA_AST_METHOD_DECL) return false;
@ -323,6 +365,12 @@ static RavaType_t* _rava_semantic_check_expression(RavaSemanticAnalyzer_t *analy
return rava_type_create_primitive(RAVA_TYPE_BOOLEAN); return rava_type_create_primitive(RAVA_TYPE_BOOLEAN);
} else if (strcmp(method, "compareTo") == 0) { } else if (strcmp(method, "compareTo") == 0) {
return rava_type_create_primitive(RAVA_TYPE_INT); return rava_type_create_primitive(RAVA_TYPE_INT);
} else if (strcmp(method, "size") == 0) {
return rava_type_create_primitive(RAVA_TYPE_INT);
} else if (strcmp(method, "isEmpty") == 0) {
return rava_type_create_primitive(RAVA_TYPE_BOOLEAN);
} else if (strcmp(method, "containsKey") == 0) {
return rava_type_create_primitive(RAVA_TYPE_BOOLEAN);
} }
} }
return rava_type_create_primitive(RAVA_TYPE_INT); return rava_type_create_primitive(RAVA_TYPE_INT);
@ -451,6 +499,9 @@ static bool _rava_semantic_analyze_node(RavaSemanticAnalyzer_t *analyzer, RavaAS
case RAVA_AST_CLASS_DECL: case RAVA_AST_CLASS_DECL:
return _rava_semantic_analyze_class(analyzer, node); return _rava_semantic_analyze_class(analyzer, node);
case RAVA_AST_ENUM_DECL:
return _rava_semantic_analyze_enum(analyzer, node);
case RAVA_AST_METHOD_DECL: case RAVA_AST_METHOD_DECL:
return _rava_semantic_analyze_method(analyzer, node); return _rava_semantic_analyze_method(analyzer, node);

View File

@ -10,6 +10,7 @@
typedef enum { typedef enum {
RAVA_SYMBOL_CLASS, RAVA_SYMBOL_CLASS,
RAVA_SYMBOL_ENUM,
RAVA_SYMBOL_METHOD, RAVA_SYMBOL_METHOD,
RAVA_SYMBOL_FIELD, RAVA_SYMBOL_FIELD,
RAVA_SYMBOL_VARIABLE, RAVA_SYMBOL_VARIABLE,

32
utils/safe_alloc.h Normal file
View File

@ -0,0 +1,32 @@
#ifndef RAVA_SAFE_ALLOC_H
#define RAVA_SAFE_ALLOC_H
#include <stdlib.h>
#include <stdio.h>
#define RAVA_ERROR_BUFFER_SIZE 512
static inline void* rava_safe_realloc(void *ptr, size_t size) {
if (size == 0) {
free(ptr);
return NULL;
}
void *new_ptr = realloc(ptr, size);
if (!new_ptr) {
free(ptr);
return NULL;
}
return new_ptr;
}
static inline void* rava_safe_malloc(size_t size) {
if (size == 0) return NULL;
return malloc(size);
}
static inline void* rava_safe_calloc(size_t count, size_t size) {
if (count == 0 || size == 0) return NULL;
return calloc(count, size);
}
#endif