feat: implement support for multi-dimensional array initialization and access
This commit is contained in:
@@ -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";
|
||||
|
||||
@@ -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
@@ -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];
|
||||
|
||||
|
||||
Reference in New Issue
Block a user