Update.
Some checks failed
CI / Optimization Infrastructure Tests (push) Failing after 13s
CI / Unit Tests (push) Failing after 29s
CI / Integration Tests (push) Has been skipped
CI / Performance Benchmark (push) Has been skipped

This commit is contained in:
retoor 2025-12-04 16:49:20 +01:00
parent e1ddf91281
commit 1afd91c1c7
13 changed files with 1046 additions and 18 deletions

View File

@ -17,7 +17,7 @@ SEMANTIC_OBJECTS = $(SEMANTIC_SOURCES:.c=.o)
IR_SOURCES = ir/ir.c ir/ir_gen.c
IR_OBJECTS = $(IR_SOURCES:.c=.o)
RUNTIME_SOURCES = runtime/runtime.c runtime/runtime_array.c runtime/runtime_object.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)
PHASE0_SOURCES = runtime/fastframe.c runtime/labeltable.c runtime/methodcache.c
@ -101,7 +101,13 @@ TEST_STATIC_INIT_OBJECTS = $(TEST_STATIC_INIT_SOURCES:.c=.o)
TEST_NEGATIVE_SOURCES = tests/test_negative.c
TEST_NEGATIVE_OBJECTS = $(TEST_NEGATIVE_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_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)
$(CC) $(CFLAGS) -o $@ $^ $(LDFLAGS)
@ -181,6 +187,12 @@ test_static_init: $(LEXER_OBJECTS) $(PARSER_OBJECTS) $(TYPES_OBJECTS) $(SEMANTIC
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
$(CC) $(CFLAGS) -c $< -o $@
@ -246,8 +258,8 @@ clean:
$(PHASE0_OBJECTS) \
$(TEST_LEXER_OBJECTS) $(TEST_PARSER_OBJECTS) $(TEST_SEMANTIC_OBJECTS) $(TEST_IR_OBJECTS) $(TEST_RUNTIME_OBJECTS) \
$(TEST_STRINGS_OBJECTS) $(TEST_ARRAYS_OBJECTS) $(TEST_OBJECTS_OBJECTS) $(TEST_INSTANCE_OBJECTS) $(TEST_FILEIO_OBJECTS) \
$(TEST_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_BENCHMARK_OBJECTS) \
test_lexer test_parser test_semantic test_ir test_runtime test_strings test_arrays test_objects test_instance_methods test_fileio test_dowhile test_switch test_math test_string_methods test_static test_interfaces test_exceptions test_ternary test_bitwise test_enhanced_for test_array_init test_instanceof test_shortcircuit test_multidim_arrays test_static_init test_negative test_benchmark \
$(TEST_DOWHILE_OBJECTS) $(TEST_SWITCH_OBJECTS) $(TEST_MATH_OBJECTS) $(TEST_STRING_METHODS_OBJECTS) $(TEST_STATIC_OBJECTS) $(TEST_INTERFACES_OBJECTS) $(TEST_EXCEPTIONS_OBJECTS) $(TEST_TERNARY_OBJECTS) $(TEST_BITWISE_OBJECTS) $(TEST_ENHANCED_FOR_OBJECTS) $(TEST_ARRAY_INIT_OBJECTS) $(TEST_INSTANCEOF_OBJECTS) $(TEST_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_negative test_enums test_collections test_benchmark \
test_nanbox test_fastframe test_labeltable test_methodcache test_benchmark_pgo *.gcda */*.gcda
.PHONY: all clean benchmark test_phase0 pgo test_benchmark_pgo_gen pgo_run test_benchmark_pgo test
@ -260,4 +272,5 @@ test: all
./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 && \
echo "" && echo "=== All Tests Passed ==="

15
ir/ir.c
View File

@ -265,6 +265,21 @@ static const char* _rava_opcode_name(RavaOpCode_e opcode) {
case RAVA_OP_DUP: return "DUP";
case RAVA_OP_PRINT: return "PRINT";
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";
}
}

20
ir/ir.h
View File

@ -127,7 +127,24 @@ typedef enum {
RAVA_OP_MATH_TAN,
RAVA_OP_MATH_LOG,
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;
typedef union {
@ -212,6 +229,7 @@ typedef struct {
size_t method_count;
size_t method_capacity;
int method_hash[RAVA_METHOD_HASH_SIZE];
bool is_enum;
} RavaClass_t;
typedef struct {

View File

@ -426,8 +426,16 @@ static void _rava_ir_gen_expression(RavaIRGenerator_t *gen, RavaASTNode_t *expr)
_rava_ir_emit(gen, instr);
}
} else if (expr->data.new_expr.type) {
const char *type_name = expr->data.new_expr.type->data.type.type_name;
if (strcmp(type_name, "ArrayList") == 0) {
instr.opcode = RAVA_OP_ARRAYLIST_NEW;
_rava_ir_emit(gen, instr);
} else if (strcmp(type_name, "HashMap") == 0) {
instr.opcode = RAVA_OP_HASHMAP_NEW;
_rava_ir_emit(gen, instr);
} else {
instr.opcode = RAVA_OP_NEW;
instr.operand.call.class_name = strdup(expr->data.new_expr.type->data.type.type_name);
instr.operand.call.class_name = strdup(type_name);
instr.operand.call.arg_count = expr->data.new_expr.arguments_count;
_rava_ir_emit(gen, instr);
instr.opcode = RAVA_OP_DUP;
@ -439,6 +447,7 @@ static void _rava_ir_gen_expression(RavaIRGenerator_t *gen, RavaASTNode_t *expr)
instr.operand.call.method_name = strdup("<init>");
_rava_ir_emit(gen, instr);
}
}
break;
case RAVA_AST_CALL_EXPR: {
@ -476,7 +485,17 @@ static void _rava_ir_gen_expression(RavaIRGenerator_t *gen, RavaASTNode_t *expr)
bool is_math_log = false;
bool is_math_exp = 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 *collection_object = NULL;
if (expr->data.call.callee->type == RAVA_AST_MEMBER_ACCESS_EXPR) {
RavaASTNode_t *member = expr->data.call.callee;
@ -581,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) {
is_string_trim = true;
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;
}
}
@ -722,6 +768,50 @@ static void _rava_ir_gen_expression(RavaIRGenerator_t *gen, RavaASTNode_t *expr)
} else if (is_math_random) {
instr.opcode = RAVA_OP_MATH_RANDOM;
_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) {
for (size_t i = 0; i < expr->data.call.arguments_count; i++) {
_rava_ir_gen_expression(gen, expr->data.call.arguments[i]);
@ -1488,6 +1578,54 @@ static void _rava_ir_gen_class(RavaIRGenerator_t *gen, RavaASTNode_t *class_node
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) {
if (!generator || !root) return NULL;
@ -1496,6 +1634,8 @@ RavaProgram_t* rava_ir_generate(RavaIRGenerator_t *generator, RavaASTNode_t *roo
RavaASTNode_t *child = root->children[i];
if (child->type == RAVA_AST_CLASS_DECL) {
_rava_ir_gen_class(generator, child);
} else if (child->type == RAVA_AST_ENUM_DECL) {
_rava_ir_gen_enum(generator, child);
}
}
}

View File

@ -35,6 +35,14 @@ void rava_ast_node_destroy(RavaASTNode_t *node) {
free(node->data.class_decl.modifiers);
rava_ast_node_destroy(node->data.class_decl.type);
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:
free(node->data.method_decl.name);
free(node->data.method_decl.modifiers);

View File

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

View File

@ -269,6 +269,112 @@ static RavaASTNode_t* _rava_parser_parse_interface_declaration(RavaParser_t *par
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 *root = rava_ast_node_create(RAVA_AST_COMPILATION_UNIT, 1, 1);
@ -293,6 +399,11 @@ RavaASTNode_t* rava_parser_parse(RavaParser_t *parser) {
parser->current_token = saved;
free(modifiers);
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 {
free(modifiers);
break;

View File

@ -12,6 +12,7 @@ static const char* _rava_ast_node_type_name(RavaASTNodeType_e type) {
switch (type) {
case RAVA_AST_COMPILATION_UNIT: return "CompilationUnit";
case RAVA_AST_CLASS_DECL: return "ClassDecl";
case RAVA_AST_ENUM_DECL: return "EnumDecl";
case RAVA_AST_METHOD_DECL: return "MethodDecl";
case RAVA_AST_FIELD_DECL: return "FieldDecl";
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:
printf(": %s\n", node->data.class_decl.name);
break;
case RAVA_AST_ENUM_DECL:
printf(": %s\n", node->data.enum_decl.name);
break;
case RAVA_AST_METHOD_DECL:
printf(": %s\n", node->data.method_decl.name);
break;

View File

@ -1661,6 +1661,156 @@ static bool _rava_vm_execute_instruction(RavaVM_t *vm, RavaCallFrame_t *frame, R
break;
}
case RAVA_OP_ARRAYLIST_NEW: {
RavaArrayList_t *list = rava_arraylist_create();
rava_stack_push(stack, rava_value_arraylist(list));
break;
}
case RAVA_OP_ARRAYLIST_ADD: {
RavaValue_t value = rava_stack_pop(stack);
RavaValue_t list_val = rava_stack_pop(stack);
if (list_val.type == RAVA_VAL_ARRAYLIST) {
rava_arraylist_add(list_val.data.arraylist_val, value);
}
break;
}
case RAVA_OP_ARRAYLIST_GET: {
RavaValue_t index_or_key = rava_stack_pop(stack);
RavaValue_t coll_val = rava_stack_pop(stack);
if (coll_val.type == RAVA_VAL_ARRAYLIST) {
rava_stack_push(stack, rava_arraylist_get(coll_val.data.arraylist_val, (size_t)rava_value_as_int(index_or_key)));
} else if (coll_val.type == RAVA_VAL_HASHMAP && index_or_key.type == RAVA_VAL_STRING) {
rava_stack_push(stack, rava_hashmap_get(coll_val.data.hashmap_val, index_or_key.data.string_val));
} else {
rava_stack_push(stack, rava_value_null());
}
break;
}
case RAVA_OP_ARRAYLIST_SET: {
RavaValue_t value = rava_stack_pop(stack);
RavaValue_t index = rava_stack_pop(stack);
RavaValue_t list_val = rava_stack_pop(stack);
if (list_val.type == RAVA_VAL_ARRAYLIST) {
rava_arraylist_set(list_val.data.arraylist_val, (size_t)rava_value_as_int(index), value);
}
break;
}
case RAVA_OP_ARRAYLIST_SIZE: {
RavaValue_t coll_val = rava_stack_pop(stack);
if (coll_val.type == RAVA_VAL_ARRAYLIST) {
rava_stack_push(stack, rava_value_int((int32_t)rava_arraylist_size(coll_val.data.arraylist_val)));
} else if (coll_val.type == RAVA_VAL_HASHMAP) {
rava_stack_push(stack, rava_value_int((int32_t)rava_hashmap_size(coll_val.data.hashmap_val)));
} else {
rava_stack_push(stack, rava_value_int(0));
}
break;
}
case RAVA_OP_ARRAYLIST_REMOVE: {
RavaValue_t index_or_key = rava_stack_pop(stack);
RavaValue_t coll_val = rava_stack_pop(stack);
if (coll_val.type == RAVA_VAL_ARRAYLIST) {
rava_stack_push(stack, rava_arraylist_remove(coll_val.data.arraylist_val, (size_t)rava_value_as_int(index_or_key)));
} else if (coll_val.type == RAVA_VAL_HASHMAP && index_or_key.type == RAVA_VAL_STRING) {
rava_stack_push(stack, rava_hashmap_remove(coll_val.data.hashmap_val, index_or_key.data.string_val));
} else {
rava_stack_push(stack, rava_value_null());
}
break;
}
case RAVA_OP_ARRAYLIST_CLEAR: {
RavaValue_t coll_val = rava_stack_pop(stack);
if (coll_val.type == RAVA_VAL_ARRAYLIST) {
rava_arraylist_clear(coll_val.data.arraylist_val);
} else if (coll_val.type == RAVA_VAL_HASHMAP) {
rava_hashmap_clear(coll_val.data.hashmap_val);
}
break;
}
case RAVA_OP_ARRAYLIST_ISEMPTY: {
RavaValue_t list_val = rava_stack_pop(stack);
if (list_val.type == RAVA_VAL_ARRAYLIST) {
rava_stack_push(stack, rava_value_boolean(rava_arraylist_isempty(list_val.data.arraylist_val)));
} else {
rava_stack_push(stack, rava_value_boolean(true));
}
break;
}
case RAVA_OP_HASHMAP_NEW: {
RavaHashMap_t *map = rava_hashmap_create();
rava_stack_push(stack, rava_value_hashmap(map));
break;
}
case RAVA_OP_HASHMAP_PUT: {
RavaValue_t value = rava_stack_pop(stack);
RavaValue_t key_val = rava_stack_pop(stack);
RavaValue_t map_val = rava_stack_pop(stack);
if (map_val.type == RAVA_VAL_HASHMAP && key_val.type == RAVA_VAL_STRING) {
rava_hashmap_put(map_val.data.hashmap_val, key_val.data.string_val, value);
}
break;
}
case RAVA_OP_HASHMAP_GET: {
RavaValue_t key_val = rava_stack_pop(stack);
RavaValue_t map_val = rava_stack_pop(stack);
if (map_val.type == RAVA_VAL_HASHMAP && key_val.type == RAVA_VAL_STRING) {
rava_stack_push(stack, rava_hashmap_get(map_val.data.hashmap_val, key_val.data.string_val));
} else {
rava_stack_push(stack, rava_value_null());
}
break;
}
case RAVA_OP_HASHMAP_REMOVE: {
RavaValue_t key_val = rava_stack_pop(stack);
RavaValue_t map_val = rava_stack_pop(stack);
if (map_val.type == RAVA_VAL_HASHMAP && key_val.type == RAVA_VAL_STRING) {
rava_stack_push(stack, rava_hashmap_remove(map_val.data.hashmap_val, key_val.data.string_val));
} else {
rava_stack_push(stack, rava_value_null());
}
break;
}
case RAVA_OP_HASHMAP_SIZE: {
RavaValue_t map_val = rava_stack_pop(stack);
if (map_val.type == RAVA_VAL_HASHMAP) {
rava_stack_push(stack, rava_value_int((int32_t)rava_hashmap_size(map_val.data.hashmap_val)));
} else {
rava_stack_push(stack, rava_value_int(0));
}
break;
}
case RAVA_OP_HASHMAP_CONTAINSKEY: {
RavaValue_t key_val = rava_stack_pop(stack);
RavaValue_t map_val = rava_stack_pop(stack);
if (map_val.type == RAVA_VAL_HASHMAP && key_val.type == RAVA_VAL_STRING) {
rava_stack_push(stack, rava_value_boolean(rava_hashmap_containskey(map_val.data.hashmap_val, key_val.data.string_val)));
} else {
rava_stack_push(stack, rava_value_boolean(false));
}
break;
}
case RAVA_OP_HASHMAP_CLEAR: {
RavaValue_t map_val = rava_stack_pop(stack);
if (map_val.type == RAVA_VAL_HASHMAP) {
rava_hashmap_clear(map_val.data.hashmap_val);
}
break;
}
case RAVA_OP_CAST: {
RavaValue_t val = rava_stack_pop(stack);
RavaType_t *target_type = instr->operand.var.type;
@ -3090,7 +3240,11 @@ static bool _rava_vm_execute_ultrafast(RavaVM_t *vm, RavaMethod_t *entry_method)
&&uf_math_abs, &&uf_math_sqrt, &&uf_math_pow, &&uf_math_min, &&uf_math_max,
&&uf_math_floor, &&uf_math_ceil, &&uf_math_round,
&&uf_math_sin, &&uf_math_cos, &&uf_math_tan, &&uf_math_log, &&uf_math_exp,
&&uf_math_random
&&uf_math_random,
&&uf_arraylist_new, &&uf_arraylist_add, &&uf_arraylist_get, &&uf_arraylist_set,
&&uf_arraylist_size, &&uf_arraylist_remove, &&uf_arraylist_clear, &&uf_arraylist_isempty,
&&uf_hashmap_new, &&uf_hashmap_put, &&uf_hashmap_get, &&uf_hashmap_remove,
&&uf_hashmap_size, &&uf_hashmap_containskey, &&uf_hashmap_clear
};
rava_fastframe_reset();
@ -4248,6 +4402,252 @@ uf_math_random: {
UF_DISPATCH();
}
uf_arraylist_new: {
RavaArrayList_t *list = rava_arraylist_create();
UF_PUSH(rava_nanbox_object(list));
UF_DISPATCH();
}
uf_arraylist_add: {
RavaNanboxValue_t val = UF_POP();
RavaNanboxValue_t list_nb = UF_POP();
RavaArrayList_t *list = (RavaArrayList_t*)rava_nanbox_as_object(list_nb);
if (list) {
RavaValue_t v;
if (rava_nanbox_is_int(val)) {
v = rava_value_int(rava_nanbox_to_int(val));
} else if (rava_nanbox_is_double(val)) {
v = rava_value_double(rava_nanbox_to_double(val));
} else {
v = rava_value_null();
}
rava_arraylist_add(list, v);
}
UF_DISPATCH();
}
uf_arraylist_get: {
RavaNanboxValue_t idx_nb = UF_POP();
RavaNanboxValue_t coll_nb = UF_POP();
void *ptr = rava_nanbox_as_object(coll_nb);
if (rava_nanbox_is_int(idx_nb)) {
RavaArrayList_t *list = (RavaArrayList_t*)ptr;
if (list) {
RavaValue_t v = rava_arraylist_get(list, (size_t)rava_nanbox_to_int(idx_nb));
if (v.type == RAVA_VAL_INT) {
UF_PUSH(rava_nanbox_int(v.data.int_val));
} else if (v.type == RAVA_VAL_DOUBLE) {
UF_PUSH(rava_nanbox_double(v.data.double_val));
} else {
UF_PUSH(rava_nanbox_null());
}
} else {
UF_PUSH(rava_nanbox_null());
}
} else if (rava_nanbox_is_string(idx_nb)) {
RavaHashMap_t *map = (RavaHashMap_t*)ptr;
if (map) {
RavaValue_t v = rava_hashmap_get(map, rava_nanbox_as_string(idx_nb));
if (v.type == RAVA_VAL_INT) {
UF_PUSH(rava_nanbox_int(v.data.int_val));
} else if (v.type == RAVA_VAL_DOUBLE) {
UF_PUSH(rava_nanbox_double(v.data.double_val));
} else {
UF_PUSH(rava_nanbox_null());
}
} else {
UF_PUSH(rava_nanbox_null());
}
} else {
UF_PUSH(rava_nanbox_null());
}
UF_DISPATCH();
}
uf_arraylist_set: {
RavaNanboxValue_t val = UF_POP();
RavaNanboxValue_t idx_nb = UF_POP();
RavaNanboxValue_t list_nb = UF_POP();
RavaArrayList_t *list = (RavaArrayList_t*)rava_nanbox_as_object(list_nb);
if (list) {
RavaValue_t v;
if (rava_nanbox_is_int(val)) {
v = rava_value_int(rava_nanbox_to_int(val));
} else if (rava_nanbox_is_double(val)) {
v = rava_value_double(rava_nanbox_to_double(val));
} else {
v = rava_value_null();
}
rava_arraylist_set(list, (size_t)rava_nanbox_to_int(idx_nb), v);
}
UF_DISPATCH();
}
uf_arraylist_size: {
RavaNanboxValue_t coll_nb = UF_POP();
void *ptr = rava_nanbox_as_object(coll_nb);
if (ptr) {
int type = *(int*)ptr;
if (type == RAVA_COLLECTION_ARRAYLIST) {
UF_PUSH(rava_nanbox_int((int32_t)rava_arraylist_size((RavaArrayList_t*)ptr)));
} else if (type == RAVA_COLLECTION_HASHMAP) {
UF_PUSH(rava_nanbox_int((int32_t)rava_hashmap_size((RavaHashMap_t*)ptr)));
} else {
UF_PUSH(rava_nanbox_int(0));
}
} else {
UF_PUSH(rava_nanbox_int(0));
}
UF_DISPATCH();
}
uf_arraylist_remove: {
RavaNanboxValue_t idx_or_key = UF_POP();
RavaNanboxValue_t coll_nb = UF_POP();
void *ptr = rava_nanbox_as_object(coll_nb);
if (ptr) {
int type = *(int*)ptr;
if (type == RAVA_COLLECTION_ARRAYLIST && rava_nanbox_is_int(idx_or_key)) {
RavaValue_t v = rava_arraylist_remove((RavaArrayList_t*)ptr, (size_t)rava_nanbox_to_int(idx_or_key));
if (v.type == RAVA_VAL_INT) {
UF_PUSH(rava_nanbox_int(v.data.int_val));
} else {
UF_PUSH(rava_nanbox_null());
}
} else if (type == RAVA_COLLECTION_HASHMAP && rava_nanbox_is_string(idx_or_key)) {
RavaValue_t v = rava_hashmap_remove((RavaHashMap_t*)ptr, rava_nanbox_as_string(idx_or_key));
if (v.type == RAVA_VAL_INT) {
UF_PUSH(rava_nanbox_int(v.data.int_val));
} else {
UF_PUSH(rava_nanbox_null());
}
} else {
UF_PUSH(rava_nanbox_null());
}
} else {
UF_PUSH(rava_nanbox_null());
}
UF_DISPATCH();
}
uf_arraylist_clear: {
RavaNanboxValue_t coll_nb = UF_POP();
void *ptr = rava_nanbox_as_object(coll_nb);
if (ptr) {
int type = *(int*)ptr;
if (type == RAVA_COLLECTION_ARRAYLIST) {
rava_arraylist_clear((RavaArrayList_t*)ptr);
} else if (type == RAVA_COLLECTION_HASHMAP) {
rava_hashmap_clear((RavaHashMap_t*)ptr);
}
}
UF_DISPATCH();
}
uf_arraylist_isempty: {
RavaNanboxValue_t list_nb = UF_POP();
RavaArrayList_t *list = (RavaArrayList_t*)rava_nanbox_as_object(list_nb);
if (list) {
UF_PUSH(rava_nanbox_int(rava_arraylist_isempty(list) ? 1 : 0));
} else {
UF_PUSH(rava_nanbox_int(1));
}
UF_DISPATCH();
}
uf_hashmap_new: {
RavaHashMap_t *map = rava_hashmap_create();
UF_PUSH(rava_nanbox_object(map));
UF_DISPATCH();
}
uf_hashmap_put: {
RavaNanboxValue_t val = UF_POP();
RavaNanboxValue_t key_nb = UF_POP();
RavaNanboxValue_t map_nb = UF_POP();
RavaHashMap_t *map = (RavaHashMap_t*)rava_nanbox_as_object(map_nb);
if (map && rava_nanbox_is_string(key_nb)) {
RavaValue_t v;
if (rava_nanbox_is_int(val)) {
v = rava_value_int(rava_nanbox_to_int(val));
} else if (rava_nanbox_is_double(val)) {
v = rava_value_double(rava_nanbox_to_double(val));
} else {
v = rava_value_null();
}
rava_hashmap_put(map, rava_nanbox_as_string(key_nb), v);
}
UF_DISPATCH();
}
uf_hashmap_get: {
RavaNanboxValue_t key_nb = UF_POP();
RavaNanboxValue_t map_nb = UF_POP();
RavaHashMap_t *map = (RavaHashMap_t*)rava_nanbox_as_object(map_nb);
if (map && rava_nanbox_is_string(key_nb)) {
RavaValue_t v = rava_hashmap_get(map, rava_nanbox_as_string(key_nb));
if (v.type == RAVA_VAL_INT) {
UF_PUSH(rava_nanbox_int(v.data.int_val));
} else if (v.type == RAVA_VAL_DOUBLE) {
UF_PUSH(rava_nanbox_double(v.data.double_val));
} else {
UF_PUSH(rava_nanbox_null());
}
} else {
UF_PUSH(rava_nanbox_null());
}
UF_DISPATCH();
}
uf_hashmap_remove: {
RavaNanboxValue_t key_nb = UF_POP();
RavaNanboxValue_t map_nb = UF_POP();
RavaHashMap_t *map = (RavaHashMap_t*)rava_nanbox_as_object(map_nb);
if (map && rava_nanbox_is_string(key_nb)) {
RavaValue_t v = rava_hashmap_remove(map, rava_nanbox_as_string(key_nb));
if (v.type == RAVA_VAL_INT) {
UF_PUSH(rava_nanbox_int(v.data.int_val));
} else {
UF_PUSH(rava_nanbox_null());
}
} else {
UF_PUSH(rava_nanbox_null());
}
UF_DISPATCH();
}
uf_hashmap_size: {
RavaNanboxValue_t map_nb = UF_POP();
RavaHashMap_t *map = (RavaHashMap_t*)rava_nanbox_as_object(map_nb);
if (map) {
UF_PUSH(rava_nanbox_int((int32_t)rava_hashmap_size(map)));
} else {
UF_PUSH(rava_nanbox_int(0));
}
UF_DISPATCH();
}
uf_hashmap_containskey: {
RavaNanboxValue_t key_nb = UF_POP();
RavaNanboxValue_t map_nb = UF_POP();
RavaHashMap_t *map = (RavaHashMap_t*)rava_nanbox_as_object(map_nb);
if (map && rava_nanbox_is_string(key_nb)) {
UF_PUSH(rava_nanbox_int(rava_hashmap_containskey(map, rava_nanbox_as_string(key_nb)) ? 1 : 0));
} else {
UF_PUSH(rava_nanbox_int(0));
}
UF_DISPATCH();
}
uf_hashmap_clear: {
RavaNanboxValue_t map_nb = UF_POP();
RavaHashMap_t *map = (RavaHashMap_t*)rava_nanbox_as_object(map_nb);
if (map) {
rava_hashmap_clear(map);
}
UF_DISPATCH();
}
uf_done:
rava_fastframe_reset();
return !vm->had_error;

View File

@ -17,7 +17,9 @@ typedef enum {
RAVA_VAL_NULL,
RAVA_VAL_OBJECT,
RAVA_VAL_ARRAY,
RAVA_VAL_STRING
RAVA_VAL_STRING,
RAVA_VAL_ARRAYLIST,
RAVA_VAL_HASHMAP
} RavaValueType_e;
typedef struct {
@ -28,6 +30,8 @@ typedef struct {
typedef struct RavaObject_t RavaObject_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
@ -52,9 +56,36 @@ struct RavaValue_t {
RavaObject_t *object_val;
RavaArray_t *array_val;
char *string_val;
RavaArrayList_t *arraylist_val;
RavaHashMap_t *hashmap_val;
} 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 {
RavaValue_t *values;
size_t capacity;
@ -197,6 +228,20 @@ static inline RavaValue_t rava_value_object(RavaObject_t *obj) {
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);
int32_t rava_value_as_int(RavaValue_t value);
@ -225,6 +270,25 @@ 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);
void rava_stack_destroy(RavaStack_t *stack);
void rava_stack_push(RavaStack_t *stack, RavaValue_t value);

View File

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

View File

@ -82,6 +82,41 @@ static bool _rava_semantic_analyze_class(RavaSemanticAnalyzer_t *analyzer, RavaA
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) {
if (method_node->type != RAVA_AST_METHOD_DECL) return false;
@ -330,6 +365,12 @@ static RavaType_t* _rava_semantic_check_expression(RavaSemanticAnalyzer_t *analy
return rava_type_create_primitive(RAVA_TYPE_BOOLEAN);
} else if (strcmp(method, "compareTo") == 0) {
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);
@ -458,6 +499,9 @@ static bool _rava_semantic_analyze_node(RavaSemanticAnalyzer_t *analyzer, RavaAS
case RAVA_AST_CLASS_DECL:
return _rava_semantic_analyze_class(analyzer, node);
case RAVA_AST_ENUM_DECL:
return _rava_semantic_analyze_enum(analyzer, node);
case RAVA_AST_METHOD_DECL:
return _rava_semantic_analyze_method(analyzer, node);

View File

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