feat: implement support for multi-dimensional array initialization and access

This commit is contained in:
2025-12-03 13:08:55 +00:00
parent 6dfbe4a4d0
commit 43103e7120
7 changed files with 301 additions and 21 deletions
+1
View File
@@ -140,6 +140,7 @@ static const char* _rava_opcode_name(RavaOpCode_e opcode) {
case RAVA_OP_RETURN_VOID: return "RETURN_VOID";
case RAVA_OP_NEW: return "NEW";
case RAVA_OP_NEW_ARRAY: return "NEW_ARRAY";
case RAVA_OP_NEW_ARRAY_OF_ARRAYS: return "NEW_ARRAY_OF_ARRAYS";
case RAVA_OP_ARRAY_LENGTH: return "ARRAY_LENGTH";
case RAVA_OP_LOAD_ARRAY: return "LOAD_ARRAY";
case RAVA_OP_STORE_ARRAY: return "STORE_ARRAY";
+1
View File
@@ -61,6 +61,7 @@ typedef enum {
RAVA_OP_NEW,
RAVA_OP_NEW_ARRAY,
RAVA_OP_NEW_ARRAY_OF_ARRAYS,
RAVA_OP_ARRAY_LENGTH,
RAVA_OP_GET_FIELD,
RAVA_OP_PUT_FIELD,
+164 -7
View File
@@ -7,6 +7,13 @@
static void _rava_ir_gen_expression(RavaIRGenerator_t *gen, RavaASTNode_t *expr);
static void _rava_ir_gen_statement(RavaIRGenerator_t *gen, RavaASTNode_t *stmt);
static bool _rava_has_modifier(RavaModifier_e *mods, size_t count, RavaModifier_e mod) {
for (size_t i = 0; i < count; i++) {
if (mods[i] == mod) return true;
}
return false;
}
static void _rava_ir_clear_locals(RavaIRGenerator_t *gen) {
RavaLocalVar_t *current = gen->locals;
while (current) {
@@ -286,8 +293,12 @@ static void _rava_ir_gen_expression(RavaIRGenerator_t *gen, RavaASTNode_t *expr)
}
}
_rava_ir_gen_expression(gen, expr->data.member_access.object);
instr.opcode = RAVA_OP_GET_FIELD;
instr.operand.field.field_name = strdup(expr->data.member_access.member);
if (strcmp(expr->data.member_access.member, "length") == 0) {
instr.opcode = RAVA_OP_ARRAY_LENGTH;
} else {
instr.opcode = RAVA_OP_GET_FIELD;
instr.operand.field.field_name = strdup(expr->data.member_access.member);
}
_rava_ir_emit(gen, instr);
break;
@@ -300,11 +311,94 @@ static void _rava_ir_gen_expression(RavaIRGenerator_t *gen, RavaASTNode_t *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.arguments_count > 0) {
if (expr->data.new_expr.arguments_count == 1) {
_rava_ir_gen_expression(gen, expr->data.new_expr.arguments[0]);
instr.opcode = RAVA_OP_NEW_ARRAY;
_rava_ir_emit(gen, instr);
} else if (expr->data.new_expr.arguments_count >= 2) {
int saved_next_local = gen->next_local;
_rava_ir_gen_expression(gen, expr->data.new_expr.arguments[0]);
instr.opcode = RAVA_OP_NEW_ARRAY_OF_ARRAYS;
_rava_ir_emit(gen, instr);
int outer_var = gen->next_local++;
instr.opcode = RAVA_OP_STORE_LOCAL;
instr.operand.var.index = outer_var;
_rava_ir_emit(gen, instr);
int loop_var = gen->next_local++;
instr.opcode = RAVA_OP_LOAD_CONST;
instr.operand.int_value = 0;
_rava_ir_emit(gen, instr);
instr.opcode = RAVA_OP_STORE_LOCAL;
instr.operand.var.index = loop_var;
_rava_ir_emit(gen, instr);
int loop_start = rava_instruction_list_new_label(gen->current_method->instructions);
int loop_end = rava_instruction_list_new_label(gen->current_method->instructions);
instr.opcode = RAVA_OP_LABEL;
instr.operand.label_id = loop_start;
_rava_ir_emit(gen, instr);
instr.opcode = RAVA_OP_LOAD_LOCAL;
instr.operand.var.index = loop_var;
_rava_ir_emit(gen, instr);
_rava_ir_gen_expression(gen, expr->data.new_expr.arguments[0]);
instr.opcode = RAVA_OP_LT;
_rava_ir_emit(gen, instr);
instr.opcode = RAVA_OP_JUMP_IF_FALSE;
instr.operand.label_id = loop_end;
_rava_ir_emit(gen, instr);
instr.opcode = RAVA_OP_LOAD_LOCAL;
instr.operand.var.index = outer_var;
_rava_ir_emit(gen, instr);
instr.opcode = RAVA_OP_LOAD_LOCAL;
instr.operand.var.index = loop_var;
_rava_ir_emit(gen, instr);
_rava_ir_gen_expression(gen, expr->data.new_expr.arguments[1]);
instr.opcode = RAVA_OP_NEW_ARRAY;
_rava_ir_emit(gen, instr);
instr.opcode = RAVA_OP_STORE_ARRAY;
_rava_ir_emit(gen, instr);
instr.opcode = RAVA_OP_LOAD_LOCAL;
instr.operand.var.index = loop_var;
_rava_ir_emit(gen, instr);
instr.opcode = RAVA_OP_LOAD_CONST;
instr.operand.int_value = 1;
_rava_ir_emit(gen, instr);
instr.opcode = RAVA_OP_ADD;
_rava_ir_emit(gen, instr);
instr.opcode = RAVA_OP_STORE_LOCAL;
instr.operand.var.index = loop_var;
_rava_ir_emit(gen, instr);
instr.opcode = RAVA_OP_JUMP;
instr.operand.label_id = loop_start;
_rava_ir_emit(gen, instr);
instr.opcode = RAVA_OP_LABEL;
instr.operand.label_id = loop_end;
_rava_ir_emit(gen, instr);
instr.opcode = RAVA_OP_LOAD_LOCAL;
instr.operand.var.index = outer_var;
_rava_ir_emit(gen, instr);
if (gen->next_local > gen->current_method->local_count) {
gen->current_method->local_count = gen->next_local;
}
gen->next_local = saved_next_local;
} else {
instr.opcode = RAVA_OP_LOAD_CONST;
instr.operand.int_value = 0;
_rava_ir_emit(gen, instr);
instr.opcode = RAVA_OP_NEW_ARRAY;
_rava_ir_emit(gen, instr);
}
instr.opcode = RAVA_OP_NEW_ARRAY;
_rava_ir_emit(gen, instr);
} else if (expr->data.new_expr.type) {
instr.opcode = RAVA_OP_NEW;
instr.operand.call.class_name = strdup(expr->data.new_expr.type->data.type.type_name);
@@ -612,6 +706,17 @@ static void _rava_ir_gen_expression(RavaIRGenerator_t *gen, RavaASTNode_t *expr)
instr.opcode = RAVA_OP_PRINT;
}
_rava_ir_emit(gen, instr);
} else if (expr->data.call.callee->type == RAVA_AST_SUPER_EXPR) {
instr.opcode = RAVA_OP_LOAD_THIS;
_rava_ir_emit(gen, instr);
for (size_t i = 0; i < expr->data.call.arguments_count; i++) {
_rava_ir_gen_expression(gen, expr->data.call.arguments[i]);
}
instr.opcode = RAVA_OP_CALL_SUPER;
instr.operand.call.class_name = gen->current_class->superclass ? strdup(gen->current_class->superclass) : NULL;
instr.operand.call.method_name = strdup("<init>");
instr.operand.call.arg_count = expr->data.call.arguments_count;
_rava_ir_emit(gen, instr);
} else if (expr->data.call.callee->type == RAVA_AST_MEMBER_ACCESS_EXPR) {
RavaASTNode_t *member = expr->data.call.callee;
if (member->data.member_access.object->type == RAVA_AST_SUPER_EXPR) {
@@ -1178,7 +1283,15 @@ static void _rava_ir_gen_method(RavaIRGenerator_t *gen, RavaASTNode_t *method_no
rava_symbol_table_exit_scope(gen->analyzer->symbol_table);
method->local_count = gen->next_local;
if (return_type && strcmp(return_type->name, "void") == 0) {
RavaInstruction_t ret_instr = {0};
ret_instr.opcode = RAVA_OP_RETURN_VOID;
_rava_ir_emit(gen, ret_instr);
}
if (gen->next_local > method->local_count) {
method->local_count = gen->next_local;
}
rava_class_add_method(gen->current_class, method);
gen->current_method = NULL;
}
@@ -1206,7 +1319,9 @@ static void _rava_ir_gen_constructor(RavaIRGenerator_t *gen, RavaASTNode_t *ctor
ret_instr.opcode = RAVA_OP_RETURN_VOID;
_rava_ir_emit(gen, ret_instr);
method->local_count = gen->next_local;
if (gen->next_local > method->local_count) {
method->local_count = gen->next_local;
}
rava_class_add_method(gen->current_class, method);
gen->current_method = NULL;
}
@@ -1222,6 +1337,48 @@ static void _rava_ir_gen_class(RavaIRGenerator_t *gen, RavaASTNode_t *class_node
rava_symbol_table_enter_scope(gen->analyzer->symbol_table, class_node->data.class_decl.name);
bool has_static_init = false;
for (size_t i = 0; i < class_node->children_count; i++) {
RavaASTNode_t *child = class_node->children[i];
if (child->type == RAVA_AST_FIELD_DECL &&
child->data.field_decl.initializer &&
_rava_has_modifier(child->data.field_decl.modifiers,
child->data.field_decl.modifiers_count,
RAVA_MODIFIER_STATIC)) {
has_static_init = true;
break;
}
}
if (has_static_init) {
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 < class_node->children_count; i++) {
RavaASTNode_t *child = class_node->children[i];
if (child->type == RAVA_AST_FIELD_DECL &&
child->data.field_decl.initializer &&
_rava_has_modifier(child->data.field_decl.modifiers,
child->data.field_decl.modifiers_count,
RAVA_MODIFIER_STATIC)) {
_rava_ir_gen_expression(gen, child->data.field_decl.initializer);
instr.opcode = RAVA_OP_STORE_STATIC;
instr.operand.field.class_name = strdup(class_node->data.class_decl.name);
instr.operand.field.field_name = strdup(child->data.field_decl.name);
_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 < class_node->children_count; i++) {
RavaASTNode_t *child = class_node->children[i];