chore: remove trailing whitespace from README.md formatting

This commit is contained in:
2025-12-02 20:12:50 +00:00
parent 0216064cf1
commit c09a0a41be
11 changed files with 2435 additions and 71 deletions
+32 -1
View File
@@ -53,6 +53,7 @@ typedef enum {
RAVA_OP_CALL,
RAVA_OP_CALL_STATIC,
RAVA_OP_CALL_VIRTUAL,
RAVA_OP_CALL_SUPER,
RAVA_OP_CALL_NATIVE,
RAVA_OP_RETURN,
RAVA_OP_RETURN_VOID,
@@ -67,6 +68,8 @@ typedef enum {
RAVA_OP_INSTANCEOF,
RAVA_OP_THROW,
RAVA_OP_TRY_BEGIN,
RAVA_OP_TRY_END,
RAVA_OP_POP,
RAVA_OP_DUP,
@@ -78,6 +81,13 @@ typedef enum {
RAVA_OP_STRING_SUBSTRING,
RAVA_OP_STRING_EQUALS,
RAVA_OP_STRING_COMPARETO,
RAVA_OP_STRING_INDEXOF,
RAVA_OP_STRING_CONTAINS,
RAVA_OP_STRING_STARTSWITH,
RAVA_OP_STRING_ENDSWITH,
RAVA_OP_STRING_TOLOWERCASE,
RAVA_OP_STRING_TOUPPERCASE,
RAVA_OP_STRING_TRIM,
RAVA_OP_LOAD_THIS,
@@ -96,7 +106,22 @@ typedef enum {
RAVA_OP_LOAD_LOCAL_CONST_LE_JUMPFALSE,
RAVA_OP_LOAD_TWO_LOCALS,
RAVA_OP_ADD_LOCAL_TO_LOCAL,
RAVA_OP_LOAD_LOCAL_LT_LOCAL_JUMPFALSE
RAVA_OP_LOAD_LOCAL_LT_LOCAL_JUMPFALSE,
RAVA_OP_MATH_ABS,
RAVA_OP_MATH_SQRT,
RAVA_OP_MATH_POW,
RAVA_OP_MATH_MIN,
RAVA_OP_MATH_MAX,
RAVA_OP_MATH_FLOOR,
RAVA_OP_MATH_CEIL,
RAVA_OP_MATH_ROUND,
RAVA_OP_MATH_SIN,
RAVA_OP_MATH_COS,
RAVA_OP_MATH_TAN,
RAVA_OP_MATH_LOG,
RAVA_OP_MATH_EXP,
RAVA_OP_MATH_RANDOM
} RavaOpCode_e;
typedef union {
@@ -135,6 +160,12 @@ typedef union {
int local2;
int label_id;
} cmp_locals;
struct {
int catch_label;
int finally_label;
int end_label;
int exception_local;
} try_handler;
} RavaOperand_u;
typedef struct {
+557 -8
View File
@@ -35,6 +35,15 @@ static int _rava_ir_find_local(RavaIRGenerator_t *gen, const char *name) {
return -1;
}
static bool _rava_ir_is_class_name(RavaIRGenerator_t *gen, const char *name) {
for (size_t i = 0; i < gen->program->class_count; i++) {
if (strcmp(gen->program->classes[i]->name, name) == 0) {
return true;
}
}
return false;
}
RavaIRGenerator_t* rava_ir_generator_create(RavaSemanticAnalyzer_t *analyzer) {
RavaIRGenerator_t *gen = calloc(1, sizeof(RavaIRGenerator_t));
gen->program = rava_program_create();
@@ -82,6 +91,12 @@ static void _rava_ir_gen_binary_expr(RavaIRGenerator_t *gen, RavaASTNode_t *expr
case RAVA_BINOP_GE: instr.opcode = RAVA_OP_GE; break;
case RAVA_BINOP_AND: instr.opcode = RAVA_OP_AND; break;
case RAVA_BINOP_OR: instr.opcode = RAVA_OP_OR; break;
case RAVA_BINOP_BITAND: instr.opcode = RAVA_OP_AND; break;
case RAVA_BINOP_BITOR: instr.opcode = RAVA_OP_OR; break;
case RAVA_BINOP_BITXOR: instr.opcode = RAVA_OP_XOR; break;
case RAVA_BINOP_LSHIFT: instr.opcode = RAVA_OP_SHL; break;
case RAVA_BINOP_RSHIFT: instr.opcode = RAVA_OP_SHR; break;
case RAVA_BINOP_URSHIFT: instr.opcode = RAVA_OP_USHR; break;
default: instr.opcode = RAVA_OP_NOP; break;
}
@@ -190,6 +205,19 @@ static void _rava_ir_gen_expression(RavaIRGenerator_t *gen, RavaASTNode_t *expr)
instr.opcode = RAVA_OP_STORE_ARRAY;
_rava_ir_emit(gen, instr);
} else if (expr->data.assign.target->type == RAVA_AST_MEMBER_ACCESS_EXPR) {
RavaASTNode_t *target_member = expr->data.assign.target;
if (target_member->data.member_access.object->type == RAVA_AST_IDENTIFIER_EXPR) {
const char *obj_name = target_member->data.member_access.object->data.identifier.name;
if (_rava_ir_is_class_name(gen, obj_name) ||
strcmp(obj_name, gen->current_class->name) == 0) {
_rava_ir_gen_expression(gen, expr->data.assign.value);
instr.opcode = RAVA_OP_STORE_STATIC;
instr.operand.field.class_name = strdup(obj_name);
instr.operand.field.field_name = strdup(target_member->data.member_access.member);
_rava_ir_emit(gen, instr);
break;
}
}
_rava_ir_gen_expression(gen, expr->data.assign.target->data.member_access.object);
_rava_ir_gen_expression(gen, expr->data.assign.value);
instr.opcode = RAVA_OP_PUT_FIELD;
@@ -210,6 +238,17 @@ static void _rava_ir_gen_expression(RavaIRGenerator_t *gen, RavaASTNode_t *expr)
break;
case RAVA_AST_MEMBER_ACCESS_EXPR:
if (expr->data.member_access.object->type == RAVA_AST_IDENTIFIER_EXPR) {
const char *obj_name = expr->data.member_access.object->data.identifier.name;
if (_rava_ir_is_class_name(gen, obj_name) ||
strcmp(obj_name, gen->current_class->name) == 0) {
instr.opcode = RAVA_OP_LOAD_STATIC;
instr.operand.field.class_name = strdup(obj_name);
instr.operand.field.field_name = strdup(expr->data.member_access.member);
_rava_ir_emit(gen, instr);
break;
}
}
_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);
@@ -251,13 +290,36 @@ static void _rava_ir_gen_expression(RavaIRGenerator_t *gen, RavaASTNode_t *expr)
bool is_print = false;
bool is_string_length = false;
bool is_string_charat = false;
bool is_string_substring = false;
bool is_string_equals = false;
bool is_string_compareto = false;
bool is_string_indexof = false;
bool is_string_contains = false;
bool is_string_startswith = false;
bool is_string_endswith = false;
bool is_string_tolowercase = false;
bool is_string_touppercase = false;
bool is_string_trim = false;
bool is_file_read = false;
bool is_file_write = false;
bool is_file_exists = false;
bool is_file_delete = false;
bool is_current_time_millis = false;
bool is_nano_time = false;
bool is_math_abs = false;
bool is_math_sqrt = false;
bool is_math_pow = false;
bool is_math_min = false;
bool is_math_max = false;
bool is_math_floor = false;
bool is_math_ceil = false;
bool is_math_round = false;
bool is_math_sin = false;
bool is_math_cos = false;
bool is_math_tan = false;
bool is_math_log = false;
bool is_math_exp = false;
bool is_math_random = false;
RavaASTNode_t *string_object = NULL;
if (expr->data.call.callee->type == RAVA_AST_MEMBER_ACCESS_EXPR) {
@@ -294,6 +356,39 @@ static void _rava_ir_gen_expression(RavaIRGenerator_t *gen, RavaASTNode_t *expr)
is_file_delete = true;
}
}
if (member->data.member_access.object->type == RAVA_AST_IDENTIFIER_EXPR &&
strcmp(member->data.member_access.object->data.identifier.name, "Math") == 0) {
const char *method = member->data.member_access.member;
if (strcmp(method, "abs") == 0 && expr->data.call.arguments_count == 1) {
is_math_abs = true;
} else if (strcmp(method, "sqrt") == 0 && expr->data.call.arguments_count == 1) {
is_math_sqrt = true;
} else if (strcmp(method, "pow") == 0 && expr->data.call.arguments_count == 2) {
is_math_pow = true;
} else if (strcmp(method, "min") == 0 && expr->data.call.arguments_count == 2) {
is_math_min = true;
} else if (strcmp(method, "max") == 0 && expr->data.call.arguments_count == 2) {
is_math_max = true;
} else if (strcmp(method, "floor") == 0 && expr->data.call.arguments_count == 1) {
is_math_floor = true;
} else if (strcmp(method, "ceil") == 0 && expr->data.call.arguments_count == 1) {
is_math_ceil = true;
} else if (strcmp(method, "round") == 0 && expr->data.call.arguments_count == 1) {
is_math_round = true;
} else if (strcmp(method, "sin") == 0 && expr->data.call.arguments_count == 1) {
is_math_sin = true;
} else if (strcmp(method, "cos") == 0 && expr->data.call.arguments_count == 1) {
is_math_cos = true;
} else if (strcmp(method, "tan") == 0 && expr->data.call.arguments_count == 1) {
is_math_tan = true;
} else if (strcmp(method, "log") == 0 && expr->data.call.arguments_count == 1) {
is_math_log = true;
} else if (strcmp(method, "exp") == 0 && expr->data.call.arguments_count == 1) {
is_math_exp = true;
} else if (strcmp(method, "random") == 0 && expr->data.call.arguments_count == 0) {
is_math_random = true;
}
}
if (strcmp(member->data.member_access.member, "length") == 0 && expr->data.call.arguments_count == 0) {
is_string_length = true;
string_object = member->data.member_access.object;
@@ -303,6 +398,33 @@ static void _rava_ir_gen_expression(RavaIRGenerator_t *gen, RavaASTNode_t *expr)
} else if (strcmp(member->data.member_access.member, "equals") == 0 && expr->data.call.arguments_count == 1) {
is_string_equals = true;
string_object = member->data.member_access.object;
} else if (strcmp(member->data.member_access.member, "substring") == 0 && expr->data.call.arguments_count == 2) {
is_string_substring = true;
string_object = member->data.member_access.object;
} else if (strcmp(member->data.member_access.member, "compareTo") == 0 && expr->data.call.arguments_count == 1) {
is_string_compareto = true;
string_object = member->data.member_access.object;
} else if (strcmp(member->data.member_access.member, "indexOf") == 0 && expr->data.call.arguments_count == 1) {
is_string_indexof = true;
string_object = member->data.member_access.object;
} else if (strcmp(member->data.member_access.member, "contains") == 0 && expr->data.call.arguments_count == 1) {
is_string_contains = true;
string_object = member->data.member_access.object;
} else if (strcmp(member->data.member_access.member, "startsWith") == 0 && expr->data.call.arguments_count == 1) {
is_string_startswith = true;
string_object = member->data.member_access.object;
} else if (strcmp(member->data.member_access.member, "endsWith") == 0 && expr->data.call.arguments_count == 1) {
is_string_endswith = true;
string_object = member->data.member_access.object;
} else if (strcmp(member->data.member_access.member, "toLowerCase") == 0 && expr->data.call.arguments_count == 0) {
is_string_tolowercase = true;
string_object = member->data.member_access.object;
} else if (strcmp(member->data.member_access.member, "toUpperCase") == 0 && expr->data.call.arguments_count == 0) {
is_string_touppercase = true;
string_object = member->data.member_access.object;
} 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;
}
}
@@ -343,6 +465,107 @@ static void _rava_ir_gen_expression(RavaIRGenerator_t *gen, RavaASTNode_t *expr)
_rava_ir_gen_expression(gen, expr->data.call.arguments[0]);
instr.opcode = RAVA_OP_STRING_EQUALS;
_rava_ir_emit(gen, instr);
} else if (is_string_substring) {
_rava_ir_gen_expression(gen, string_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_STRING_SUBSTRING;
_rava_ir_emit(gen, instr);
} else if (is_string_compareto) {
_rava_ir_gen_expression(gen, string_object);
_rava_ir_gen_expression(gen, expr->data.call.arguments[0]);
instr.opcode = RAVA_OP_STRING_COMPARETO;
_rava_ir_emit(gen, instr);
} else if (is_string_indexof) {
_rava_ir_gen_expression(gen, string_object);
_rava_ir_gen_expression(gen, expr->data.call.arguments[0]);
instr.opcode = RAVA_OP_STRING_INDEXOF;
_rava_ir_emit(gen, instr);
} else if (is_string_contains) {
_rava_ir_gen_expression(gen, string_object);
_rava_ir_gen_expression(gen, expr->data.call.arguments[0]);
instr.opcode = RAVA_OP_STRING_CONTAINS;
_rava_ir_emit(gen, instr);
} else if (is_string_startswith) {
_rava_ir_gen_expression(gen, string_object);
_rava_ir_gen_expression(gen, expr->data.call.arguments[0]);
instr.opcode = RAVA_OP_STRING_STARTSWITH;
_rava_ir_emit(gen, instr);
} else if (is_string_endswith) {
_rava_ir_gen_expression(gen, string_object);
_rava_ir_gen_expression(gen, expr->data.call.arguments[0]);
instr.opcode = RAVA_OP_STRING_ENDSWITH;
_rava_ir_emit(gen, instr);
} else if (is_string_tolowercase) {
_rava_ir_gen_expression(gen, string_object);
instr.opcode = RAVA_OP_STRING_TOLOWERCASE;
_rava_ir_emit(gen, instr);
} else if (is_string_touppercase) {
_rava_ir_gen_expression(gen, string_object);
instr.opcode = RAVA_OP_STRING_TOUPPERCASE;
_rava_ir_emit(gen, instr);
} else if (is_string_trim) {
_rava_ir_gen_expression(gen, string_object);
instr.opcode = RAVA_OP_STRING_TRIM;
_rava_ir_emit(gen, instr);
} else if (is_math_abs) {
_rava_ir_gen_expression(gen, expr->data.call.arguments[0]);
instr.opcode = RAVA_OP_MATH_ABS;
_rava_ir_emit(gen, instr);
} else if (is_math_sqrt) {
_rava_ir_gen_expression(gen, expr->data.call.arguments[0]);
instr.opcode = RAVA_OP_MATH_SQRT;
_rava_ir_emit(gen, instr);
} else if (is_math_pow) {
_rava_ir_gen_expression(gen, expr->data.call.arguments[0]);
_rava_ir_gen_expression(gen, expr->data.call.arguments[1]);
instr.opcode = RAVA_OP_MATH_POW;
_rava_ir_emit(gen, instr);
} else if (is_math_min) {
_rava_ir_gen_expression(gen, expr->data.call.arguments[0]);
_rava_ir_gen_expression(gen, expr->data.call.arguments[1]);
instr.opcode = RAVA_OP_MATH_MIN;
_rava_ir_emit(gen, instr);
} else if (is_math_max) {
_rava_ir_gen_expression(gen, expr->data.call.arguments[0]);
_rava_ir_gen_expression(gen, expr->data.call.arguments[1]);
instr.opcode = RAVA_OP_MATH_MAX;
_rava_ir_emit(gen, instr);
} else if (is_math_floor) {
_rava_ir_gen_expression(gen, expr->data.call.arguments[0]);
instr.opcode = RAVA_OP_MATH_FLOOR;
_rava_ir_emit(gen, instr);
} else if (is_math_ceil) {
_rava_ir_gen_expression(gen, expr->data.call.arguments[0]);
instr.opcode = RAVA_OP_MATH_CEIL;
_rava_ir_emit(gen, instr);
} else if (is_math_round) {
_rava_ir_gen_expression(gen, expr->data.call.arguments[0]);
instr.opcode = RAVA_OP_MATH_ROUND;
_rava_ir_emit(gen, instr);
} else if (is_math_sin) {
_rava_ir_gen_expression(gen, expr->data.call.arguments[0]);
instr.opcode = RAVA_OP_MATH_SIN;
_rava_ir_emit(gen, instr);
} else if (is_math_cos) {
_rava_ir_gen_expression(gen, expr->data.call.arguments[0]);
instr.opcode = RAVA_OP_MATH_COS;
_rava_ir_emit(gen, instr);
} else if (is_math_tan) {
_rava_ir_gen_expression(gen, expr->data.call.arguments[0]);
instr.opcode = RAVA_OP_MATH_TAN;
_rava_ir_emit(gen, instr);
} else if (is_math_log) {
_rava_ir_gen_expression(gen, expr->data.call.arguments[0]);
instr.opcode = RAVA_OP_MATH_LOG;
_rava_ir_emit(gen, instr);
} else if (is_math_exp) {
_rava_ir_gen_expression(gen, expr->data.call.arguments[0]);
instr.opcode = RAVA_OP_MATH_EXP;
_rava_ir_emit(gen, instr);
} else if (is_math_random) {
instr.opcode = RAVA_OP_MATH_RANDOM;
_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]);
@@ -355,15 +578,28 @@ static void _rava_ir_gen_expression(RavaIRGenerator_t *gen, RavaASTNode_t *expr)
_rava_ir_emit(gen, instr);
} else if (expr->data.call.callee->type == RAVA_AST_MEMBER_ACCESS_EXPR) {
RavaASTNode_t *member = expr->data.call.callee;
_rava_ir_gen_expression(gen, member->data.member_access.object);
for (size_t i = 0; i < expr->data.call.arguments_count; i++) {
_rava_ir_gen_expression(gen, expr->data.call.arguments[i]);
if (member->data.member_access.object->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(member->data.member_access.member);
instr.operand.call.arg_count = expr->data.call.arguments_count;
_rava_ir_emit(gen, instr);
} else {
_rava_ir_gen_expression(gen, member->data.member_access.object);
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_VIRTUAL;
instr.operand.call.class_name = strdup(gen->current_class->name);
instr.operand.call.method_name = strdup(member->data.member_access.member);
instr.operand.call.arg_count = expr->data.call.arguments_count;
_rava_ir_emit(gen, instr);
}
instr.opcode = RAVA_OP_CALL_VIRTUAL;
instr.operand.call.class_name = strdup(gen->current_class->name);
instr.operand.call.method_name = strdup(member->data.member_access.member);
instr.operand.call.arg_count = expr->data.call.arguments_count;
_rava_ir_emit(gen, instr);
} else {
for (size_t i = 0; i < expr->data.call.arguments_count; i++) {
_rava_ir_gen_expression(gen, expr->data.call.arguments[i]);
@@ -384,6 +620,74 @@ static void _rava_ir_gen_expression(RavaIRGenerator_t *gen, RavaASTNode_t *expr)
_rava_ir_emit(gen, instr);
break;
case RAVA_AST_CAST_EXPR:
_rava_ir_gen_expression(gen, expr->data.cast.expression);
instr.opcode = RAVA_OP_CAST;
if (expr->data.cast.type && expr->data.cast.type->data.type.type_name) {
instr.operand.var.type = rava_type_from_name(expr->data.cast.type->data.type.type_name);
}
_rava_ir_emit(gen, instr);
break;
case RAVA_AST_TERNARY_EXPR: {
_rava_ir_gen_expression(gen, expr->data.ternary.condition);
int else_label = rava_instruction_list_new_label(gen->current_method->instructions);
int end_label = rava_instruction_list_new_label(gen->current_method->instructions);
instr.opcode = RAVA_OP_JUMP_IF_FALSE;
instr.operand.label_id = else_label;
_rava_ir_emit(gen, instr);
_rava_ir_gen_expression(gen, expr->data.ternary.true_expr);
instr.opcode = RAVA_OP_JUMP;
instr.operand.label_id = end_label;
_rava_ir_emit(gen, instr);
instr.opcode = RAVA_OP_LABEL;
instr.operand.label_id = else_label;
_rava_ir_emit(gen, instr);
_rava_ir_gen_expression(gen, expr->data.ternary.false_expr);
instr.opcode = RAVA_OP_LABEL;
instr.operand.label_id = end_label;
_rava_ir_emit(gen, instr);
break;
}
case RAVA_AST_ARRAY_INIT_EXPR: {
instr.opcode = RAVA_OP_LOAD_CONST;
instr.operand.int_value = (int)expr->data.array_init.elements_count;
_rava_ir_emit(gen, instr);
instr.opcode = RAVA_OP_NEW_ARRAY;
_rava_ir_emit(gen, instr);
for (size_t i = 0; i < expr->data.array_init.elements_count; i++) {
instr.opcode = RAVA_OP_DUP;
_rava_ir_emit(gen, instr);
instr.opcode = RAVA_OP_LOAD_CONST;
instr.operand.int_value = (int)i;
_rava_ir_emit(gen, instr);
_rava_ir_gen_expression(gen, expr->data.array_init.elements[i]);
instr.opcode = RAVA_OP_STORE_ARRAY;
_rava_ir_emit(gen, instr);
}
break;
}
case RAVA_AST_INSTANCEOF_EXPR:
_rava_ir_gen_expression(gen, expr->data.instanceof_expr.expression);
instr.opcode = RAVA_OP_INSTANCEOF;
instr.operand.string_value = strdup(expr->data.instanceof_expr.type_name);
_rava_ir_emit(gen, instr);
break;
default:
break;
}
@@ -463,6 +767,33 @@ static void _rava_ir_gen_statement(RavaIRGenerator_t *gen, RavaASTNode_t *stmt)
break;
}
case RAVA_AST_DO_WHILE_STMT: {
int start_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 };
gen->loop_context = &loop_ctx;
instr.opcode = RAVA_OP_LABEL;
instr.operand.label_id = start_label;
_rava_ir_emit(gen, instr);
_rava_ir_gen_statement(gen, stmt->data.while_stmt.body);
_rava_ir_gen_expression(gen, stmt->data.while_stmt.condition);
instr.opcode = RAVA_OP_JUMP_IF_TRUE;
instr.operand.label_id = start_label;
_rava_ir_emit(gen, instr);
instr.opcode = RAVA_OP_LABEL;
instr.operand.label_id = end_label;
_rava_ir_emit(gen, instr);
gen->loop_context = loop_ctx.parent;
break;
}
case RAVA_AST_FOR_STMT: {
if (stmt->data.for_stmt.init) {
if (stmt->data.for_stmt.init->type == RAVA_AST_VAR_DECL) {
@@ -516,6 +847,93 @@ static void _rava_ir_gen_statement(RavaIRGenerator_t *gen, RavaASTNode_t *stmt)
break;
}
case RAVA_AST_ENHANCED_FOR_STMT: {
size_t idx_local = gen->next_local++;
size_t elem_local = gen->next_local++;
gen->current_method->local_count = gen->next_local;
_rava_ir_add_local(gen, stmt->data.enhanced_for.var_name, elem_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 = idx_local;
_rava_ir_emit(gen, instr);
int start_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);
RavaLoopContext_t loop_ctx = { .break_label = end_label, .continue_label = continue_label, .parent = gen->loop_context };
gen->loop_context = &loop_ctx;
instr.opcode = RAVA_OP_LABEL;
instr.operand.label_id = start_label;
_rava_ir_emit(gen, instr);
instr.opcode = RAVA_OP_LOAD_LOCAL;
instr.operand.var.index = idx_local;
_rava_ir_emit(gen, instr);
_rava_ir_gen_expression(gen, stmt->data.enhanced_for.iterable);
instr.opcode = RAVA_OP_ARRAY_LENGTH;
_rava_ir_emit(gen, instr);
instr.opcode = RAVA_OP_LT;
_rava_ir_emit(gen, instr);
instr.opcode = RAVA_OP_JUMP_IF_FALSE;
instr.operand.label_id = end_label;
_rava_ir_emit(gen, instr);
_rava_ir_gen_expression(gen, stmt->data.enhanced_for.iterable);
instr.opcode = RAVA_OP_LOAD_LOCAL;
instr.operand.var.index = idx_local;
_rava_ir_emit(gen, instr);
instr.opcode = RAVA_OP_LOAD_ARRAY;
_rava_ir_emit(gen, instr);
instr.opcode = RAVA_OP_STORE_LOCAL;
instr.operand.var.index = elem_local;
_rava_ir_emit(gen, instr);
_rava_ir_gen_statement(gen, stmt->data.enhanced_for.body);
instr.opcode = RAVA_OP_LABEL;
instr.operand.label_id = continue_label;
_rava_ir_emit(gen, instr);
instr.opcode = RAVA_OP_LOAD_LOCAL;
instr.operand.var.index = idx_local;
_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 = idx_local;
_rava_ir_emit(gen, instr);
instr.opcode = RAVA_OP_JUMP;
instr.operand.label_id = start_label;
_rava_ir_emit(gen, instr);
instr.opcode = RAVA_OP_LABEL;
instr.operand.label_id = end_label;
_rava_ir_emit(gen, instr);
gen->loop_context = loop_ctx.parent;
break;
}
case RAVA_AST_RETURN_STMT:
if (stmt->data.return_stmt.value) {
_rava_ir_gen_expression(gen, stmt->data.return_stmt.value);
@@ -546,6 +964,67 @@ static void _rava_ir_gen_statement(RavaIRGenerator_t *gen, RavaASTNode_t *stmt)
break;
}
case RAVA_AST_SWITCH_STMT: {
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 };
gen->loop_context = &switch_ctx;
size_t case_count = stmt->children_count;
int *case_labels = malloc(case_count * sizeof(int));
int default_label = -1;
for (size_t i = 0; i < case_count; i++) {
case_labels[i] = rava_instruction_list_new_label(gen->current_method->instructions);
if (stmt->children[i]->data.case_stmt.is_default) {
default_label = case_labels[i];
}
}
for (size_t i = 0; i < case_count; i++) {
RavaASTNode_t *case_node = stmt->children[i];
if (!case_node->data.case_stmt.is_default) {
_rava_ir_gen_expression(gen, stmt->data.switch_stmt.expression);
_rava_ir_gen_expression(gen, case_node->data.case_stmt.value);
instr.opcode = RAVA_OP_EQ;
_rava_ir_emit(gen, instr);
instr.opcode = RAVA_OP_JUMP_IF_TRUE;
instr.operand.label_id = case_labels[i];
_rava_ir_emit(gen, instr);
}
}
if (default_label >= 0) {
instr.opcode = RAVA_OP_JUMP;
instr.operand.label_id = default_label;
_rava_ir_emit(gen, instr);
} else {
instr.opcode = RAVA_OP_JUMP;
instr.operand.label_id = end_label;
_rava_ir_emit(gen, instr);
}
for (size_t i = 0; i < case_count; i++) {
RavaASTNode_t *case_node = stmt->children[i];
instr.opcode = RAVA_OP_LABEL;
instr.operand.label_id = case_labels[i];
_rava_ir_emit(gen, instr);
for (size_t j = 0; j < case_node->children_count; j++) {
_rava_ir_gen_statement(gen, case_node->children[j]);
}
}
instr.opcode = RAVA_OP_LABEL;
instr.operand.label_id = end_label;
_rava_ir_emit(gen, instr);
free(case_labels);
gen->loop_context = switch_ctx.parent;
break;
}
case RAVA_AST_BREAK_STMT:
if (gen->loop_context) {
instr.opcode = RAVA_OP_JUMP;
@@ -562,6 +1041,76 @@ static void _rava_ir_gen_statement(RavaIRGenerator_t *gen, RavaASTNode_t *stmt)
}
break;
case RAVA_AST_THROW_STMT:
if (stmt->data.throw_stmt.expression) {
_rava_ir_gen_expression(gen, stmt->data.throw_stmt.expression);
} else {
instr.opcode = RAVA_OP_LOAD_CONST;
instr.operand.int_value = 1;
_rava_ir_emit(gen, instr);
}
instr.opcode = RAVA_OP_THROW;
_rava_ir_emit(gen, instr);
break;
case RAVA_AST_TRY_STMT: {
int catch_label = rava_instruction_list_new_label(gen->current_method->instructions);
int finally_label = rava_instruction_list_new_label(gen->current_method->instructions);
int end_label = rava_instruction_list_new_label(gen->current_method->instructions);
int exception_local = gen->next_local++;
gen->current_method->local_count = gen->next_local;
instr.opcode = RAVA_OP_TRY_BEGIN;
instr.operand.try_handler.catch_label = catch_label;
instr.operand.try_handler.finally_label = stmt->data.try_stmt.finally_block ? finally_label : -1;
instr.operand.try_handler.end_label = end_label;
instr.operand.try_handler.exception_local = exception_local;
_rava_ir_emit(gen, instr);
_rava_ir_gen_statement(gen, stmt->data.try_stmt.try_block);
instr.opcode = RAVA_OP_TRY_END;
_rava_ir_emit(gen, instr);
if (stmt->data.try_stmt.finally_block) {
instr.opcode = RAVA_OP_JUMP;
instr.operand.label_id = finally_label;
_rava_ir_emit(gen, instr);
} else {
instr.opcode = RAVA_OP_JUMP;
instr.operand.label_id = end_label;
_rava_ir_emit(gen, instr);
}
instr.opcode = RAVA_OP_LABEL;
instr.operand.label_id = catch_label;
_rava_ir_emit(gen, instr);
for (size_t i = 0; i < stmt->data.try_stmt.catch_count; i++) {
RavaASTNode_t *catch_node = stmt->data.try_stmt.catch_clauses[i];
if (catch_node->data.catch_clause.exception_name) {
_rava_ir_add_local(gen, catch_node->data.catch_clause.exception_name, exception_local);
}
_rava_ir_gen_statement(gen, catch_node->data.catch_clause.body);
}
if (stmt->data.try_stmt.finally_block) {
instr.opcode = RAVA_OP_LABEL;
instr.operand.label_id = finally_label;
_rava_ir_emit(gen, instr);
_rava_ir_gen_statement(gen, stmt->data.try_stmt.finally_block);
}
instr.opcode = RAVA_OP_LABEL;
instr.operand.label_id = end_label;
_rava_ir_emit(gen, instr);
break;
}
default:
break;
}