Compare commits
2 Commits
c8fe57191c
...
1afd91c1c7
| Author | SHA1 | Date | |
|---|---|---|---|
| 1afd91c1c7 | |||
| e1ddf91281 |
29
Makefile
29
Makefile
@ -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 ==="
|
||||||
|
|||||||
54
ir/ir.c
54
ir/ir.c
@ -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
25
ir/ir.h
@ -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 {
|
||||||
|
|||||||
266
ir/ir_gen.c
266
ir/ir_gen.c
@ -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,18 +426,27 @@ 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) {
|
||||||
instr.opcode = RAVA_OP_NEW;
|
const char *type_name = expr->data.new_expr.type->data.type.type_name;
|
||||||
instr.operand.call.class_name = strdup(expr->data.new_expr.type->data.type.type_name);
|
if (strcmp(type_name, "ArrayList") == 0) {
|
||||||
instr.operand.call.arg_count = expr->data.new_expr.arguments_count;
|
instr.opcode = RAVA_OP_ARRAYLIST_NEW;
|
||||||
_rava_ir_emit(gen, instr);
|
_rava_ir_emit(gen, instr);
|
||||||
instr.opcode = RAVA_OP_DUP;
|
} else if (strcmp(type_name, "HashMap") == 0) {
|
||||||
_rava_ir_emit(gen, instr);
|
instr.opcode = RAVA_OP_HASHMAP_NEW;
|
||||||
for (size_t i = 0; i < expr->data.new_expr.arguments_count; i++) {
|
_rava_ir_emit(gen, instr);
|
||||||
_rava_ir_gen_expression(gen, expr->data.new_expr.arguments[i]);
|
} else {
|
||||||
|
instr.opcode = RAVA_OP_NEW;
|
||||||
|
instr.operand.call.class_name = strdup(type_name);
|
||||||
|
instr.operand.call.arg_count = expr->data.new_expr.arguments_count;
|
||||||
|
_rava_ir_emit(gen, instr);
|
||||||
|
instr.opcode = RAVA_OP_DUP;
|
||||||
|
_rava_ir_emit(gen, instr);
|
||||||
|
for (size_t i = 0; i < expr->data.new_expr.arguments_count; i++) {
|
||||||
|
_rava_ir_gen_expression(gen, expr->data.new_expr.arguments[i]);
|
||||||
|
}
|
||||||
|
instr.opcode = RAVA_OP_CALL_VIRTUAL;
|
||||||
|
instr.operand.call.method_name = strdup("<init>");
|
||||||
|
_rava_ir_emit(gen, instr);
|
||||||
}
|
}
|
||||||
instr.opcode = RAVA_OP_CALL_VIRTUAL;
|
|
||||||
instr.operand.call.method_name = strdup("<init>");
|
|
||||||
_rava_ir_emit(gen, instr);
|
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
@ -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);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -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 {
|
||||||
|
|||||||
@ -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;
|
||||||
}
|
}
|
||||||
|
|||||||
@ -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);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -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) {
|
||||||
message, parser->current_token->line, parser->current_token->column);
|
snprintf(parser->error_message, RAVA_ERROR_BUFFER_SIZE, "%s at line %d, column %d",
|
||||||
|
message, parser->current_token->line, parser->current_token->column);
|
||||||
|
}
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -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;
|
||||||
|
|||||||
@ -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;
|
||||||
|
|||||||
@ -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);
|
||||||
|
|||||||
@ -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;
|
||||||
|
|||||||
@ -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
@ -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
101
runtime/runtime_array.c
Normal 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;
|
||||||
|
}
|
||||||
202
runtime/runtime_collections.c
Normal file
202
runtime/runtime_collections.c
Normal 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
133
runtime/runtime_object.c
Normal 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;
|
||||||
|
}
|
||||||
@ -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);
|
||||||
|
|||||||
@ -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);
|
||||||
|
|
||||||
|
|||||||
@ -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
32
utils/safe_alloc.h
Normal 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
|
||||||
Loading…
Reference in New Issue
Block a user