2025-12-02 06:54:32 +01:00
|
|
|
#define _POSIX_C_SOURCE 200809L
|
|
|
|
|
#include "ir_gen.h"
|
|
|
|
|
#include <stdlib.h>
|
|
|
|
|
#include <string.h>
|
|
|
|
|
#include <stdio.h>
|
|
|
|
|
|
|
|
|
|
static void _rava_ir_gen_expression(RavaIRGenerator_t *gen, RavaASTNode_t *expr);
|
|
|
|
|
static void _rava_ir_gen_statement(RavaIRGenerator_t *gen, RavaASTNode_t *stmt);
|
|
|
|
|
|
2025-12-03 14:08:55 +01:00
|
|
|
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;
|
|
|
|
|
}
|
|
|
|
|
|
2025-12-02 06:54:32 +01:00
|
|
|
static void _rava_ir_clear_locals(RavaIRGenerator_t *gen) {
|
|
|
|
|
RavaLocalVar_t *current = gen->locals;
|
|
|
|
|
while (current) {
|
|
|
|
|
RavaLocalVar_t *next = current->next;
|
|
|
|
|
free(current->name);
|
|
|
|
|
free(current);
|
|
|
|
|
current = next;
|
|
|
|
|
}
|
|
|
|
|
gen->locals = NULL;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void _rava_ir_add_local(RavaIRGenerator_t *gen, const char *name, size_t index) {
|
|
|
|
|
RavaLocalVar_t *local = calloc(1, sizeof(RavaLocalVar_t));
|
|
|
|
|
local->name = strdup(name);
|
|
|
|
|
local->index = index;
|
|
|
|
|
local->next = gen->locals;
|
|
|
|
|
gen->locals = local;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static int _rava_ir_find_local(RavaIRGenerator_t *gen, const char *name) {
|
|
|
|
|
for (RavaLocalVar_t *local = gen->locals; local; local = local->next) {
|
|
|
|
|
if (strcmp(local->name, name) == 0) {
|
|
|
|
|
return (int)local->index;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
return -1;
|
|
|
|
|
}
|
|
|
|
|
|
2025-12-02 21:12:50 +01:00
|
|
|
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;
|
|
|
|
|
}
|
|
|
|
|
|
2025-12-02 06:54:32 +01:00
|
|
|
RavaIRGenerator_t* rava_ir_generator_create(RavaSemanticAnalyzer_t *analyzer) {
|
|
|
|
|
RavaIRGenerator_t *gen = calloc(1, sizeof(RavaIRGenerator_t));
|
|
|
|
|
gen->program = rava_program_create();
|
|
|
|
|
gen->current_class = NULL;
|
|
|
|
|
gen->current_method = NULL;
|
|
|
|
|
gen->analyzer = analyzer;
|
|
|
|
|
gen->next_local = 0;
|
|
|
|
|
gen->locals = NULL;
|
|
|
|
|
gen->loop_context = NULL;
|
|
|
|
|
gen->error_message = NULL;
|
|
|
|
|
gen->had_error = false;
|
|
|
|
|
return gen;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void rava_ir_generator_destroy(RavaIRGenerator_t *generator) {
|
|
|
|
|
if (!generator) return;
|
|
|
|
|
_rava_ir_clear_locals(generator);
|
|
|
|
|
free(generator->error_message);
|
|
|
|
|
free(generator);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void _rava_ir_emit(RavaIRGenerator_t *gen, RavaInstruction_t instr) {
|
|
|
|
|
if (!gen->current_method) return;
|
|
|
|
|
rava_instruction_list_add(gen->current_method->instructions, instr);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void _rava_ir_gen_binary_expr(RavaIRGenerator_t *gen, RavaASTNode_t *expr) {
|
|
|
|
|
_rava_ir_gen_expression(gen, expr->data.binary.left);
|
|
|
|
|
_rava_ir_gen_expression(gen, expr->data.binary.right);
|
|
|
|
|
|
|
|
|
|
RavaInstruction_t instr = {0};
|
|
|
|
|
instr.line = expr->line;
|
|
|
|
|
|
|
|
|
|
switch (expr->data.binary.op) {
|
|
|
|
|
case RAVA_BINOP_ADD: instr.opcode = RAVA_OP_ADD; break;
|
|
|
|
|
case RAVA_BINOP_SUB: instr.opcode = RAVA_OP_SUB; break;
|
|
|
|
|
case RAVA_BINOP_MUL: instr.opcode = RAVA_OP_MUL; break;
|
|
|
|
|
case RAVA_BINOP_DIV: instr.opcode = RAVA_OP_DIV; break;
|
|
|
|
|
case RAVA_BINOP_MOD: instr.opcode = RAVA_OP_MOD; break;
|
|
|
|
|
case RAVA_BINOP_EQ: instr.opcode = RAVA_OP_EQ; break;
|
|
|
|
|
case RAVA_BINOP_NE: instr.opcode = RAVA_OP_NE; break;
|
|
|
|
|
case RAVA_BINOP_LT: instr.opcode = RAVA_OP_LT; break;
|
|
|
|
|
case RAVA_BINOP_LE: instr.opcode = RAVA_OP_LE; break;
|
|
|
|
|
case RAVA_BINOP_GT: instr.opcode = RAVA_OP_GT; break;
|
|
|
|
|
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;
|
2025-12-02 21:12:50 +01:00
|
|
|
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;
|
2025-12-02 06:54:32 +01:00
|
|
|
default: instr.opcode = RAVA_OP_NOP; break;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
_rava_ir_emit(gen, instr);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void _rava_ir_gen_expression(RavaIRGenerator_t *gen, RavaASTNode_t *expr) {
|
|
|
|
|
if (!expr) return;
|
|
|
|
|
|
|
|
|
|
RavaInstruction_t instr = {0};
|
|
|
|
|
instr.line = expr->line;
|
|
|
|
|
|
|
|
|
|
switch (expr->type) {
|
|
|
|
|
case RAVA_AST_LITERAL_EXPR:
|
|
|
|
|
if (expr->data.literal.literal_type == RAVA_TOKEN_LITERAL_STRING) {
|
|
|
|
|
instr.opcode = RAVA_OP_LOAD_STRING;
|
|
|
|
|
instr.operand.string_value = strdup(expr->data.literal.value.string_value);
|
|
|
|
|
_rava_ir_emit(gen, instr);
|
|
|
|
|
} else if (expr->data.literal.literal_type == RAVA_TOKEN_LITERAL_LONG) {
|
|
|
|
|
instr.opcode = RAVA_OP_LOAD_LONG;
|
|
|
|
|
instr.operand.int_value = expr->data.literal.value.int_value;
|
|
|
|
|
_rava_ir_emit(gen, instr);
|
|
|
|
|
} else if (expr->data.literal.literal_type == RAVA_TOKEN_LITERAL_DOUBLE) {
|
|
|
|
|
instr.opcode = RAVA_OP_LOAD_DOUBLE;
|
|
|
|
|
instr.operand.float_value = expr->data.literal.value.float_value;
|
|
|
|
|
_rava_ir_emit(gen, instr);
|
|
|
|
|
} else {
|
|
|
|
|
instr.opcode = RAVA_OP_LOAD_CONST;
|
|
|
|
|
instr.operand.int_value = expr->data.literal.value.int_value;
|
|
|
|
|
_rava_ir_emit(gen, instr);
|
|
|
|
|
}
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case RAVA_AST_IDENTIFIER_EXPR: {
|
|
|
|
|
int local_index = _rava_ir_find_local(gen, expr->data.identifier.name);
|
|
|
|
|
if (local_index >= 0) {
|
|
|
|
|
instr.opcode = RAVA_OP_LOAD_LOCAL;
|
|
|
|
|
instr.operand.var.index = (size_t)local_index;
|
|
|
|
|
_rava_ir_emit(gen, instr);
|
|
|
|
|
}
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
case RAVA_AST_BINARY_EXPR:
|
2025-12-02 22:04:26 +01:00
|
|
|
if (expr->data.binary.op == RAVA_BINOP_AND) {
|
|
|
|
|
_rava_ir_gen_expression(gen, expr->data.binary.left);
|
|
|
|
|
instr.opcode = RAVA_OP_DUP;
|
|
|
|
|
_rava_ir_emit(gen, instr);
|
|
|
|
|
int end_label = rava_instruction_list_new_label(gen->current_method->instructions);
|
|
|
|
|
instr.opcode = RAVA_OP_JUMP_IF_FALSE;
|
|
|
|
|
instr.operand.label_id = end_label;
|
|
|
|
|
_rava_ir_emit(gen, instr);
|
|
|
|
|
instr.opcode = RAVA_OP_POP;
|
|
|
|
|
_rava_ir_emit(gen, instr);
|
|
|
|
|
_rava_ir_gen_expression(gen, expr->data.binary.right);
|
|
|
|
|
instr.opcode = RAVA_OP_LABEL;
|
|
|
|
|
instr.operand.label_id = end_label;
|
|
|
|
|
_rava_ir_emit(gen, instr);
|
|
|
|
|
} else if (expr->data.binary.op == RAVA_BINOP_OR) {
|
|
|
|
|
_rava_ir_gen_expression(gen, expr->data.binary.left);
|
|
|
|
|
instr.opcode = RAVA_OP_DUP;
|
|
|
|
|
_rava_ir_emit(gen, instr);
|
|
|
|
|
int end_label = rava_instruction_list_new_label(gen->current_method->instructions);
|
|
|
|
|
instr.opcode = RAVA_OP_JUMP_IF_TRUE;
|
|
|
|
|
instr.operand.label_id = end_label;
|
|
|
|
|
_rava_ir_emit(gen, instr);
|
|
|
|
|
instr.opcode = RAVA_OP_POP;
|
|
|
|
|
_rava_ir_emit(gen, instr);
|
|
|
|
|
_rava_ir_gen_expression(gen, expr->data.binary.right);
|
|
|
|
|
instr.opcode = RAVA_OP_LABEL;
|
|
|
|
|
instr.operand.label_id = end_label;
|
|
|
|
|
_rava_ir_emit(gen, instr);
|
|
|
|
|
} else {
|
|
|
|
|
_rava_ir_gen_binary_expr(gen, expr);
|
|
|
|
|
}
|
2025-12-02 06:54:32 +01:00
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case RAVA_AST_UNARY_EXPR:
|
2025-12-02 22:04:26 +01:00
|
|
|
if (expr->data.unary.op == RAVA_UNOP_PLUS) {
|
|
|
|
|
_rava_ir_gen_expression(gen, expr->data.unary.operand);
|
|
|
|
|
} else if (expr->data.unary.op == RAVA_UNOP_MINUS) {
|
2025-12-02 06:54:32 +01:00
|
|
|
_rava_ir_gen_expression(gen, expr->data.unary.operand);
|
|
|
|
|
instr.opcode = RAVA_OP_NEG;
|
|
|
|
|
_rava_ir_emit(gen, instr);
|
|
|
|
|
} else if (expr->data.unary.op == RAVA_UNOP_NOT) {
|
|
|
|
|
_rava_ir_gen_expression(gen, expr->data.unary.operand);
|
|
|
|
|
instr.opcode = RAVA_OP_NOT;
|
|
|
|
|
_rava_ir_emit(gen, instr);
|
2025-12-02 22:04:26 +01:00
|
|
|
} else if (expr->data.unary.op == RAVA_UNOP_BITNOT) {
|
|
|
|
|
_rava_ir_gen_expression(gen, expr->data.unary.operand);
|
|
|
|
|
instr.opcode = RAVA_OP_BITNOT;
|
|
|
|
|
_rava_ir_emit(gen, instr);
|
2025-12-02 06:54:32 +01:00
|
|
|
} else if (expr->data.unary.op == RAVA_UNOP_PREINC || expr->data.unary.op == RAVA_UNOP_PREDEC) {
|
|
|
|
|
if (expr->data.unary.operand->type == RAVA_AST_IDENTIFIER_EXPR) {
|
|
|
|
|
int local_index = _rava_ir_find_local(gen, expr->data.unary.operand->data.identifier.name);
|
|
|
|
|
if (local_index >= 0) {
|
|
|
|
|
instr.opcode = RAVA_OP_LOAD_LOCAL;
|
|
|
|
|
instr.operand.var.index = (size_t)local_index;
|
|
|
|
|
_rava_ir_emit(gen, instr);
|
|
|
|
|
instr.opcode = RAVA_OP_LOAD_CONST;
|
|
|
|
|
instr.operand.int_value = 1;
|
|
|
|
|
_rava_ir_emit(gen, instr);
|
|
|
|
|
instr.opcode = (expr->data.unary.op == RAVA_UNOP_PREINC) ? RAVA_OP_ADD : RAVA_OP_SUB;
|
|
|
|
|
_rava_ir_emit(gen, instr);
|
|
|
|
|
instr.opcode = RAVA_OP_DUP;
|
|
|
|
|
_rava_ir_emit(gen, instr);
|
|
|
|
|
instr.opcode = RAVA_OP_STORE_LOCAL;
|
|
|
|
|
instr.operand.var.index = (size_t)local_index;
|
|
|
|
|
_rava_ir_emit(gen, instr);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
} else if (expr->data.unary.op == RAVA_UNOP_POSTINC || expr->data.unary.op == RAVA_UNOP_POSTDEC) {
|
|
|
|
|
if (expr->data.unary.operand->type == RAVA_AST_IDENTIFIER_EXPR) {
|
|
|
|
|
int local_index = _rava_ir_find_local(gen, expr->data.unary.operand->data.identifier.name);
|
|
|
|
|
if (local_index >= 0) {
|
|
|
|
|
instr.opcode = RAVA_OP_LOAD_LOCAL;
|
|
|
|
|
instr.operand.var.index = (size_t)local_index;
|
|
|
|
|
_rava_ir_emit(gen, instr);
|
|
|
|
|
instr.opcode = RAVA_OP_LOAD_LOCAL;
|
|
|
|
|
instr.operand.var.index = (size_t)local_index;
|
|
|
|
|
_rava_ir_emit(gen, instr);
|
|
|
|
|
instr.opcode = RAVA_OP_LOAD_CONST;
|
|
|
|
|
instr.operand.int_value = 1;
|
|
|
|
|
_rava_ir_emit(gen, instr);
|
|
|
|
|
instr.opcode = (expr->data.unary.op == RAVA_UNOP_POSTINC) ? RAVA_OP_ADD : RAVA_OP_SUB;
|
|
|
|
|
_rava_ir_emit(gen, instr);
|
|
|
|
|
instr.opcode = RAVA_OP_STORE_LOCAL;
|
|
|
|
|
instr.operand.var.index = (size_t)local_index;
|
|
|
|
|
_rava_ir_emit(gen, instr);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
} else {
|
|
|
|
|
_rava_ir_gen_expression(gen, expr->data.unary.operand);
|
|
|
|
|
}
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case RAVA_AST_ASSIGN_EXPR:
|
|
|
|
|
if (expr->data.assign.target->type == RAVA_AST_ARRAY_ACCESS_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.index);
|
|
|
|
|
_rava_ir_gen_expression(gen, expr->data.assign.value);
|
2025-12-04 06:14:22 +01:00
|
|
|
|
|
|
|
|
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;
|
2025-12-02 06:54:32 +01:00
|
|
|
_rava_ir_emit(gen, instr);
|
|
|
|
|
} else if (expr->data.assign.target->type == RAVA_AST_MEMBER_ACCESS_EXPR) {
|
2025-12-02 21:12:50 +01:00
|
|
|
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;
|
|
|
|
|
}
|
|
|
|
|
}
|
2025-12-02 06:54:32 +01:00
|
|
|
_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;
|
|
|
|
|
instr.operand.field.field_name = strdup(expr->data.assign.target->data.member_access.member);
|
|
|
|
|
_rava_ir_emit(gen, instr);
|
|
|
|
|
} else {
|
|
|
|
|
_rava_ir_gen_expression(gen, expr->data.assign.value);
|
|
|
|
|
|
|
|
|
|
if (expr->data.assign.target->type == RAVA_AST_IDENTIFIER_EXPR) {
|
|
|
|
|
int local_index = _rava_ir_find_local(gen, expr->data.assign.target->data.identifier.name);
|
|
|
|
|
if (local_index >= 0) {
|
|
|
|
|
instr.opcode = RAVA_OP_STORE_LOCAL;
|
|
|
|
|
instr.operand.var.index = (size_t)local_index;
|
|
|
|
|
_rava_ir_emit(gen, instr);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case RAVA_AST_MEMBER_ACCESS_EXPR:
|
2025-12-02 21:12:50 +01:00
|
|
|
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;
|
|
|
|
|
}
|
|
|
|
|
}
|
2025-12-02 06:54:32 +01:00
|
|
|
_rava_ir_gen_expression(gen, expr->data.member_access.object);
|
2025-12-03 14:08:55 +01:00
|
|
|
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);
|
|
|
|
|
}
|
2025-12-02 06:54:32 +01:00
|
|
|
_rava_ir_emit(gen, instr);
|
|
|
|
|
break;
|
|
|
|
|
|
2025-12-04 06:14:22 +01:00
|
|
|
case RAVA_AST_ARRAY_ACCESS_EXPR: {
|
2025-12-02 06:54:32 +01:00
|
|
|
_rava_ir_gen_expression(gen, expr->data.array_access.array);
|
|
|
|
|
_rava_ir_gen_expression(gen, expr->data.array_access.index);
|
2025-12-04 06:14:22 +01:00
|
|
|
|
|
|
|
|
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;
|
2025-12-02 06:54:32 +01:00
|
|
|
_rava_ir_emit(gen, instr);
|
|
|
|
|
break;
|
2025-12-04 06:14:22 +01:00
|
|
|
}
|
2025-12-02 06:54:32 +01:00
|
|
|
|
|
|
|
|
case RAVA_AST_NEW_EXPR:
|
|
|
|
|
if (expr->data.new_expr.type && expr->data.new_expr.type->data.type.is_array) {
|
2025-12-03 14:08:55 +01:00
|
|
|
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);
|
2025-12-02 06:54:32 +01:00
|
|
|
_rava_ir_gen_expression(gen, expr->data.new_expr.arguments[0]);
|
2025-12-03 14:08:55 +01:00
|
|
|
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);
|
2025-12-02 06:54:32 +01:00
|
|
|
}
|
|
|
|
|
} 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);
|
|
|
|
|
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);
|
|
|
|
|
}
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case RAVA_AST_CALL_EXPR: {
|
|
|
|
|
bool is_println = false;
|
|
|
|
|
bool is_print = false;
|
|
|
|
|
bool is_string_length = false;
|
|
|
|
|
bool is_string_charat = false;
|
2025-12-02 21:12:50 +01:00
|
|
|
bool is_string_substring = false;
|
2025-12-02 06:54:32 +01:00
|
|
|
bool is_string_equals = false;
|
2025-12-02 21:12:50 +01:00
|
|
|
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;
|
2025-12-02 06:54:32 +01:00
|
|
|
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;
|
2025-12-02 21:12:50 +01:00
|
|
|
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;
|
2025-12-02 06:54:32 +01:00
|
|
|
RavaASTNode_t *string_object = NULL;
|
|
|
|
|
|
|
|
|
|
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_IDENTIFIER_EXPR &&
|
|
|
|
|
strcmp(member->data.member_access.object->data.identifier.name, "System") == 0) {
|
|
|
|
|
if (strcmp(member->data.member_access.member, "currentTimeMillis") == 0) {
|
|
|
|
|
is_current_time_millis = true;
|
|
|
|
|
} else if (strcmp(member->data.member_access.member, "nanoTime") == 0) {
|
|
|
|
|
is_nano_time = true;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
if (member->data.member_access.object->type == RAVA_AST_MEMBER_ACCESS_EXPR) {
|
|
|
|
|
RavaASTNode_t *system_out = member->data.member_access.object;
|
|
|
|
|
if (system_out->data.member_access.object->type == RAVA_AST_IDENTIFIER_EXPR &&
|
|
|
|
|
strcmp(system_out->data.member_access.object->data.identifier.name, "System") == 0 &&
|
|
|
|
|
strcmp(system_out->data.member_access.member, "out") == 0) {
|
|
|
|
|
if (strcmp(member->data.member_access.member, "println") == 0) {
|
|
|
|
|
is_println = true;
|
|
|
|
|
} else if (strcmp(member->data.member_access.member, "print") == 0) {
|
|
|
|
|
is_print = true;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
if (member->data.member_access.object->type == RAVA_AST_IDENTIFIER_EXPR &&
|
|
|
|
|
strcmp(member->data.member_access.object->data.identifier.name, "Files") == 0) {
|
|
|
|
|
if (strcmp(member->data.member_access.member, "read") == 0 && expr->data.call.arguments_count == 1) {
|
|
|
|
|
is_file_read = true;
|
|
|
|
|
} else if (strcmp(member->data.member_access.member, "write") == 0 && expr->data.call.arguments_count == 2) {
|
|
|
|
|
is_file_write = true;
|
|
|
|
|
} else if (strcmp(member->data.member_access.member, "exists") == 0 && expr->data.call.arguments_count == 1) {
|
|
|
|
|
is_file_exists = true;
|
|
|
|
|
} else if (strcmp(member->data.member_access.member, "delete") == 0 && expr->data.call.arguments_count == 1) {
|
|
|
|
|
is_file_delete = true;
|
|
|
|
|
}
|
|
|
|
|
}
|
2025-12-02 21:12:50 +01:00
|
|
|
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;
|
|
|
|
|
}
|
|
|
|
|
}
|
2025-12-02 06:54:32 +01:00
|
|
|
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;
|
|
|
|
|
} else if (strcmp(member->data.member_access.member, "charAt") == 0 && expr->data.call.arguments_count == 1) {
|
|
|
|
|
is_string_charat = true;
|
|
|
|
|
string_object = member->data.member_access.object;
|
|
|
|
|
} 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;
|
2025-12-02 21:12:50 +01:00
|
|
|
} 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;
|
2025-12-02 06:54:32 +01:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (is_current_time_millis) {
|
|
|
|
|
instr.opcode = RAVA_OP_CURRENT_TIME_MILLIS;
|
|
|
|
|
_rava_ir_emit(gen, instr);
|
|
|
|
|
} else if (is_nano_time) {
|
|
|
|
|
instr.opcode = RAVA_OP_NANO_TIME;
|
|
|
|
|
_rava_ir_emit(gen, instr);
|
|
|
|
|
} else if (is_file_read) {
|
|
|
|
|
_rava_ir_gen_expression(gen, expr->data.call.arguments[0]);
|
|
|
|
|
instr.opcode = RAVA_OP_FILE_READ;
|
|
|
|
|
_rava_ir_emit(gen, instr);
|
|
|
|
|
} else if (is_file_write) {
|
|
|
|
|
_rava_ir_gen_expression(gen, expr->data.call.arguments[0]);
|
|
|
|
|
_rava_ir_gen_expression(gen, expr->data.call.arguments[1]);
|
|
|
|
|
instr.opcode = RAVA_OP_FILE_WRITE;
|
|
|
|
|
_rava_ir_emit(gen, instr);
|
|
|
|
|
} else if (is_file_exists) {
|
|
|
|
|
_rava_ir_gen_expression(gen, expr->data.call.arguments[0]);
|
|
|
|
|
instr.opcode = RAVA_OP_FILE_EXISTS;
|
|
|
|
|
_rava_ir_emit(gen, instr);
|
|
|
|
|
} else if (is_file_delete) {
|
|
|
|
|
_rava_ir_gen_expression(gen, expr->data.call.arguments[0]);
|
|
|
|
|
instr.opcode = RAVA_OP_FILE_DELETE;
|
|
|
|
|
_rava_ir_emit(gen, instr);
|
|
|
|
|
} else if (is_string_length) {
|
|
|
|
|
_rava_ir_gen_expression(gen, string_object);
|
|
|
|
|
instr.opcode = RAVA_OP_STRING_LENGTH;
|
|
|
|
|
_rava_ir_emit(gen, instr);
|
|
|
|
|
} else if (is_string_charat) {
|
|
|
|
|
_rava_ir_gen_expression(gen, string_object);
|
|
|
|
|
_rava_ir_gen_expression(gen, expr->data.call.arguments[0]);
|
|
|
|
|
instr.opcode = RAVA_OP_STRING_CHARAT;
|
|
|
|
|
_rava_ir_emit(gen, instr);
|
|
|
|
|
} else if (is_string_equals) {
|
|
|
|
|
_rava_ir_gen_expression(gen, string_object);
|
|
|
|
|
_rava_ir_gen_expression(gen, expr->data.call.arguments[0]);
|
|
|
|
|
instr.opcode = RAVA_OP_STRING_EQUALS;
|
|
|
|
|
_rava_ir_emit(gen, instr);
|
2025-12-02 21:12:50 +01:00
|
|
|
} 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);
|
2025-12-02 06:54:32 +01:00
|
|
|
} 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]);
|
|
|
|
|
}
|
|
|
|
|
if (is_println) {
|
|
|
|
|
instr.opcode = RAVA_OP_PRINTLN;
|
|
|
|
|
} else {
|
|
|
|
|
instr.opcode = RAVA_OP_PRINT;
|
|
|
|
|
}
|
|
|
|
|
_rava_ir_emit(gen, instr);
|
2025-12-03 14:08:55 +01:00
|
|
|
} 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);
|
2025-12-02 06:54:32 +01:00
|
|
|
} else if (expr->data.call.callee->type == RAVA_AST_MEMBER_ACCESS_EXPR) {
|
|
|
|
|
RavaASTNode_t *member = expr->data.call.callee;
|
2025-12-02 21:12:50 +01:00
|
|
|
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);
|
2025-12-02 06:54:32 +01:00
|
|
|
}
|
|
|
|
|
} else {
|
|
|
|
|
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_STATIC;
|
|
|
|
|
if (expr->data.call.callee->type == RAVA_AST_IDENTIFIER_EXPR) {
|
2025-12-03 23:51:38 +01:00
|
|
|
const char *method_name = expr->data.call.callee->data.identifier.name;
|
|
|
|
|
if (gen->current_method && strcmp(gen->current_method->name, method_name) == 0) {
|
|
|
|
|
instr.opcode = RAVA_OP_CALL_RECURSIVE;
|
|
|
|
|
instr.operand.call.cached_method = (void*)gen->current_method;
|
|
|
|
|
}
|
2025-12-02 06:54:32 +01:00
|
|
|
instr.operand.call.class_name = strdup(gen->current_class->name);
|
2025-12-03 23:51:38 +01:00
|
|
|
instr.operand.call.method_name = strdup(method_name);
|
2025-12-02 06:54:32 +01:00
|
|
|
instr.operand.call.arg_count = expr->data.call.arguments_count;
|
|
|
|
|
}
|
|
|
|
|
_rava_ir_emit(gen, instr);
|
|
|
|
|
}
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
case RAVA_AST_THIS_EXPR:
|
|
|
|
|
instr.opcode = RAVA_OP_LOAD_THIS;
|
|
|
|
|
_rava_ir_emit(gen, instr);
|
|
|
|
|
break;
|
|
|
|
|
|
2025-12-02 21:12:50 +01:00
|
|
|
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;
|
|
|
|
|
|
2025-12-02 06:54:32 +01:00
|
|
|
default:
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void _rava_ir_gen_statement(RavaIRGenerator_t *gen, RavaASTNode_t *stmt) {
|
|
|
|
|
if (!stmt) return;
|
|
|
|
|
|
|
|
|
|
RavaInstruction_t instr = {0};
|
|
|
|
|
instr.line = stmt->line;
|
|
|
|
|
|
|
|
|
|
switch (stmt->type) {
|
|
|
|
|
case RAVA_AST_BLOCK_STMT:
|
|
|
|
|
for (size_t i = 0; i < stmt->children_count; i++) {
|
|
|
|
|
_rava_ir_gen_statement(gen, stmt->children[i]);
|
|
|
|
|
}
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case RAVA_AST_IF_STMT: {
|
|
|
|
|
_rava_ir_gen_expression(gen, stmt->data.if_stmt.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_statement(gen, stmt->data.if_stmt.then_stmt);
|
|
|
|
|
|
|
|
|
|
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);
|
|
|
|
|
|
|
|
|
|
if (stmt->data.if_stmt.else_stmt) {
|
|
|
|
|
_rava_ir_gen_statement(gen, stmt->data.if_stmt.else_stmt);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
instr.opcode = RAVA_OP_LABEL;
|
|
|
|
|
instr.operand.label_id = end_label;
|
|
|
|
|
_rava_ir_emit(gen, instr);
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
case RAVA_AST_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);
|
|
|
|
|
|
2025-12-04 06:14:22 +01:00
|
|
|
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
|
|
|
|
|
};
|
2025-12-02 06:54:32 +01:00
|
|
|
gen->loop_context = &loop_ctx;
|
|
|
|
|
|
|
|
|
|
instr.opcode = RAVA_OP_LABEL;
|
|
|
|
|
instr.operand.label_id = start_label;
|
|
|
|
|
_rava_ir_emit(gen, instr);
|
|
|
|
|
|
|
|
|
|
_rava_ir_gen_expression(gen, stmt->data.while_stmt.condition);
|
|
|
|
|
|
|
|
|
|
instr.opcode = RAVA_OP_JUMP_IF_FALSE;
|
|
|
|
|
instr.operand.label_id = end_label;
|
|
|
|
|
_rava_ir_emit(gen, instr);
|
|
|
|
|
|
|
|
|
|
_rava_ir_gen_statement(gen, stmt->data.while_stmt.body);
|
|
|
|
|
|
|
|
|
|
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;
|
|
|
|
|
}
|
|
|
|
|
|
2025-12-02 21:12:50 +01:00
|
|
|
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);
|
|
|
|
|
|
2025-12-04 06:14:22 +01:00
|
|
|
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
|
|
|
|
|
};
|
2025-12-02 21:12:50 +01:00
|
|
|
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;
|
|
|
|
|
}
|
|
|
|
|
|
2025-12-02 06:54:32 +01:00
|
|
|
case RAVA_AST_FOR_STMT: {
|
2025-12-04 06:14:22 +01:00
|
|
|
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;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2025-12-02 06:54:32 +01:00
|
|
|
if (stmt->data.for_stmt.init) {
|
|
|
|
|
if (stmt->data.for_stmt.init->type == RAVA_AST_VAR_DECL) {
|
|
|
|
|
_rava_ir_gen_statement(gen, stmt->data.for_stmt.init);
|
|
|
|
|
} else {
|
|
|
|
|
_rava_ir_gen_expression(gen, stmt->data.for_stmt.init);
|
|
|
|
|
instr.opcode = RAVA_OP_POP;
|
|
|
|
|
_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);
|
|
|
|
|
|
2025-12-04 06:14:22 +01:00
|
|
|
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
|
|
|
|
|
};
|
2025-12-02 06:54:32 +01:00
|
|
|
gen->loop_context = &loop_ctx;
|
|
|
|
|
|
|
|
|
|
instr.opcode = RAVA_OP_LABEL;
|
|
|
|
|
instr.operand.label_id = start_label;
|
|
|
|
|
_rava_ir_emit(gen, instr);
|
|
|
|
|
|
|
|
|
|
if (stmt->data.for_stmt.condition) {
|
|
|
|
|
_rava_ir_gen_expression(gen, stmt->data.for_stmt.condition);
|
|
|
|
|
instr.opcode = RAVA_OP_JUMP_IF_FALSE;
|
|
|
|
|
instr.operand.label_id = end_label;
|
|
|
|
|
_rava_ir_emit(gen, instr);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
_rava_ir_gen_statement(gen, stmt->data.for_stmt.body);
|
|
|
|
|
|
|
|
|
|
instr.opcode = RAVA_OP_LABEL;
|
|
|
|
|
instr.operand.label_id = continue_label;
|
|
|
|
|
_rava_ir_emit(gen, instr);
|
|
|
|
|
|
|
|
|
|
if (stmt->data.for_stmt.update) {
|
|
|
|
|
_rava_ir_gen_expression(gen, stmt->data.for_stmt.update);
|
|
|
|
|
instr.opcode = RAVA_OP_POP;
|
|
|
|
|
_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;
|
|
|
|
|
}
|
|
|
|
|
|
2025-12-02 21:12:50 +01:00
|
|
|
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);
|
|
|
|
|
|
2025-12-04 06:14:22 +01:00
|
|
|
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
|
|
|
|
|
};
|
2025-12-02 21:12:50 +01:00
|
|
|
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;
|
|
|
|
|
}
|
|
|
|
|
|
2025-12-02 06:54:32 +01:00
|
|
|
case RAVA_AST_RETURN_STMT:
|
|
|
|
|
if (stmt->data.return_stmt.value) {
|
|
|
|
|
_rava_ir_gen_expression(gen, stmt->data.return_stmt.value);
|
|
|
|
|
instr.opcode = RAVA_OP_RETURN;
|
|
|
|
|
} else {
|
|
|
|
|
instr.opcode = RAVA_OP_RETURN_VOID;
|
|
|
|
|
}
|
|
|
|
|
_rava_ir_emit(gen, instr);
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case RAVA_AST_EXPR_STMT:
|
|
|
|
|
if (stmt->children_count > 0) {
|
|
|
|
|
_rava_ir_gen_expression(gen, stmt->children[0]);
|
|
|
|
|
instr.opcode = RAVA_OP_POP;
|
|
|
|
|
_rava_ir_emit(gen, instr);
|
|
|
|
|
}
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case RAVA_AST_VAR_DECL: {
|
|
|
|
|
_rava_ir_add_local(gen, stmt->data.var_decl.name, gen->next_local);
|
|
|
|
|
gen->next_local++;
|
|
|
|
|
if (stmt->data.var_decl.initializer) {
|
|
|
|
|
_rava_ir_gen_expression(gen, stmt->data.var_decl.initializer);
|
|
|
|
|
instr.opcode = RAVA_OP_STORE_LOCAL;
|
|
|
|
|
instr.operand.var.index = gen->next_local - 1;
|
|
|
|
|
_rava_ir_emit(gen, instr);
|
|
|
|
|
}
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
|
2025-12-02 21:12:50 +01:00
|
|
|
case RAVA_AST_SWITCH_STMT: {
|
|
|
|
|
int end_label = rava_instruction_list_new_label(gen->current_method->instructions);
|
|
|
|
|
|
2025-12-04 06:14:22 +01:00
|
|
|
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
|
|
|
|
|
};
|
2025-12-02 21:12:50 +01:00
|
|
|
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;
|
|
|
|
|
}
|
|
|
|
|
|
2025-12-02 06:54:32 +01:00
|
|
|
case RAVA_AST_BREAK_STMT:
|
|
|
|
|
if (gen->loop_context) {
|
|
|
|
|
instr.opcode = RAVA_OP_JUMP;
|
|
|
|
|
instr.operand.label_id = gen->loop_context->break_label;
|
|
|
|
|
_rava_ir_emit(gen, instr);
|
|
|
|
|
}
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case RAVA_AST_CONTINUE_STMT:
|
|
|
|
|
if (gen->loop_context) {
|
|
|
|
|
instr.opcode = RAVA_OP_JUMP;
|
|
|
|
|
instr.operand.label_id = gen->loop_context->continue_label;
|
|
|
|
|
_rava_ir_emit(gen, instr);
|
|
|
|
|
}
|
|
|
|
|
break;
|
|
|
|
|
|
2025-12-02 21:12:50 +01:00
|
|
|
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;
|
|
|
|
|
}
|
|
|
|
|
|
2025-12-02 06:54:32 +01:00
|
|
|
default:
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void _rava_ir_gen_method(RavaIRGenerator_t *gen, RavaASTNode_t *method_node) {
|
|
|
|
|
if (method_node->type != RAVA_AST_METHOD_DECL) return;
|
|
|
|
|
|
|
|
|
|
RavaType_t *return_type = rava_type_from_name(
|
|
|
|
|
method_node->data.method_decl.return_type->data.type.type_name);
|
|
|
|
|
|
|
|
|
|
RavaMethod_t *method = rava_method_create(method_node->data.method_decl.name, return_type);
|
|
|
|
|
gen->current_method = method;
|
|
|
|
|
gen->next_local = 0;
|
|
|
|
|
_rava_ir_clear_locals(gen);
|
|
|
|
|
|
|
|
|
|
rava_symbol_table_enter_scope(gen->analyzer->symbol_table, method_node->data.method_decl.name);
|
|
|
|
|
|
|
|
|
|
for (size_t i = 0; i < method_node->children_count; i++) {
|
|
|
|
|
RavaASTNode_t *child = method_node->children[i];
|
|
|
|
|
|
|
|
|
|
if (child->type == RAVA_AST_PARAM_DECL) {
|
|
|
|
|
_rava_ir_add_local(gen, child->data.var_decl.name, gen->next_local);
|
|
|
|
|
gen->next_local++;
|
|
|
|
|
} else if (child->type == RAVA_AST_BLOCK_STMT) {
|
|
|
|
|
_rava_ir_gen_statement(gen, child);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
rava_symbol_table_exit_scope(gen->analyzer->symbol_table);
|
|
|
|
|
|
2025-12-03 14:08:55 +01:00
|
|
|
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;
|
|
|
|
|
}
|
2025-12-02 06:54:32 +01:00
|
|
|
rava_class_add_method(gen->current_class, method);
|
|
|
|
|
gen->current_method = NULL;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void _rava_ir_gen_constructor(RavaIRGenerator_t *gen, RavaASTNode_t *ctor_node) {
|
|
|
|
|
if (ctor_node->type != RAVA_AST_CONSTRUCTOR_DECL) return;
|
|
|
|
|
|
|
|
|
|
RavaType_t *void_type = rava_type_from_name("void");
|
|
|
|
|
RavaMethod_t *method = rava_method_create("<init>", void_type);
|
|
|
|
|
gen->current_method = method;
|
|
|
|
|
gen->next_local = 0;
|
|
|
|
|
_rava_ir_clear_locals(gen);
|
|
|
|
|
|
|
|
|
|
for (size_t i = 0; i < ctor_node->children_count; i++) {
|
|
|
|
|
RavaASTNode_t *child = ctor_node->children[i];
|
|
|
|
|
if (child->type == RAVA_AST_PARAM_DECL) {
|
|
|
|
|
_rava_ir_add_local(gen, child->data.var_decl.name, gen->next_local);
|
|
|
|
|
gen->next_local++;
|
|
|
|
|
} else if (child->type == RAVA_AST_BLOCK_STMT) {
|
|
|
|
|
_rava_ir_gen_statement(gen, child);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
RavaInstruction_t ret_instr = {0};
|
|
|
|
|
ret_instr.opcode = RAVA_OP_RETURN_VOID;
|
|
|
|
|
_rava_ir_emit(gen, ret_instr);
|
|
|
|
|
|
2025-12-03 14:08:55 +01:00
|
|
|
if (gen->next_local > method->local_count) {
|
|
|
|
|
method->local_count = gen->next_local;
|
|
|
|
|
}
|
2025-12-02 06:54:32 +01:00
|
|
|
rava_class_add_method(gen->current_class, method);
|
|
|
|
|
gen->current_method = NULL;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void _rava_ir_gen_class(RavaIRGenerator_t *gen, RavaASTNode_t *class_node) {
|
|
|
|
|
if (class_node->type != RAVA_AST_CLASS_DECL) return;
|
|
|
|
|
|
|
|
|
|
RavaClass_t *class = rava_class_create(class_node->data.class_decl.name);
|
|
|
|
|
if (class_node->data.class_decl.superclass) {
|
|
|
|
|
class->superclass = strdup(class_node->data.class_decl.superclass);
|
|
|
|
|
}
|
|
|
|
|
gen->current_class = class;
|
|
|
|
|
|
|
|
|
|
rava_symbol_table_enter_scope(gen->analyzer->symbol_table, class_node->data.class_decl.name);
|
|
|
|
|
|
2025-12-03 14:08:55 +01:00
|
|
|
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;
|
|
|
|
|
}
|
|
|
|
|
|
2025-12-02 06:54:32 +01:00
|
|
|
for (size_t i = 0; i < class_node->children_count; i++) {
|
|
|
|
|
RavaASTNode_t *child = class_node->children[i];
|
|
|
|
|
|
|
|
|
|
if (child->type == RAVA_AST_METHOD_DECL) {
|
|
|
|
|
_rava_ir_gen_method(gen, child);
|
|
|
|
|
} else if (child->type == RAVA_AST_CONSTRUCTOR_DECL) {
|
|
|
|
|
_rava_ir_gen_constructor(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;
|
|
|
|
|
|
|
|
|
|
if (root->type == RAVA_AST_COMPILATION_UNIT) {
|
|
|
|
|
for (size_t i = 0; i < root->children_count; i++) {
|
|
|
|
|
RavaASTNode_t *child = root->children[i];
|
|
|
|
|
if (child->type == RAVA_AST_CLASS_DECL) {
|
|
|
|
|
_rava_ir_gen_class(generator, child);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2025-12-03 15:01:02 +01:00
|
|
|
rava_program_prebuild_label_tables(generator->program);
|
|
|
|
|
|
2025-12-02 06:54:32 +01:00
|
|
|
return generator->program;
|
|
|
|
|
}
|