aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/ast.c79
-rw-r--r--src/bytecode/bytecode.c50
-rw-r--r--src/compiler.c7
-rw-r--r--src/ir/ir.c214
-rw-r--r--src/parser.c48
-rw-r--r--src/program.c9
-rw-r--r--src/tokenizer.c19
7 files changed, 296 insertions, 130 deletions
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, &param->resolve_data.type) ||
- is_type_compatible_with(arg, &param->resolve_data.type, context) ||
- function_parameter_is_vararg(param, context);
+ is_arg_str_and_param_c_str(arg, &param->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, &reg, 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, &reg, 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, &reg));
+ /* 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, &reg));
+ 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, &reg));
- 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";