From 902a81528b9d2edcf93226a2ca13da6fcc1839e5 Mon Sep 17 00:00:00 2001 From: dec05eba Date: Mon, 23 Dec 2019 08:57:48 +0100 Subject: wip: function pointers and other stuff --- src/ast.c | 79 ++++++++++++------ src/bytecode/bytecode.c | 50 +++++++---- src/compiler.c | 7 +- src/ir/ir.c | 214 +++++++++++++++++++++++++++++++++--------------- src/parser.c | 48 +++++++---- src/program.c | 9 +- src/tokenizer.c | 19 ++++- 7 files changed, 296 insertions(+), 130 deletions(-) (limited to 'src') diff --git a/src/ast.c b/src/ast.c index 04ec646..504c1f9 100644 --- a/src/ast.c +++ b/src/ast.c @@ -169,6 +169,9 @@ BufferView ast_get_name(Ast *self) { case AST_NUMBER: name = self->value.number->code_ref; break; + case AST_BOOL: + name = self->value.bool->code_ref; + break; case AST_LHS: name = self->value.lhs_expr->var_name; break; @@ -352,6 +355,11 @@ void number_init(Number *self, AmalNumber *value, BufferView code_ref) { self->code_ref = code_ref; } +void ast_bool_init(AstBool *self, bool value, BufferView code_ref) { + self->value = value; + self->code_ref = code_ref; +} + void variable_init(Variable *self, BufferView name) { self->name = name; scope_named_object_init(&self->resolved_var); @@ -464,8 +472,7 @@ static void __scope_get_resolved_variable(Scope *self, Scope *start, AstCompiler exists = hash_map_get(&self->named_objects, name, &ast_result); if(!exists) { if(self->function_signature) { - FunctionParameter *func_param; - func_param = function_signature_get_parameter_by_name(self->function_signature, name); + FunctionParameter *func_param = function_signature_get_parameter_by_name(self->function_signature, name); if(func_param) { prev_scope = context->scope; context->scope = self; @@ -477,6 +484,9 @@ static void __scope_get_resolved_variable(Scope *self, Scope *start, AstCompiler result->resolve_data = &func_param->resolve_data; return; } + + /* TODO: Remove this when closures can capture variables */ + assert(self->parent == &context->parser->struct_decl.body); } if(self->parent) { @@ -721,8 +731,7 @@ static Scope* ast_resolved_type_get_scope(AstResolvedType *self) { } static void funcdecl_resolve(Ast *self, AstCompilerContext *context) { - FunctionDecl *func_decl; - func_decl = self->value.func_decl; + FunctionDecl *func_decl = self->value.func_decl; function_signature_resolve(func_decl->signature, context); scope_resolve(&func_decl->body, context); self->resolve_data.type.type = RESOLVED_TYPE_FUNC_SIG; @@ -734,27 +743,39 @@ static usize min(usize a, usize b) { } static bool is_c_pointer_compatible(VariableType *self) { - return self->variable_type_flags & (VARIABLE_TYPE_FLAG_OPTIONAL | VARIABLE_TYPE_FLAG_BORROW); + return self->variable_type_flags & VARIABLE_TYPE_FLAG_BORROW; } -static bool is_type_compatible_with(AstResolvedType *self, AstResolvedType *other, AstCompilerContext *context) { - return self->value.data == &context->compiler->default_types.str->lhs_expr && - other->value.data == context->compiler->default_types.c_char && is_c_pointer_compatible(&other->value.lhs_expr->type); +static bool is_arg_str_and_param_c_str(AstResolvedType *arg_type, VariableType *param_type, AstCompilerContext *context) { + return arg_type->value.data == &context->compiler->default_types.str->lhs_expr && + param_type->type == VARIABLE_TYPE_VARIABLE && + param_type->value.variable->resolved_var.value.data == context->compiler->default_types.c_char && + is_c_pointer_compatible(param_type); } static bool resolve_data_type_equals(AstResolvedType *self, AstResolvedType *other) { - return self->value.data == other->value.data; + if(self->type != other->type) + return bool_false; + + switch(self->type) { + case RESOLVED_TYPE_NONE: + case RESOLVED_TYPE_LHS_EXPR: + return self->value.data == other->value.data; + case RESOLVED_TYPE_FUNC_SIG: + return function_signature_equals(self->value.func_sig, other->value.func_sig); + } + assert(bool_false); } -static bool function_parameter_is_vararg(FunctionParameter *self, AstCompilerContext *context) { +static bool function_parameter_is_c_vararg(FunctionParameter *self, AstCompilerContext *context) { amal_default_type *vararg_type = context->compiler->default_types.c_varargs; return self->resolve_data.type.value.data == &vararg_type->lhs_expr; } static bool is_function_arg_compatible_with_parameter(AstResolvedType *arg, FunctionParameter *param, AstCompilerContext *context) { return resolve_data_type_equals(arg, ¶m->resolve_data.type) || - is_type_compatible_with(arg, ¶m->resolve_data.type, context) || - function_parameter_is_vararg(param, context); + is_arg_str_and_param_c_str(arg, ¶m->type, context) || + function_parameter_is_c_vararg(param, context); } /* Pointers, isize and usize are returned with size 4, as that is the smallest possible size for them */ @@ -814,7 +835,7 @@ static void funccall_resolve_signature_types(FunctionCall *func_call, FunctionSi if(num_missing_args > 0) { FunctionParameter *vararg_param = buffer_begin(&func_sig->parameters); - bool has_vararg = num_params > 0 && function_parameter_is_vararg(&vararg_param[num_params - 1], context); + bool has_vararg = num_params > 0 && function_parameter_is_c_vararg(&vararg_param[num_params - 1], context); if (has_vararg) num_missing_args -= 1; if(num_missing_args > 0) { @@ -845,10 +866,14 @@ static void funccall_resolve(Ast *self, AstCompilerContext *context) { { func_sig = self->resolve_data.type.value.func_sig; - FunctionReturnType *return_type = buffer_begin(&func_sig->return_types); - assert(buffer_get_size(&func_sig->return_types, FunctionReturnType) == 1); self->resolve_data.type.type = RESOLVED_TYPE_LHS_EXPR; - self->resolve_data.type = return_type->resolved_type; + if(func_sig->return_types.size > 0) { + FunctionReturnType *return_type = buffer_begin(&func_sig->return_types); + self->resolve_data.type = return_type->resolved_type; + } else { + self->resolve_data.type.type = RESOLVED_TYPE_LHS_EXPR; + self->resolve_data.type.value.lhs_expr = &context->compiler->default_types.void_type->lhs_expr; + } } ast = buffer_begin(&func_call->args); @@ -918,12 +943,11 @@ static bool is_struct_decl(Ast *self) { return resolved_type->rhs_expr && resolved_type->rhs_expr->type == AST_STRUCT_DECL; } -static void binop_resolve_dot_access(Ast *ast, AstCompilerContext *context) { +static void binop_resolve_dot_access(Ast *ast, AstCompilerContext *context, ScopeNamedObject *rhs_resolved_var) { Binop *self; Scope *lhs_scope; BufferView caller_code_ref; BufferView callee_code_ref; - ScopeNamedObject rhs_resolved_var; assert(ast->type == AST_BINOP); self = ast->value.binop; @@ -935,8 +959,8 @@ static void binop_resolve_dot_access(Ast *ast, AstCompilerContext *context) { } lhs_scope = ast_resolved_type_get_scope(&self->lhs->resolve_data.type); - scope_get_resolved_variable(lhs_scope, context, self->rhs->value.variable->name, &rhs_resolved_var); - self->rhs->resolve_data.type = scope_named_object_get_resolved_type(&rhs_resolved_var, context); + scope_get_resolved_variable(lhs_scope, context, self->rhs->value.variable->name, rhs_resolved_var); + self->rhs->resolve_data.type = scope_named_object_get_resolved_type(rhs_resolved_var, context); caller_code_ref = ast_get_code_reference(self->rhs); callee_code_ref = ast_resolved_type_get_name(&self->rhs->resolve_data.type); @@ -982,13 +1006,15 @@ static void binop_resolve(Ast *ast, AstCompilerContext *context) { self = ast->value.binop; ast_resolve(self->lhs, context); if(self->type == BINOP_DOT && (self->rhs->type == AST_VARIABLE || self->rhs->type == AST_FUNCTION_CALL)) { - binop_resolve_dot_access(ast, context); + ScopeNamedObject rhs_resolved_var; + binop_resolve_dot_access(ast, context, &rhs_resolved_var); /* Only function call has extra data that needs to be resolved (args) */ if(self->rhs->type == AST_FUNCTION_CALL) { - Scope *prev_scope = context->scope; - context->scope = ast_resolved_type_get_scope(&self->lhs->resolve_data.type); + /*Scope *prev_scope = context->scope;*/ + /*context->scope = ast_resolved_type_get_scope(&self->lhs->resolve_data.type);*/ + self->rhs->value.func_call->func.resolved_var = rhs_resolved_var; ast_resolve(self->rhs, context); - context->scope = prev_scope; + /*context->scope = prev_scope;*/ } self->rhs->resolve_data.status = AST_RESOLVED; ast->resolve_data.type = self->rhs->resolve_data.type; @@ -1206,6 +1232,11 @@ void ast_resolve(Ast *self, AstCompilerContext *context) { case AST_NUMBER: number_resolve(self, context); break; + case AST_BOOL: { + self->resolve_data.type.type = RESOLVED_TYPE_LHS_EXPR; + self->resolve_data.type.value.lhs_expr = &context->compiler->default_types.bool->lhs_expr; + break; + } case AST_FUNCTION_DECL: funcdecl_resolve(self, context); break; diff --git a/src/bytecode/bytecode.c b/src/bytecode/bytecode.c index af9251b..add351f 100644 --- a/src/bytecode/bytecode.c +++ b/src/bytecode/bytecode.c @@ -177,15 +177,15 @@ static void add_functions(BytecodeCompilerContext *self) { |Function[]|Functions |Multiple non-extern functions, where the number of functions is defined by @num_funcs.| # Function - |Type|Field |Description | - |----|-------------------------|------------------------------------------------------------------------------------------------------------------------| - |u32 |func_offset |The offset in the program code (machine code) where the function starts. Is always 0 until the program has been started.| - |u8 |num_params |The number of parameters. | - |u32 |params_num_pointers |The number of pointers in the parameters. | - |u32 |params_fixed_size |The size of all non-pointer type parameters, in bytes. | - |u8 |num_return_types |The number of return values. | - |u32 |return_types_num_pointers|The number of pointers in the return types. | - |u32 |return_types_fixed_size |The size of all non-pointer type return types, in bytes. | + |Type|Field |Description | + |----|-------------------------|-------------------------------------------------------------------------------------------------------------------------| + |u32 |func_offset |The offset in the program code (machine code) where the function starts. Is always ~0 until the program has been started.| + |u8 |num_params |The number of parameters. | + |u32 |params_num_pointers |The number of pointers in the parameters. | + |u32 |params_fixed_size |The size of all non-pointer type parameters, in bytes. | + |u8 |num_return_types |The number of return values. | + |u32 |return_types_num_pointers|The number of pointers in the return types. | + |u32 |return_types_fixed_size |The size of all non-pointer type return types, in bytes. | */ Ir *ir = self->parser->ir; @@ -204,7 +204,7 @@ static void add_functions(BytecodeCompilerContext *self) { TypeSize params_total_size = function_signature_get_params_size(func->func_sig); TypeSize return_types_total_size = function_signature_get_return_types_size(func->func_sig); - header_func.func_offset = 0; + header_func.func_offset = ~(u32)0UL; header_func.num_params = buffer_get_size(&func->func_sig->parameters, FunctionParameter); header_func.params_num_pointers = params_total_size.num_pointers; @@ -301,12 +301,12 @@ static void add_export_functions(BytecodeCompilerContext *self) { |Exported function[]|Exported functions|Multiple exported functions, where the number of functions is defined by @num_export_func| # Exported function - |Type|Field |Description | - |----|------------------|--------------------------------------------------------------------------------------------------------------------------| - |u32 |instruction_offset|The offset in the instruction data where the exported function is defined. Is always 0 until the program has been started.| - |u8 |num_args |The number of arguments the functions has. | - |u8 |name_len |The length of the exported function name, in bytes. Excluding the null-terminate character. | - |u8[]|name |The name of the exported function, where the size is defined by @name_len. Names are null-terminated. | + |Type|Field |Description | + |----|------------------|---------------------------------------------------------------------------------------------------------------------------| + |u32 |instruction_offset|The offset in the instruction data where the exported function is defined. Is always ~0 until the program has been started.| + |u8 |num_args |The number of arguments the functions has. | + |u8 |name_len |The length of the exported function name, in bytes. Excluding the null-terminate character. | + |u8[]|name |The name of the exported function, where the size is defined by @name_len. Names are null-terminated. | */ Ir *ir = self->parser->ir; Buffer *instructions = &self->bytecode->data; @@ -324,7 +324,7 @@ static void add_export_functions(BytecodeCompilerContext *self) { throw_if_error(buffer_append(instructions, &export_funcs_size, sizeof(u32))); for(; export_func != export_func_end; ++export_func) { const char null_s = '\0'; - const u32 instruction_offset = 0; + const u32 instruction_offset = ~(u32)0UL; u8 num_args = buffer_get_size(&export_func->func_sig->parameters, FunctionParameter); throw_if_error(buffer_append(instructions, &instruction_offset, sizeof(instruction_offset))); throw_if_error(buffer_append(instructions, &num_args, sizeof(num_args))); @@ -472,6 +472,11 @@ static void add_instructions(BytecodeCompilerContext *self) { u32 num_instructions_index = self->bytecode->data.size; throw_if_error(buffer_append_empty(&self->bytecode->data, sizeof(num_instructions_index))); + /* + TODO: Limit registers from u16 to u7. Right now they are downcasted and will cause bugs + if there are too many registers used in the program. + */ + while(instruction != instructions_end) { IrInstruction ins = (IrInstruction)*instruction++; switch(ins) { @@ -490,6 +495,11 @@ static void add_instructions(BytecodeCompilerContext *self) { add_ins3(self, AMAL_OP_MOV, ir_ins_form1.lhs, ir_ins_form1.rhs, "mov r%d, r%d"); break; } + case IR_ASSIGN_FUNC: { + instruction += ir_extract_data(instruction, &ir_ins_form1, sizeof(ir_ins_form1)); + add_ins6(self, AMAL_OP_LOADF, ir_ins_form1.lhs, ir_ins_form1.rhs, "loadf r%d, f%d"); + break; + } case IR_ADD: { instruction += ir_extract_data(instruction, &ir_ins_form2, sizeof(ir_ins_form2)); add_ins5(self, AMAL_OP_ADD, ir_ins_form2.result, ir_ins_form2.lhs, ir_ins_form2.rhs, "add r%d, r%d, r%d"); @@ -614,6 +624,12 @@ static void add_instructions(BytecodeCompilerContext *self) { add_ins6(self, AMAL_OP_CALLE, ir_ins_func_call_extern.import_index, ir_ins_func_call_extern.func_decl_lhs->extern_index, "calle ef(%d,%d)"); break; } + case IR_CALLR: { + IrRegister reg; + instruction += ir_extract_data(instruction, ®, sizeof(reg)); + add_ins2(self, AMAL_OP_CALLR, reg, "callr r%d"); + break; + } case IR_JUMP_ZERO: { instruction += ir_extract_data(instruction, &ir_ins_jump_zero, sizeof(ir_ins_jump_zero)); add_ins6(self, AMAL_OP_JZ, ir_ins_jump_zero.condition_reg, ir_ins_jump_zero.target_label, "jz r%d, l%d"); diff --git a/src/compiler.c b/src/compiler.c index 48ba71e..f9d9355 100644 --- a/src/compiler.c +++ b/src/compiler.c @@ -59,6 +59,7 @@ static CHECK_RESULT int create_default_type_fixed_size(amal_compiler *compiler, static CHECK_RESULT int init_default_types(amal_compiler *compiler) { /* Plain old datatype */ + return_if_error(create_default_type_fixed_size(compiler, "void", 0, &compiler->default_types.void_type, bool_false)); return_if_error(create_default_type_fixed_size(compiler, "i8", 1, &compiler->default_types.i8, bool_true)); return_if_error(create_default_type_fixed_size(compiler, "i16", 2, &compiler->default_types.i16, bool_true)); return_if_error(create_default_type_fixed_size(compiler, "i32", 4, &compiler->default_types.i32, bool_true)); @@ -266,8 +267,10 @@ static CHECK_RESULT int thread_generate_ir(Parser *parser) { amal_log_debug("Generating IR for file: %.*s", parser->tokenizer.code_name.size, parser->tokenizer.code_name.data); result = setjmp(compiler_context.env); - if(result == 0) - scope_generate_ir(&parser->struct_decl.body, &compiler_context); + if(result == 0) { + scope_generate_function_ids(&parser->struct_decl.body, &compiler_context); + scope_generate_functions_ir(&parser->struct_decl.body, &compiler_context); + } return result; } diff --git a/src/ir/ir.c b/src/ir/ir.c index 62d3516..1ca154a 100644 --- a/src/ir/ir.c +++ b/src/ir/ir.c @@ -294,34 +294,44 @@ static CHECK_RESULT int ir_ins_assign_reg(Ir *self, IrRegister dest, IrRegister return ir_add_ins_form1(self, IR_ASSIGN_REG, dest, src); } +static CHECK_RESULT int ir_ins_assign_func(Ir *self, IrRegister dest, IrFuncIndex func_index) { + amal_log_debug("r%d = f%d", dest, func_index); + return ir_add_ins_form1(self, IR_ASSIGN_FUNC, dest, func_index); +} + static CHECK_RESULT int ir_ins_binop(Ir *self, IrInstruction binop_type, IrRegister lhs, IrRegister rhs, IrRegister *result) { assert(binop_type >= IR_ADD && binop_type <= IR_GE); return ir_add_ins_form2(self, binop_type, lhs, rhs, result); } -static CHECK_RESULT int ir_ins_func_start(Ir *self, u8 func_flags, FunctionSignature *func_sig, IrFuncIndex *result, usize *func_metadata_index) { +static CHECK_RESULT int ir_ins_func_start(Ir *self, u8 func_flags, FunctionSignature *func_sig, usize *func_metadata_index) { const u8 ins_type = IR_FUNC_START; IrInsFuncStart ins_func_start; + IrFunc func; - /* Overflow */ - if(self->func_counter + 1 <= self->func_counter) { - amal_log_error("Ir too many closures!"); - return -1; - } + func.func_sig = func_sig; + return_if_error(buffer_append(&self->funcs, &func, sizeof(func))); - *result = self->func_counter++; - { - IrFunc func; - func.func_sig = func_sig; - return_if_error(buffer_append(&self->funcs, &func, sizeof(func))); - } ins_func_start.flags = func_flags; /* Dont set number of local registers yet. That will be set by @func_metadata_index later when it's known */ /*ins_func_start.num_local_vars_regs = ---*/ return_if_error(buffer_append(&self->instructions, &ins_type, 1)); return_if_error(buffer_append(&self->instructions, &ins_func_start, sizeof(ins_func_start))); *func_metadata_index = self->instructions.size - sizeof(ins_func_start.num_local_vars_regs); - amal_log_debug("FUNC_START f%u(%d) %d", *result, buffer_get_size(&func_sig->parameters, FunctionParameter), buffer_get_size(&func_sig->return_types, FunctionReturnType)); + amal_log_debug("FUNC_START f%d(%d) %d", + func_sig->func_decl ? func_sig->func_decl->ir_func_index : -1, + buffer_get_size(&func_sig->parameters, FunctionParameter), + buffer_get_size(&func_sig->return_types, FunctionReturnType)); + return 0; +} + +static CHECK_RESULT int ir_inc_func_index(Ir *self, IrFuncIndex *result) { + /* Overflow */ + if(self->func_counter + 1 <= self->func_counter) { + amal_log_error("Ir too many closures!"); + return -1; + } + *result = self->func_counter++; return 0; } @@ -373,6 +383,13 @@ static CHECK_RESULT int ir_ins_call_extern(Ir *self, int import_index, LhsExpr * return buffer_append(&self->instructions, &ins_func_call_extern, sizeof(ins_func_call_extern)); } +static CHECK_RESULT int ir_ins_call_reg(Ir *self, IrRegister reg) { + const u8 ins_type = IR_CALLR; + amal_log_debug("CALLR r%d", reg); + return_if_error(buffer_append(&self->instructions, &ins_type, 1)); + return buffer_append(&self->instructions, ®, sizeof(reg)); +} + static CHECK_RESULT int ir_ins_jumpzero(Ir *self, IrRegister condition_reg, IrLabelIndex target_label, usize *instruction_offset) { const u8 ins_type = IR_JUMP_ZERO; IrInsJumpZero ins_jump_zero; @@ -466,23 +483,6 @@ static bool ast_resolved_type_is_decl(AstResolvedType *self) { return lhs_expr->rhs_expr->type == AST_FUNCTION_DECL || lhs_expr->rhs_expr->type == AST_STRUCT_DECL; } #endif -static bool lhs_expr_is_decl(LhsExpr *self) { - if(self->rhs_expr) { - return self->rhs_expr->type == AST_FUNCTION_DECL || self->rhs_expr->type == AST_STRUCT_DECL; - } else { - switch(self->type.type) { - case VARIABLE_TYPE_NONE: - assert(bool_false); - return 0; - case VARIABLE_TYPE_VARIABLE: - return bool_false; - case VARIABLE_TYPE_SIGNATURE: - /* TODO: This should return bool_false when it's possible to use signature in expressions */ - return bool_true; - } - return 0; - } -} static CHECK_RESULT IrRegister number_generate_ir(Number *self, IrCompilerContext *context) { IrRegister reg; @@ -501,6 +501,17 @@ static CHECK_RESULT IrRegister number_generate_ir(Number *self, IrCompilerContex return reg; } +static CHECK_RESULT IrRegister ast_bool_generate_ir(AstBool *self, IrCompilerContext *context) { + IrRegister reg; + IrNumber number; + number.type = IR_NUMBER_TYPE_INTEGER; + number.value.integer = self->value; + throw_if_error(ir_get_unique_reg(context->ir, ®)); + /* TODO: Maybe bool shouldn't be a regular number? */ + throw_if_error(ir_ins_assign_inter(context->ir, reg, number)); + return reg; +} + static CHECK_RESULT IrRegister lhsexpr_extern_generate_ir(LhsExpr *self, IrCompilerContext *context) { /* TODO: IrRegister should be extended to include static and extern data */ if(self->type.type == VARIABLE_TYPE_SIGNATURE) { @@ -534,6 +545,7 @@ static CHECK_RESULT IrRegister lhsexpr_extern_generate_ir(LhsExpr *self, IrCompi return 0; } +#if 0 static CHECK_RESULT IrRegister lhsexpr_export_generate_ir(LhsExpr *self, IrCompilerContext *context) { /* TODO: IrRegister should be extended to include static and export data */ if(self->rhs_expr->type == AST_FUNCTION_DECL) { @@ -543,6 +555,7 @@ static CHECK_RESULT IrRegister lhsexpr_export_generate_ir(LhsExpr *self, IrCompi } return 0; } +#endif static CHECK_RESULT IrRegister lhsexpr_generate_ir(LhsExpr *self, AstResolveData *resolve_data, IrCompilerContext *context) { IrRegister reg; @@ -552,19 +565,17 @@ static CHECK_RESULT IrRegister lhsexpr_generate_ir(LhsExpr *self, AstResolveData if(self->rhs_expr) { Ast *rhs_expr = self->rhs_expr; - IrRegister rhs_reg; - rhs_reg = ast_generate_ir(rhs_expr, context); + IrRegister rhs_reg = ast_generate_ir(rhs_expr, context); +#if 0 if(LHS_EXPR_IS_EXPORT(self)) return lhsexpr_export_generate_ir(self, context); - +#endif /* - Declarations (struct and function declaration) resolves to itself and in that case this expression - is just a compile-time name for the declaration. Import expression also has no meaning in IR until it's used. TODO: Shouldn't lhsexpr that have struct/function declaration as rhs be different ast expression types? */ - if(lhs_expr_is_decl(self) || rhs_expr->type == AST_IMPORT) { + if(rhs_expr->type == AST_IMPORT) { /*assert(bool_false);*/ return 0; } @@ -620,12 +631,7 @@ static CHECK_RESULT void function_signature_generate_params_ir(FunctionSignature } } -/* -TODO: Each function declaration should be in separate IR instances so ast can be converted into ir -in any order. -*/ static CHECK_RESULT IrRegister funcdecl_generate_ir(FunctionDecl *self, IrCompilerContext *context) { - /* TODO: Implement */ /* Reset reg counter in each function, because each function has a separate register context that is reset after function end @@ -636,10 +642,7 @@ static CHECK_RESULT IrRegister funcdecl_generate_ir(FunctionDecl *self, IrCompil context->ir->param_counter = 0; context->ir->label_counter = 0; - /* - Parameters need to have generated ir so the first ir registers belong to the function. - This way we can know if a register access is for a parameter or not by checking the number - */ + /* All parameters need to be generated, so that the parameter matches its index... */ function_signature_generate_params_ir(self->signature, context); amal_log_debug("IR funcdecl %p", self); @@ -649,7 +652,7 @@ static CHECK_RESULT IrRegister funcdecl_generate_ir(FunctionDecl *self, IrCompil if(LHS_EXPR_IS_EXPORT(self->lhs_expr)) func_flags |= FUNC_FLAG_EXPORTED; } - throw_if_error(ir_ins_func_start(context->ir, func_flags, self->signature, &self->ir_func_index, &func_metadata_index)); + throw_if_error(ir_ins_func_start(context->ir, func_flags, self->signature, &func_metadata_index)); scope_generate_ir(&self->body, context); throw_if_error(ir_ins_func_end(context->ir)); @@ -658,27 +661,57 @@ static CHECK_RESULT IrRegister funcdecl_generate_ir(FunctionDecl *self, IrCompil return 0; } +static CHECK_RESULT IrRegister funcdecl_ref_generate_ir(FunctionDecl *self, IrCompilerContext *context) { + IrRegister reg; + if(self->lhs_expr && LHS_EXPR_IS_EXTERN(self->lhs_expr)) { + assert(bool_false && "TODO: Implement assign func for extern closures"); + throw(-1); + } + throw_if_error(ir_get_unique_reg(context->ir, ®)); + throw_if_error(ir_ins_assign_func(context->ir, reg, self->ir_func_index)); + return reg; +} + + static CHECK_RESULT IrRegister funccall_generate_ir(FunctionCall *self, IrCompilerContext *context) { IrRegister reg; FunctionSignature *func_sig; FunctionDecl *func_decl; LhsExpr *func_lhs_expr; + FunctionParameter *func_param_expr; int import_index = context->import_index; + + func_lhs_expr = NULL; + func_param_expr = NULL; context->import_index = 0; throw_if_error(ir_get_unique_reg(context->ir, ®)); - assert(self->func.resolved_var.type == NAMED_OBJECT_LHS_EXPR); - func_lhs_expr = self->func.resolved_var.value.lhs_expr; - if(func_lhs_expr->type.type == VARIABLE_TYPE_SIGNATURE) { - func_sig = func_lhs_expr->type.value.signature; - } else if(func_lhs_expr->type.type == VARIABLE_TYPE_VARIABLE) { - AstResolveData *resolve_data = func_lhs_expr->type.value.variable->resolved_var.resolve_data; - assert(resolve_data->type.type == RESOLVED_TYPE_FUNC_SIG); - func_sig = resolve_data->type.value.func_sig; - } else { - assert(func_lhs_expr->rhs_expr && func_lhs_expr->rhs_expr->resolve_data.type.type == RESOLVED_TYPE_FUNC_SIG); - func_sig = func_lhs_expr->rhs_expr->resolve_data.type.value.func_sig; + switch(self->func.resolved_var.type) { + case NAMED_OBJECT_NONE: + assert(bool_false); + break; + case NAMED_OBJECT_LHS_EXPR: { + func_lhs_expr = self->func.resolved_var.value.lhs_expr; + if(func_lhs_expr->type.type == VARIABLE_TYPE_SIGNATURE) { + func_sig = func_lhs_expr->type.value.signature; + } else if(func_lhs_expr->type.type == VARIABLE_TYPE_VARIABLE) { + AstResolveData *resolve_data = func_lhs_expr->type.value.variable->resolved_var.resolve_data; + assert(resolve_data->type.type == RESOLVED_TYPE_FUNC_SIG); + func_sig = resolve_data->type.value.func_sig; + } else { + assert(func_lhs_expr->rhs_expr && func_lhs_expr->rhs_expr->resolve_data.type.type == RESOLVED_TYPE_FUNC_SIG); + func_sig = func_lhs_expr->rhs_expr->resolve_data.type.value.func_sig; + } + break; + } + case NAMED_OBJECT_FUNC_PARAM: { + func_param_expr = self->func.resolved_var.value.func_param; + assert(func_param_expr->type.type == VARIABLE_TYPE_SIGNATURE); + func_sig = func_param_expr->type.value.signature; + break; + } } + func_decl = func_sig->func_decl; /* Push return arguments */ @@ -719,15 +752,16 @@ static CHECK_RESULT IrRegister funccall_generate_ir(FunctionCall *self, IrCompil if(func_lhs_expr && LHS_EXPR_IS_EXTERN(func_lhs_expr)) { throw_if_error(ir_ins_call_extern(context->ir, import_index, func_lhs_expr)); - } else { - assert(func_decl); - /* rhs wont be null here because only extern variable can't have rhs */ + } else if(func_decl) { throw_if_error(ir_ins_call(context->ir, import_index, func_decl)); + } else if(func_param_expr) { + throw_if_error(ir_ins_call_reg(context->ir, function_parameter_generate_ir(func_param_expr, context))); } return reg; } +#if 0 static CHECK_RESULT IrRegister structdecl_generate_ir(StructDecl *self, IrCompilerContext *context) { /* TODO: Implement */ /*assert(bool_false);*/ @@ -742,6 +776,7 @@ static CHECK_RESULT IrRegister structfield_generate_ir(StructField *self, IrComp (void)context; return 0; } +#endif static CHECK_RESULT IrRegister string_generate_ir(String *self, IrCompilerContext *context) { IrRegister reg; @@ -895,24 +930,29 @@ static void return_expr_generate_ir(ReturnExpr *self, IrCompilerContext *context } static CHECK_RESULT IrRegister ast_generate_ir_resolve_data(void *ast_data, AstType ast_type, AstResolveData *resolve_data, IrCompilerContext *context) { - if(resolve_data->status == AST_IR_RESOLVED) - return resolve_data->ir_reg; + /*if(resolve_data->status == AST_IR_RESOLVED) + return resolve_data->ir_reg;*/ switch(ast_type) { case AST_NUMBER: resolve_data->ir_reg = number_generate_ir(ast_data, context); break; + case AST_BOOL: + resolve_data->ir_reg = ast_bool_generate_ir(ast_data, context); + break; case AST_FUNCTION_DECL: - resolve_data->ir_reg = funcdecl_generate_ir(ast_data, context); + /* The IR for function declarations is done separately, in @scope_generate_functions_ir */ + resolve_data->ir_reg = funcdecl_ref_generate_ir(ast_data, context); break; case AST_FUNCTION_CALL: resolve_data->ir_reg = funccall_generate_ir(ast_data, context); break; case AST_STRUCT_DECL: - resolve_data->ir_reg = structdecl_generate_ir(ast_data, context); + resolve_data->ir_reg = 0;/*structdecl_generate_ir(ast_data, context);*/ break; case AST_STRUCT_FIELD: - resolve_data->ir_reg = structfield_generate_ir(ast_data, context); + assert(bool_false); + resolve_data->ir_reg = 0;/*structfield_generate_ir(ast_data, context);*/ break; case AST_LHS: resolve_data->ir_reg = lhsexpr_generate_ir(ast_data, resolve_data, context); @@ -941,7 +981,6 @@ static CHECK_RESULT IrRegister ast_generate_ir_resolve_data(void *ast_data, AstT break; case AST_RETURN: return_expr_generate_ir(ast_data, context); - resolve_data->ir_reg = 0; break; } @@ -950,13 +989,13 @@ static CHECK_RESULT IrRegister ast_generate_ir_resolve_data(void *ast_data, AstT } CHECK_RESULT IrRegister ast_generate_ir(Ast *self, IrCompilerContext *context) { +#ifdef DEBUG assert(self); - #ifdef DEBUG if(self->resolve_data.status != AST_RESOLVED && self->resolve_data.status != AST_IR_RESOLVED) { amal_log_error("Ast type not resolved: %d", self->type); assert(bool_false); } - #endif +#endif return ast_generate_ir_resolve_data(self->value.data, self->type, &self->resolve_data, context); } @@ -980,3 +1019,42 @@ void scope_generate_ir(Scope *self, IrCompilerContext *context) { ignore_result_int(ast_generate_ir(*ast, context)); } } + +void scope_generate_function_ids(Scope *self, IrCompilerContext *context) { + Ast **ast = buffer_begin(&self->ast_objects); + Ast **ast_end = buffer_end(&self->ast_objects); + for(; ast != ast_end; ++ast) { + if((*ast)->type == AST_LHS && (*ast)->value.lhs_expr->rhs_expr->type == AST_FUNCTION_DECL) { + LhsExpr *lhs_expr = (*ast)->value.lhs_expr; + FunctionDecl *func_decl = lhs_expr->rhs_expr->value.func_decl; + /* + Going depth first will optimize scope private closures, so they are declared + before the function they are defined in. This means calling them wont create a deferred function call + in program.c + */ + scope_generate_functions_ir(&func_decl->body, context); + /* TODO: Should this not be done for extern closures? */ + throw_if_error(ir_inc_func_index(context->ir, &func_decl->ir_func_index)); + } + } +} + +void scope_generate_functions_ir(Scope *self, IrCompilerContext *context) { + Ast **ast = buffer_begin(&self->ast_objects); + Ast **ast_end = buffer_end(&self->ast_objects); + for(; ast != ast_end; ++ast) { + if((*ast)->type == AST_LHS && (*ast)->value.lhs_expr->rhs_expr->type == AST_FUNCTION_DECL) { + LhsExpr *lhs_expr = (*ast)->value.lhs_expr; + FunctionDecl *func_decl = lhs_expr->rhs_expr->value.func_decl; + /* + Going depth first will optimize scope private closures, so they are declared + before the function they are defined in. This means calling them wont create a deferred function call + in program.c + */ + scope_generate_functions_ir(&func_decl->body, context); + ignore_result_int(funcdecl_generate_ir(func_decl, context)); + if(LHS_EXPR_IS_EXPORT(lhs_expr)) + throw_if_error(ir_try_add_export_func(context->ir, func_decl->signature, lhs_expr->var_name)); + } + } +} diff --git a/src/parser.c b/src/parser.c index fb21b19..204e391 100644 --- a/src/parser.c +++ b/src/parser.c @@ -54,10 +54,6 @@ int parser_init(Parser *self, amal_compiler *compiler, ArenaAllocator *allocator return PARSER_OK; } -static bool parser_is_current_scope_file_scope(Parser *self) { - return self->current_scope == &self->struct_decl.body; -} - /* BODY_LOOP = BODY* @end_token */ @@ -410,7 +406,6 @@ static CHECK_RESULT LhsExpr* parser_parse_declaration_lhs(Parser *self) { } /* - CLOSURE = FUNC_SIGNATURE '{' BODY_LOOP '}' */ static CHECK_RESULT FunctionDecl* parser_parse_closure(Parser *self) { @@ -422,12 +417,6 @@ static CHECK_RESULT FunctionDecl* parser_parse_closure(Parser *self) { if(!signature) return NULL; - /* - TODO: Implement function declaration inside other functions. - Such functions should be moved to the file scope in the bytecode generation - */ - assert(parser_is_current_scope_file_scope(self) && "TODO: Implement function declaration inside other functions."); - throw_if_error(arena_allocator_alloc(self->allocator, sizeof(FunctionDecl), (void**)&result)); throw_if_error(funcdecl_init(result, signature, self->current_scope, self->allocator)); signature->func_decl = result; @@ -652,15 +641,17 @@ static CHECK_RESULT WhileStatement* parser_parse_while_statement(Parser *self) { return result; } +/* +NUMBER = TOK_NUMBER +*/ static CHECK_RESULT Ast* parser_parse_number(Parser *self) { Ast *result; bool match; Number *number; - result = NULL; throw_if_error(tokenizer_consume_if(&self->tokenizer, TOK_NUMBER, &match)); if(!match) - return result; + return NULL; throw_if_error(arena_allocator_alloc(self->allocator, sizeof(Number), (void**)&number)); number_init(number, &self->tokenizer.number, self->tokenizer.value.identifier); @@ -669,10 +660,29 @@ static CHECK_RESULT Ast* parser_parse_number(Parser *self) { } /* -RHS_S = STRING | NUMBER | FUNC_CALL_OR_VARIABLE +BOOL = TOK_BOOL +*/ +static CHECK_RESULT Ast* parser_parse_bool(Parser *self) { + Ast *result; + bool match; + AstBool *ast_bool; + + throw_if_error(tokenizer_consume_if(&self->tokenizer, TOK_BOOL, &match)); + if(!match) + return NULL; + + throw_if_error(arena_allocator_alloc(self->allocator, sizeof(AstBool), (void**)&ast_bool)); + ast_bool_init(ast_bool, self->tokenizer.bool_value, self->tokenizer.value.identifier); + throw_if_error(ast_create(self->allocator, ast_bool, AST_BOOL, &result)); + return result; +} + +/* +RHS_S = STRING | NUMBER | BOOL | CLOSURE | FUNC_CALL_OR_VARIABLE */ static CHECK_RESULT Ast* parser_parse_rhs_single_expr(Parser *self) { Ast *result; + FunctionDecl *func_decl; bool match; result = NULL; @@ -689,6 +699,16 @@ static CHECK_RESULT Ast* parser_parse_rhs_single_expr(Parser *self) { if(result) return result; + result = parser_parse_bool(self); + if(result) + return result; + + func_decl = parser_parse_closure(self); + if(func_decl) { + throw_if_error(ast_create(self->allocator, func_decl, AST_FUNCTION_DECL, &result)); + return result; + } + result = parser_parse_function_call_or_variable(self); if(result) return result; diff --git a/src/program.c b/src/program.c index 6c5ac7b..31485ca 100644 --- a/src/program.c +++ b/src/program.c @@ -605,7 +605,7 @@ static CHECK_RESULT int amal_program_read_instructions(amal_program *self, amal_ self->return_value_index = 0; /* func_offset will only be non-zero when the function has been decoded (FUNC_START) */ - if(func_def.func_offset != 0) { + if(func_def.func_offset != ~(u32)0UL) { /* TODO: Instead of pushing num args, push the sum of sizeof the last num_args */ return_if_error(amal_exec_call(executor, func_def.func_offset, dst_reg)); } else { @@ -633,7 +633,12 @@ static CHECK_RESULT int amal_program_read_instructions(amal_program *self, amal_ break; } case AMAL_OP_CALLR: { - assert(bool_false && "TODO: Implement CALLR"); + AmalReg dst_reg; + AmalReg func_ptr_reg = self->data.data[self->read_index]; + assert(self->return_value_index == 1); + dst_reg = self->return_values_stack[0]; + self->return_value_index = 0; + return_if_error(amal_exec_callr(executor, func_ptr_reg, dst_reg)); self->read_index += 1; break; } diff --git a/src/tokenizer.c b/src/tokenizer.c index c93add3..73dd83d 100644 --- a/src/tokenizer.c +++ b/src/tokenizer.c @@ -203,6 +203,10 @@ static CHECK_RESULT int __tokenizer_next(Tokenizer *self, Token *token) { if(am_memeql(self->value.identifier.data, "else", 4)) { *token = TOK_ELSE; return TOKENIZER_OK; + } else if(am_memeql(self->value.identifier.data, "true", 4)) { + *token = TOK_BOOL; + self->bool_value = bool_true; + return TOKENIZER_OK; } break; } @@ -213,6 +217,10 @@ static CHECK_RESULT int __tokenizer_next(Tokenizer *self, Token *token) { } else if(am_memeql(self->value.identifier.data, "while", 5)) { *token = TOK_WHILE; return TOKENIZER_OK; + } else if(am_memeql(self->value.identifier.data, "false", 5)) { + *token = TOK_BOOL; + self->bool_value = bool_false; + return TOKENIZER_OK; } break; } @@ -259,6 +267,8 @@ static CHECK_RESULT int __tokenizer_next(Tokenizer *self, Token *token) { return TOKENIZER_ERR; } + /* TODO: Check if the number fits in the result bits */ + if(dot_index == -1) { int result = string_to_integer_unchecked(number_str, &self->number.value.integer); if(result != 0) { @@ -542,6 +552,12 @@ static BufferView tokenizer_expected_token_as_string(Token token) { case TOK_STRING: str = "string"; break; + case TOK_NUMBER: + str = "number"; + break; + case TOK_BOOL: + str = "bool"; + break; case TOK_FN: str = "fn"; break; @@ -572,9 +588,6 @@ static BufferView tokenizer_expected_token_as_string(Token token) { case TOK_IMPORT: str = "import"; break; - case TOK_NUMBER: - str = "number"; - break; case TOK_BINOP: /* TODO: binop_to_string */ str = "binop"; -- cgit v1.2.3