aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/ast.c19
-rw-r--r--src/bytecode/bytecode.c13
-rw-r--r--src/parser.c11
-rw-r--r--src/program.c29
-rw-r--r--src/ssa/ssa.c31
-rw-r--r--src/tokenizer.c11
6 files changed, 81 insertions, 33 deletions
diff --git a/src/ast.c b/src/ast.c
index 90af981..5336e1e 100644
--- a/src/ast.c
+++ b/src/ast.c
@@ -733,8 +733,17 @@ static usize min(usize a, usize b) {
return a < b ? a : b;
}
+static bool is_c_pointer_compatible(VariableType *self) {
+ return self->variable_type_flags & (VARIABLE_TYPE_FLAG_OPTIONAL | 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 resolve_data_type_equals(AstResolvedType *self, AstResolvedType *other) {
- return self->type == other->type && self->value.data == other->value.data;
+ return self->value.data == other->value.data;
}
static bool function_parameter_is_vararg(FunctionParameter *self, AstCompilerContext *context) {
@@ -742,6 +751,12 @@ static bool function_parameter_is_vararg(FunctionParameter *self, AstCompilerCon
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);
+}
+
static void verify_func_call_matches_func_signature(FunctionCall *func_call, FunctionSignature *func_sig, AstCompilerContext *context) {
Ast **arg = buffer_begin(&func_call->args);
Ast **arg_end = buffer_end(&func_call->args);
@@ -755,7 +770,7 @@ static void verify_func_call_matches_func_signature(FunctionCall *func_call, Fun
usize num_check = min(num_args, num_params);
usize i = 0;
for(; i < num_check; ++i) {
- if(!resolve_data_type_equals(&(*arg)->resolve_data.type, &func_param->resolve_data.type) && !function_parameter_is_vararg(func_param, context)) {
+ if(!is_function_arg_compatible_with_parameter(&(*arg)->resolve_data.type, func_param, context)) {
BufferView arg_name = ast_resolved_type_get_name(&(*arg)->resolve_data.type);
BufferView param_name = ast_resolved_type_get_name(&func_param->resolve_data.type);
compiler_print_error(context->compiler, func_call->func.name.data,
diff --git a/src/bytecode/bytecode.c b/src/bytecode/bytecode.c
index a5e3abc..b947985 100644
--- a/src/bytecode/bytecode.c
+++ b/src/bytecode/bytecode.c
@@ -387,7 +387,7 @@ static void add_ins1(BytecodeCompilerContext *self, AmalOpcode opcode, const cha
}
}
-static void add_ins2(BytecodeCompilerContext *self, AmalOpcode opcode, i8 reg, const char *fmt) {
+static void add_ins2(BytecodeCompilerContext *self, AmalOpcode opcode, AmalReg reg, const char *fmt) {
Buffer *instructions = &self->bytecode->data;
size_t index = instructions->size;
@@ -398,7 +398,7 @@ static void add_ins2(BytecodeCompilerContext *self, AmalOpcode opcode, i8 reg, c
fputc('\n', stderr);
}
-static void add_ins3(BytecodeCompilerContext *self, AmalOpcode opcode, i8 dst_reg, i8 src_reg, const char *fmt) {
+static void add_ins3(BytecodeCompilerContext *self, AmalOpcode opcode, AmalReg dst_reg, AmalReg src_reg, const char *fmt) {
Buffer *instructions = &self->bytecode->data;
size_t index = instructions->size;
@@ -421,7 +421,7 @@ static void add_ins4(BytecodeCompilerContext *self, AmalOpcode opcode, u16 data,
fputc('\n', stderr);
}
-static void add_ins5(BytecodeCompilerContext *self, AmalOpcode opcode, i8 dst_reg, i8 reg1, i8 reg2, const char *fmt) {
+static void add_ins5(BytecodeCompilerContext *self, AmalOpcode opcode, AmalReg dst_reg, AmalReg reg1, AmalReg reg2, const char *fmt) {
Buffer *instructions = &self->bytecode->data;
size_t index = instructions->size;
@@ -434,7 +434,7 @@ static void add_ins5(BytecodeCompilerContext *self, AmalOpcode opcode, i8 dst_re
fputc('\n', stderr);
}
-static void add_ins6(BytecodeCompilerContext *self, AmalOpcode opcode, i8 dst_reg, u16 data, const char *fmt) {
+static void add_ins6(BytecodeCompilerContext *self, AmalOpcode opcode, AmalReg dst_reg, u16 data, const char *fmt) {
Buffer *instructions = &self->bytecode->data;
size_t index = instructions->size;
@@ -525,6 +525,11 @@ static void add_instructions(BytecodeCompilerContext *self) {
add_ins5(self, AMAL_OP_CMP, ssa_ins_form2.result, ssa_ins_form2.lhs, ssa_ins_form2.rhs, "cmp r%d, r%d, r%d");
break;
}
+ case SSA_AND: {
+ instruction += ssa_extract_data(instruction, &ssa_ins_form2, sizeof(ssa_ins_form2));
+ add_ins5(self, AMAL_OP_BIT_AND, ssa_ins_form2.result, ssa_ins_form2.lhs, ssa_ins_form2.rhs, "and r%d, r%d, r%d");
+ break;
+ }
case SSA_FUNC_START: {
instruction += ssa_extract_data(instruction, &ssa_ins_func_start, sizeof(ssa_ins_func_start));
add_ins6(self, AMAL_OP_FUNC_START, ssa_ins_func_start.flags, ssa_ins_func_start.num_local_vars_regs, "func_start 0x%02x, %u");
diff --git a/src/parser.c b/src/parser.c
index dc39a6a..be19a33 100644
--- a/src/parser.c
+++ b/src/parser.c
@@ -290,14 +290,9 @@ void parser_parse_var_type(Parser *self, VariableType *result) {
if(match)
result->variable_type_flags |= VARIABLE_TYPE_FLAG_OPTIONAL;
- throw_if_error(tokenizer_consume_if(&self->tokenizer, TOK_BINOP, &match));
- if(match) {
- if(self->tokenizer.value.binop_type != BINOP_MUL) {
- self->error = tokenizer_create_error(&self->tokenizer, tokenizer_get_error_index(&self->tokenizer), "Expected '*', type or closure signature");
- throw(PARSER_UNEXPECTED_TOKEN);
- }
+ throw_if_error(tokenizer_consume_if(&self->tokenizer, TOK_AMPERSAND, &match));
+ if(match)
result->variable_type_flags |= VARIABLE_TYPE_FLAG_BORROW;
- }
throw_if_error(tokenizer_consume_if(&self->tokenizer, TOK_IDENTIFIER, &match));
if(match) {
@@ -329,7 +324,7 @@ void parser_parse_var_type_def(Parser *self, VariableType *result) {
if(result->type == VARIABLE_TYPE_NONE) {
self->error = tokenizer_create_error(&self->tokenizer,
tokenizer_get_error_index(&self->tokenizer),
- "Expected type or closure signature");
+ "Expected '?', '&', type or closure signature");
throw(PARSER_UNEXPECTED_TOKEN);
}
}
diff --git a/src/program.c b/src/program.c
index 4c0f1a2..ac3c923 100644
--- a/src/program.c
+++ b/src/program.c
@@ -445,6 +445,14 @@ static void header_func_set_offset(amal_program *self, u16 func_index, u32 code_
am_memcpy(&header_func->func_offset, &code_offset, sizeof(code_offset));
}
+static u8 header_func_get_num_params(amal_program *self, u16 func_index) {
+ u8 result;
+ BytecodeHeaderFunction *header_func = ((BytecodeHeaderFunction*)self->funcs_start) + func_index;
+ assert(sizeof(header_func->num_params) == sizeof(result));
+ am_memcpy(&result, &header_func->num_params, sizeof(result));
+ return result;
+}
+
static CHECK_RESULT int amal_program_read_instructions(amal_program *self, amal_executor *executor) {
u32 instructions_size;
u32 read_start;
@@ -496,7 +504,7 @@ static CHECK_RESULT int amal_program_read_instructions(amal_program *self, amal_
u16 intermediate_index;
Number number;
- am_memcpy(&intermediate_index, &self->data.data[self->read_index + sizeof(i8)], sizeof(intermediate_index));
+ am_memcpy(&intermediate_index, &self->data.data[self->read_index + sizeof(AmalReg)], sizeof(intermediate_index));
return_if_error(amal_program_get_intermediate_by_index(self, intermediate_index, &number));
return_if_error(amal_exec_movi(executor, self->data.data[self->read_index], number.value.integer));
@@ -507,7 +515,7 @@ static CHECK_RESULT int amal_program_read_instructions(amal_program *self, amal_
u16 data_index;
BufferView data_ptr;
- am_memcpy(&data_index, &self->data.data[self->read_index + sizeof(i8)], sizeof(data_index));
+ am_memcpy(&data_index, &self->data.data[self->read_index + sizeof(AmalReg)], sizeof(data_index));
return_if_error(amal_program_get_data_by_index(self, data_index, &data_ptr));
return_if_error(amal_exec_movd(executor, self->data.data[self->read_index], data_ptr));
@@ -586,7 +594,7 @@ static CHECK_RESULT int amal_program_read_instructions(amal_program *self, amal_
u8 import_index;
u16 func_index;
BytecodeHeaderFunction func_def;
- i8 dst_reg;
+ AmalReg dst_reg;
am_memcpy(&import_index, self->data.data + self->read_index, sizeof(import_index));
am_memcpy(&func_index, self->data.data + self->read_index + sizeof(import_index), sizeof(func_index));
@@ -632,7 +640,7 @@ static CHECK_RESULT int amal_program_read_instructions(amal_program *self, amal_
case AMAL_OP_CALLE: {
u8 import_index;
u16 extern_func_index;
- i8 dst_reg;
+ AmalReg dst_reg;
am_memcpy(&import_index, self->data.data + self->read_index, sizeof(import_index));
am_memcpy(&extern_func_index, self->data.data + self->read_index + sizeof(import_index), sizeof(extern_func_index));
@@ -653,8 +661,13 @@ static CHECK_RESULT int amal_program_read_instructions(amal_program *self, amal_
self->read_index += 3;
break;
}
+ case AMAL_OP_BIT_AND: {
+ assert(bool_false && "TODO: Implement!");
+ self->read_index += 3;
+ break;
+ }
case AMAL_OP_JZ: {
- i8 reg;
+ AmalReg reg;
u16 target_label;
reg = self->data.data[self->read_index];
am_memcpy(&target_label, self->data.data + self->read_index + sizeof(reg), sizeof(target_label));
@@ -670,19 +683,21 @@ static CHECK_RESULT int amal_program_read_instructions(amal_program *self, amal_
break;
}
case AMAL_OP_RET: {
- const i8 reg = self->data.data[self->read_index];
+ const AmalReg reg = self->data.data[self->read_index];
return_if_error(amal_exec_ret(executor, reg));
self->read_index += 1;
break;
}
case AMAL_OP_FUNC_START: {
u8 func_flags;
+ u8 func_num_params;
u16 func_num_local_var_regs;
assert(!inside_func);
inside_func = bool_true;
assert(func_counter < self->num_functions);
+ func_num_params = header_func_get_num_params(self, func_counter);
header_func_set_offset(self, func_counter, amal_exec_get_code_offset(executor));
return_if_error(resolve_deferred_func_calls(self, executor, func_counter));
++func_counter;
@@ -691,7 +706,7 @@ static CHECK_RESULT int amal_program_read_instructions(amal_program *self, amal_
am_memcpy(&func_num_local_var_regs, self->data.data + self->read_index + sizeof(func_flags), sizeof(func_num_local_var_regs));
if(func_flags & FUNC_FLAG_EXPORTED)
return_if_error(amal_program_set_exported_function_instruction_offset_advance(self, amal_exec_get_code_offset(executor)));
- return_if_error(amal_exec_func_start(executor, func_num_local_var_regs));
+ return_if_error(amal_exec_func_start(executor, func_num_params, func_num_local_var_regs));
self->read_index += 3;
break;
}
diff --git a/src/ssa/ssa.c b/src/ssa/ssa.c
index 9955d9d..d875ea4 100644
--- a/src/ssa/ssa.c
+++ b/src/ssa/ssa.c
@@ -81,7 +81,7 @@ int ssa_init(Ssa *self, Parser *parser) {
static CHECK_RESULT int ssa_get_unique_reg(Ssa *self, SsaRegister *result) {
assert(result);
/* Overflow */
- if((u16)self->reg_counter + self->param_counter + 1 > INT16_MAX) {
+ if((u16)self->reg_counter + 1 > INT16_MAX) {
amal_log_error("Ssa too many registers!");
return -1;
}
@@ -90,6 +90,18 @@ static CHECK_RESULT int ssa_get_unique_reg(Ssa *self, SsaRegister *result) {
return 0;
}
+static CHECK_RESULT int ssa_get_unique_param_reg(Ssa *self, SsaRegister *result) {
+ assert(result);
+ /* Overflow */
+ if((u16)self->param_counter + 1 > INT16_MAX) {
+ amal_log_error("Ssa too many param registers!");
+ return -1;
+ }
+ assert(self->param_counter <= INT8_MAX && "TODO: Implement usage of reg higher than 128");
+ *result = self->param_counter++ | REG_FLAG_PARAM;
+ return 0;
+}
+
SsaNumber ssa_get_intermediate(Ssa *self, SsaIntermediateIndex index) {
SsaNumber result;
assert(index < buffer_get_size(&self->intermediates, SsaNumber));
@@ -239,6 +251,7 @@ static const char* binop_type_to_string(SsaInstruction binop_type) {
case SSA_MUL: return "*";
case SSA_DIV: return "/";
case SSA_EQUALS: return "==";
+ case SSA_AND: return "&&";
default: return "";
}
}
@@ -274,7 +287,7 @@ static CHECK_RESULT int ssa_ins_assign_reg(Ssa *self, SsaRegister dest, SsaRegis
}
static CHECK_RESULT int ssa_ins_binop(Ssa *self, SsaInstruction binop_type, SsaRegister lhs, SsaRegister rhs, SsaRegister *result) {
- assert(binop_type >= SSA_ADD && binop_type <= SSA_EQUALS);
+ assert(binop_type >= SSA_ADD && binop_type <= SSA_AND);
return ssa_add_ins_form2(self, binop_type, lhs, rhs, result);
}
@@ -577,14 +590,7 @@ static CHECK_RESULT SsaRegister function_parameter_generate_ssa(FunctionParamete
if(self->resolve_data.status == AST_SSA_RESOLVED)
return self->resolve_data.ssa_reg;
- throw_if_error(ssa_get_unique_reg(context->ssa, &reg));
- /* Parameters start at -1 and decrement */
- if((u16)reg - 1 >= (u16)reg) {
- amal_log_error("Ssa too many parameters!");
- throw(-1);
- }
- reg = -1 - reg;
- assert(reg >= INT8_MIN && "TODO: Implement more than 128 params");
+ throw_if_error(ssa_get_unique_param_reg(context->ssa, &reg));
self->resolve_data.status = AST_SSA_RESOLVED;
self->resolve_data.ssa_reg = reg;
return reg;
@@ -614,6 +620,7 @@ static CHECK_RESULT SsaRegister funcdecl_generate_ssa(FunctionDecl *self, SsaCom
usize func_metadata_index;
u8 func_flags = 0;
context->ssa->reg_counter = 0;
+ context->ssa->param_counter = 0;
context->ssa->label_counter = 0;
/*
@@ -621,8 +628,6 @@ static CHECK_RESULT SsaRegister funcdecl_generate_ssa(FunctionDecl *self, SsaCom
This way we can know if a register access is for a parameter or not by checking the number
*/
function_signature_generate_params_ssa(self->signature, context);
- context->ssa->param_counter = context->ssa->reg_counter;
- context->ssa->reg_counter = 0;
amal_log_debug("SSA funcdecl %p", self);
/* Anonymous closure doesn't have lhs_expr, and neither can it have any flags (extern, export etc) */
@@ -754,6 +759,8 @@ static SsaInstruction binop_type_to_ssa_type(BinopType binop_type, amal_default_
return 0;
case BINOP_EQUALS:
return SSA_EQUALS;
+ case BINOP_AND:
+ return SSA_AND;
}
return 0;
}
diff --git a/src/tokenizer.c b/src/tokenizer.c
index d753b20..da6ad53 100644
--- a/src/tokenizer.c
+++ b/src/tokenizer.c
@@ -339,6 +339,14 @@ static CHECK_RESULT int __tokenizer_next(Tokenizer *self, Token *token) {
} else {
*token = TOK_EQUALS;
}
+ } else if(c == '&') {
+ ++self->index;
+ if(self->index < (int)self->code.size && tokenizer_get_char(self) == '&') {
+ ++self->index;
+ SET_BINOP(BINOP_AND);
+ } else {
+ *token = TOK_AMPERSAND;
+ }
} else if(c == '(') {
++self->index;
*token = TOK_OPEN_PAREN;
@@ -517,6 +525,9 @@ static BufferView tokenizer_expected_token_as_string(Token token) {
case TOK_QUESTION_MARK:
str = "?";
break;
+ case TOK_AMPERSAND:
+ str = "&";
+ break;
case TOK_C_VARARGS:
str = "...";
break;