aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authordec05eba <dec05eba@protonmail.com>2019-09-21 13:59:39 +0200
committerdec05eba <dec05eba@protonmail.com>2020-07-25 14:36:46 +0200
commitc811a743a1528db1d05970e1aa14162ef7c70b75 (patch)
tree4560ab5d9084c385946415e9fc2dbf187e26c844 /src
parent142a13ad3f77c0ad1bd321d1a1f864a5117896d1 (diff)
Implement vararg, verify arguments to parameters
Diffstat (limited to 'src')
-rw-r--r--src/ast.c75
-rw-r--r--src/bytecode/bytecode.c40
-rw-r--r--src/compiler.c18
-rw-r--r--src/parser.c87
-rw-r--r--src/program.c26
-rw-r--r--src/tokenizer.c46
6 files changed, 227 insertions, 65 deletions
diff --git a/src/ast.c b/src/ast.c
index 0008785..90af981 100644
--- a/src/ast.c
+++ b/src/ast.c
@@ -5,6 +5,7 @@
#include "../include/std/hash.h"
#include <assert.h>
#include <stdarg.h>
+#include <stdio.h>
#define throw(result) do { throw_debug_msg; longjmp(context->env, (result)); } while(0)
#define throw_if_error(result) \
@@ -446,6 +447,8 @@ static void compiler_print_error(amal_compiler *compiler, const char *ref, const
tokenizer = amal_compiler_find_tokenizer_by_code_reference(compiler, ref);
if(!tokenizer) {
amal_log_error("Failed to find tokenizer for code reference %p. Is it an invalid reference?", ref ? ref : "(null)");
+ vfprintf(stderr, fmt, args);
+ fputc('\n', stderr);
return;
}
tokenizer_print_error_args(tokenizer, tokenizer_get_code_reference_index(tokenizer, ref), fmt, args);
@@ -726,9 +729,60 @@ static void funcdecl_resolve(Ast *self, AstCompilerContext *context) {
self->resolve_data.type.value.func_sig = self->value.func_decl->signature;
}
+static usize min(usize a, usize b) {
+ return a < b ? a : b;
+}
+
+static bool resolve_data_type_equals(AstResolvedType *self, AstResolvedType *other) {
+ return self->type == other->type && self->value.data == other->value.data;
+}
+
+static bool function_parameter_is_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 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);
+
+ FunctionParameter *func_param = buffer_begin(&func_sig->parameters);
+ FunctionParameter *func_param_end = buffer_end(&func_sig->parameters);
+
+ usize num_args = arg_end - arg;
+ usize num_params = func_param_end - func_param;
+ isize num_missing_args = (isize)num_params - (isize)num_args;
+ 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)) {
+ 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,
+ "Can't cast argument of type \"%.*s\" to parameter of type \"%.*s\"", arg_name.size, arg_name.data, param_name.size, param_name.data);
+ throw(AST_ERR);
+ }
+ ++arg;
+ ++func_param;
+ }
+
+ 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);
+ if (has_vararg)
+ num_missing_args -= 1;
+ if(num_missing_args > 0) {
+ compiler_print_error(context->compiler, func_call->func.name.data,
+ "Missing %d argument(s) to closure \"%.*s\"", num_missing_args, func_call->func.name.size, func_call->func.name.data);
+ throw(AST_ERR);
+ }
+ }
+}
+
static void funccall_resolve(Ast *self, AstCompilerContext *context) {
Ast **ast;
Ast **ast_end;
+ FunctionSignature *func_sig;
FunctionCall *func_call = self->value.func_call;
variable_resolve(&func_call->func, context, &self->resolve_data.type);
@@ -744,7 +798,7 @@ static void funccall_resolve(Ast *self, AstCompilerContext *context) {
}
{
- FunctionSignature *func_sig = self->resolve_data.type.value.func_sig;
+ 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;
@@ -756,6 +810,8 @@ static void funccall_resolve(Ast *self, AstCompilerContext *context) {
for(; ast != ast_end; ++ast) {
ast_resolve(*ast, context);
}
+
+ verify_func_call_matches_func_signature(func_call, func_sig, context);
}
static TypeSize variable_type_get_byte_size(VariableType *self) {
@@ -766,9 +822,13 @@ static TypeSize variable_type_get_byte_size(VariableType *self) {
case VARIABLE_TYPE_NONE:
assert(bool_false && "Variable type not resolved!");
break;
- case VARIABLE_TYPE_VARIABLE:
- type_size = resolved_type_get_byte_size(&self->value.variable->resolved_var.resolve_data->type);
+ case VARIABLE_TYPE_VARIABLE: {
+ if(self->variable_type_flags & VARIABLE_TYPE_FLAG_BORROW)
+ type_size.num_pointers = 1;
+ else
+ type_size = resolved_type_get_byte_size(&self->value.variable->resolved_var.resolve_data->type);
break;
+ }
case VARIABLE_TYPE_SIGNATURE:
type_size.num_pointers = 1;
break;
@@ -790,7 +850,8 @@ static void structdecl_resolve(Ast *self, AstCompilerContext *context) {
Ast **ast = buffer_begin(&body->ast_objects);
Ast **ast_end = buffer_end(&body->ast_objects);
for(; ast != ast_end; ++ast) {
- TypeSize type_size = variable_type_get_byte_size(&(*ast)->value.struct_field->type);
+ StructField *struct_field = (*ast)->value.struct_field;
+ TypeSize type_size = variable_type_get_byte_size(&struct_field->type);
struct_decl->fields_num_pointers += type_size.num_pointers;
struct_decl->fields_fixed_size_bytes += type_size.fixed_size;
}
@@ -1020,9 +1081,9 @@ void ast_resolve(Ast *self, AstCompilerContext *context) {
/* TODO: Support other number types */
self->resolve_data.type.type = RESOLVED_TYPE_LHS_EXPR;
if(number->is_integer)
- self->resolve_data.type.value.lhs_expr = (LhsExpr*)context->compiler->default_types.i64;
+ self->resolve_data.type.value.lhs_expr = &context->compiler->default_types.i64->lhs_expr;
else
- self->resolve_data.type.value.lhs_expr = (LhsExpr*)context->compiler->default_types.f64;
+ self->resolve_data.type.value.lhs_expr = &context->compiler->default_types.f64->lhs_expr;
break;
}
case AST_FUNCTION_DECL:
@@ -1050,7 +1111,7 @@ void ast_resolve(Ast *self, AstCompilerContext *context) {
case AST_STRING:
/* TODO: Convert special combinations. For example \n to newline */
self->resolve_data.type.type = RESOLVED_TYPE_LHS_EXPR;
- self->resolve_data.type.value.lhs_expr = (LhsExpr*)context->compiler->default_types.str;
+ self->resolve_data.type.value.lhs_expr = &context->compiler->default_types.str->lhs_expr;
break;
case AST_VARIABLE:
variable_resolve(self->value.variable, context, &self->resolve_data.type);
diff --git a/src/bytecode/bytecode.c b/src/bytecode/bytecode.c
index 7dbc305..a5e3abc 100644
--- a/src/bytecode/bytecode.c
+++ b/src/bytecode/bytecode.c
@@ -142,9 +142,13 @@ static TypeSize function_signature_get_params_size(FunctionSignature *self) {
params_total_size.num_pointers = 0;
params_total_size.fixed_size = 0;
for(; param != param_end; ++param) {
- TypeSize param_size = resolved_type_get_byte_size(&param->resolve_data.type);
- params_total_size.num_pointers += param_size.num_pointers;
- params_total_size.fixed_size += param_size.fixed_size;
+ if(param->type.variable_type_flags & VARIABLE_TYPE_FLAG_BORROW)
+ params_total_size.num_pointers += 1;
+ else {
+ TypeSize param_size = resolved_type_get_byte_size(&param->resolve_data.type);
+ params_total_size.num_pointers += param_size.num_pointers;
+ params_total_size.fixed_size += param_size.fixed_size;
+ }
}
return params_total_size;
}
@@ -228,20 +232,21 @@ static void add_extern_functions(BytecodeCompilerContext *self) {
|Type|Field |Description |
|----|-------------------------|-----------------------------------------------------------------------------------------------------|
|u8 |num_params |The number of parameters. |
+ |u8 |num_return_types |The number of return values. |
+ |u8 |name_len |The length of the external function name, in bytes. Excluding the null-terminate character. |
+ |u8 |flags |The flags for the external function. The values are defined in @amal_func_flag. |
|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. |
- |u8 |name_len |The length of the external function name, in bytes. Excluding the null-terminate character. |
|u8[]|name |The name of the external function, where the size is defined by @name_len. Names are null-terminated.|
*/
Ssa *ssa = self->parser->ssa;
Buffer *instructions = &self->bytecode->data;
SsaExternFunc *extern_func = buffer_begin(&ssa->extern_funcs);
SsaExternFunc *extern_func_end = buffer_end(&ssa->extern_funcs);
- u32 extern_funcs_size = (u32)ssa->extern_func_counter * (sizeof(BytecodeHeaderExternFunction) + sizeof(u8));
- assert(sizeof(BytecodeHeaderExternFunction) == 18);
+ u32 extern_funcs_size = (u32)ssa->extern_func_counter * sizeof(BytecodeHeaderExternFunction);
+ assert(sizeof(BytecodeHeaderExternFunction) == 20);
for(; extern_func != extern_func_end; ++extern_func) {
extern_funcs_size += extern_func->name.size + 1; /* +1 for null-termination of string */
@@ -259,17 +264,26 @@ static void add_extern_functions(BytecodeCompilerContext *self) {
BytecodeHeaderExternFunction header_func;
header_func.num_params = buffer_get_size(&extern_func->func_sig->parameters, FunctionParameter);
+ header_func.num_return_types = buffer_get_size(&extern_func->func_sig->return_types, FunctionReturnType);
+ header_func.name_len = extern_func->name.size;
+ header_func.flags = 0;
+ if(header_func.num_params > 0) {
+ amal_default_type *vararg_type = self->parser->compiler->default_types.c_varargs;
+ FunctionParameter *last_param = buffer_begin(&extern_func->func_sig->parameters);
+ last_param += (header_func.num_params - 1);
+ if(last_param->resolve_data.type.value.data == &vararg_type->lhs_expr)
+ header_func.flags |= FUNC_FLAG_VARARGS;
+ }
+
header_func.params_num_pointers = params_total_size.num_pointers;
header_func.params_fixed_size = params_total_size.fixed_size;
- header_func.num_return_types = buffer_get_size(&extern_func->func_sig->return_types, FunctionReturnType);
header_func.return_types_num_pointers = return_types_total_size.num_pointers;
header_func.return_types_fixed_size = return_types_total_size.fixed_size;
throw_if_error(buffer_append(instructions, &header_func, sizeof(header_func)));
/* TODO: Add namespace to the function name */
/* u8 is fine, because the max length of a variable is 255 */
- throw_if_error(buffer_append(instructions, &extern_func->name.size, sizeof(u8)));
throw_if_error(buffer_append(instructions, extern_func->name.data, extern_func->name.size));
throw_if_error(buffer_append(instructions, &null_s, sizeof(char)));
}
@@ -435,10 +449,10 @@ static void add_ins6(BytecodeCompilerContext *self, AmalOpcode opcode, i8 dst_re
static void add_instructions(BytecodeCompilerContext *self) {
/*doc(Bytecode instructions)
# Instructions layout
- |Type |Field |Description |
- |-----------|-----------------|---------------------------------------------------------------------------|
- |u32 |Instructions size|The size of the instructions section, in bytes. |
- |Instruction|Instructions data|The instructions data. Each instructions begins with an opcode, see #Opcode|
+ |Type |Field |Description |
+ |-------------|-----------------|---------------------------------------------------------------------------|
+ |u32 |Instructions size|The size of the instructions section, in bytes. |
+ |Instruction[]|Instructions data|The instructions data. Each instructions begins with an opcode, see #Opcode|
*/
SsaInsForm1 ssa_ins_form1;
diff --git a/src/compiler.c b/src/compiler.c
index 4d43329..5b48aaf 100644
--- a/src/compiler.c
+++ b/src/compiler.c
@@ -82,6 +82,7 @@ static CHECK_RESULT int init_default_types(amal_compiler *compiler) {
return_if_error(create_default_type_fixed_size(compiler, "c_int", sizeof(int), &compiler->default_types.c_int));
return_if_error(create_default_type_fixed_size(compiler, "c_long", sizeof(long), &compiler->default_types.c_long));
return_if_error(create_default_type_num_pointers(compiler, "c_void", 0, &compiler->default_types.c_void));
+ return_if_error(create_default_type_num_pointers(compiler, "...", 0, &compiler->default_types.c_varargs));
compiler->default_types.arithmetic_types[0] = compiler->default_types.i8;
compiler->default_types.arithmetic_types[1] = compiler->default_types.u8;
@@ -94,6 +95,11 @@ static CHECK_RESULT int init_default_types(amal_compiler *compiler) {
compiler->default_types.arithmetic_types[8] = compiler->default_types.isize;
compiler->default_types.arithmetic_types[9] = compiler->default_types.usize;
+ compiler->default_types.arithmetic_types[10] = compiler->default_types.c_char;
+ compiler->default_types.arithmetic_types[11] = compiler->default_types.c_short;
+ compiler->default_types.arithmetic_types[12] = compiler->default_types.c_int;
+ compiler->default_types.arithmetic_types[13] = compiler->default_types.c_long;
+
compiler->default_types.i8->is_signed = bool_true;
compiler->default_types.u8->is_signed = bool_false;
compiler->default_types.i16->is_signed = bool_true;
@@ -106,7 +112,15 @@ static CHECK_RESULT int init_default_types(amal_compiler *compiler) {
compiler->default_types.usize->is_signed = bool_false;
compiler->default_types.f32->is_signed = bool_true;
compiler->default_types.f64->is_signed = bool_true;
+ compiler->default_types.bool->is_signed = bool_false;
compiler->default_types.str->is_signed = bool_false;
+
+ compiler->default_types.c_char->is_signed = bool_true;
+ compiler->default_types.c_short->is_signed = bool_true;
+ compiler->default_types.c_int->is_signed = bool_true;
+ compiler->default_types.c_long->is_signed = bool_true;
+ compiler->default_types.c_void->is_signed = bool_false;
+ compiler->default_types.c_varargs->is_signed = bool_false;
return 0;
}
@@ -199,8 +213,10 @@ static CHECK_RESULT int amal_compiler_load_in_this_thread(amal_compiler *compile
parser_allocator = NULL;
result = AMAL_COMPILER_ERR;
- return_if_error(arena_allocator_alloc(&compiler->allocator, sizeof(ArenaAllocator), (void**)&parser_allocator));
+ cleanup_if_error(amal_mutex_lock(&compiler->mutex, "amal_compiler_load_in_this_thread, create allocator for parser"));
+ cleanup_if_error(arena_allocator_alloc(&compiler->allocator, sizeof(ArenaAllocator), (void**)&parser_allocator));
cleanup_if_error(arena_allocator_init(parser_allocator));
+ amal_mutex_tryunlock(&compiler->mutex);
filepath = create_buffer_view(file_scope->canonical_path.data, file_scope->canonical_path.size);
amal_log_info("Started parsing %.*s", filepath.size, filepath.data);
diff --git a/src/parser.c b/src/parser.c
index 9da9147..dc39a6a 100644
--- a/src/parser.c
+++ b/src/parser.c
@@ -119,31 +119,45 @@ static void parser_parse_struct_body_loop(Parser *self, StructDecl *struct_decl)
}
/*
-FUNC_PARAM = TOK_IDENTIFIER VAR_TYPE_DEF
+FUNC_PARAM = (TOK_IDENTIFIER VAR_TYPE_DEF)|'...'
*/
static CHECK_RESULT bool parser_parse_function_parameter(Parser *self, FunctionParameter *result) {
bool match;
throw_if_error(tokenizer_consume_if(&self->tokenizer, TOK_IDENTIFIER, &match));
- if(!match)
- return bool_false;
+ if(match) {
+ result->name = self->tokenizer.value.identifier;
+ parser_parse_var_type_def(self, &result->type);
+ if(result->type.type == VARIABLE_TYPE_NONE) {
+ self->error = tokenizer_create_error(&self->tokenizer,
+ tokenizer_get_error_index(&self->tokenizer),
+ "Expected ':' after parameter name");
+ throw(PARSER_UNEXPECTED_TOKEN);
+ }
+ return bool_true;
+ }
- result->name = self->tokenizer.value.identifier;
- parser_parse_var_type_def(self, &result->type);
- if(result->type.type == VARIABLE_TYPE_NONE) {
- self->error = tokenizer_create_error(&self->tokenizer,
- tokenizer_get_error_index(&self->tokenizer),
- "Expected ':' after parameter name");
- throw(PARSER_UNEXPECTED_TOKEN);
+ throw_if_error(tokenizer_consume_if(&self->tokenizer, TOK_C_VARARGS, &match));
+ if(match) {
+ result->name = self->tokenizer.value.identifier;
+ result->type.variable_type_flags = VARIABLE_TYPE_FLAG_NONE;
+ result->type.type = VARIABLE_TYPE_VARIABLE;
+ throw_if_error(arena_allocator_alloc(self->allocator, sizeof(Variable), (void**)&result->type.value.variable));
+ variable_init(result->type.value.variable, result->name);
+ return bool_true;
}
- return bool_true;
+ return bool_false;
}
/*
FUNC_PARAMS = FUNC_PARAM (',' FUNC_PARAM)*
*/
static void parser_parse_function_parameters(Parser *self, FunctionSignature *func_sig) {
+ amal_default_type *vararg_type = self->compiler->default_types.c_varargs;
+ int vararg_index = -1;
+ int index = 0;
+
for(;;) {
FunctionParameter func_param;
bool match;
@@ -157,6 +171,13 @@ static void parser_parse_function_parameters(Parser *self, FunctionSignature *fu
throw(PARSER_UNEXPECTED_TOKEN);
}
+ if(vararg_index != -1) {
+ self->error = tokenizer_create_error(&self->tokenizer,
+ tokenizer_get_error_index(&self->tokenizer),
+ "A closure can't have parameters after a vararg");
+ throw(PARSER_UNEXPECTED_TOKEN);
+ }
+
result = function_signature_add_parameter(func_sig, &func_param);
if(result == AST_ERR_DEF_DUP) {
self->error = tokenizer_create_error(&self->tokenizer,
@@ -169,7 +190,19 @@ static void parser_parse_function_parameters(Parser *self, FunctionSignature *fu
}
throw_if_error(tokenizer_consume_if(&self->tokenizer, TOK_COMMA, &match));
if(!match)
- return;
+ break;
+
+ if (vararg_index == -1 && buffer_view_equals(&func_param.name, &vararg_type->lhs_expr.var_name))
+ vararg_index = index;
+
+ ++index;
+ }
+
+ if (index > FUNC_MAX_PARAMS) {
+ self->error = tokenizer_create_error(&self->tokenizer,
+ tokenizer_get_error_index(&self->tokenizer),
+ "A closure can't have more than %d parameters", FUNC_MAX_PARAMS);
+ throw(PARSER_ERR);
}
}
@@ -192,19 +225,19 @@ static void parser_parse_function_return_types(Parser *self, FunctionSignature *
tokenizer_get_error_index(&self->tokenizer),
"Expected type or closure signature");
throw(PARSER_UNEXPECTED_TOKEN);
+ } else if(var_type.variable_type_flags & VARIABLE_TYPE_FLAG_BORROW) {
+ self->error = tokenizer_create_error(&self->tokenizer,
+ tokenizer_get_error_index(&self->tokenizer),
+ "A closure can't return a value as borrowed");
+ throw(PARSER_ERR);
}
+
throw_if_error(function_signature_add_return_type(func_sig, &var_type));
throw_if_error(tokenizer_consume_if(&self->tokenizer, TOK_COMMA, &match));
if(!match)
break;
- ++return_type_index;
- }
- if (buffer_get_size(&func_sig->parameters, FunctionParameter) > FUNC_MAX_PARAMS) {
- self->error = tokenizer_create_error(&self->tokenizer,
- tokenizer_get_error_index(&self->tokenizer),
- "A closure can't have more than %d parameters", FUNC_MAX_PARAMS);
- throw(PARSER_ERR);
+ ++return_type_index;
}
if (buffer_get_size(&func_sig->return_types, FunctionReturnType) > FUNC_MAX_RETURN_TYPES) {
@@ -244,13 +277,27 @@ static CHECK_RESULT FunctionSignature* parser_parse_function_signature(Parser *s
}
/*
-VAR_TYPE = TOK_IDENTIFIER|FUNC_SIGNATURE
+VAR_TYPE = '?'? TOK_IDENTIFIER|FUNC_SIGNATURE
*/
void parser_parse_var_type(Parser *self, VariableType *result) {
bool match;
result->type = VARIABLE_TYPE_NONE;
result->value.variable = NULL;
+ result->variable_type_flags = VARIABLE_TYPE_FLAG_NONE;
+
+ throw_if_error(tokenizer_consume_if(&self->tokenizer, TOK_QUESTION_MARK, &match));
+ 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);
+ }
+ result->variable_type_flags |= VARIABLE_TYPE_FLAG_BORROW;
+ }
throw_if_error(tokenizer_consume_if(&self->tokenizer, TOK_IDENTIFIER, &match));
if(match) {
diff --git a/src/program.c b/src/program.c
index 128f0f9..4c0f1a2 100644
--- a/src/program.c
+++ b/src/program.c
@@ -78,7 +78,7 @@ void amal_program_deinit(amal_program *self) {
buffer_deinit(&self->data);
}
-int amal_program_register_extern_func(amal_program *self, BufferView name, void *func_ptr, int args_byte_size) {
+int amal_program_register_extern_func(amal_program *self, BufferView name, void *func_ptr, u32 args_byte_size) {
ProgramExternFunc extern_func;
extern_func.func = func_ptr;
extern_func.args_byte_size = args_byte_size;
@@ -112,15 +112,16 @@ static void amal_program_get_header_extern_function_by_index(amal_program *self,
u32 i;
u8 *extern_funcs_start = amal_program_get_extern_funcs_start_by_import_index(self, import_index);
extern_funcs_start += sizeof(u16) + sizeof(u32);
+
for(i = 0; i < (u32)index; ++i) {
- u8 name_len;
+ BytecodeHeaderExternFunction *extern_func = (BytecodeHeaderExternFunction*)extern_funcs_start;
extern_funcs_start += sizeof(BytecodeHeaderExternFunction);
- name_len = *extern_funcs_start;
- extern_funcs_start += 1 + name_len + 1; /* +1 for skipping length byte and the null-terminated character */
+ extern_funcs_start += extern_func->name_len + 1; /* +1 for skipping the null-terminated character */
}
+
am_memcpy(&result->extern_func, extern_funcs_start, sizeof(result->extern_func));
- result->name.size = *(extern_funcs_start + sizeof(result->extern_func));
- result->name.data = (const char*)extern_funcs_start + sizeof(result->extern_func) + sizeof(u8);
+ result->name.size = result->extern_func.name_len;
+ result->name.data = (const char*)extern_funcs_start + sizeof(result->extern_func);
}
@@ -133,10 +134,15 @@ static CHECK_RESULT int amal_program_get_extern_func_by_index(amal_program *self
return AMAL_PROGRAM_NO_SUCH_EXTERNAL_FUNCTION;
}
- /* TODO: This assumes all arguments are of size sizeof(isize) */
- if(result->args_byte_size != -1 && result->args_byte_size != (int)extern_func_get_total_param_size(&extern_func.extern_func)) {
- amal_log_error("Extern function %.*s was registered to take %d byte(s), but the program says it takes %d byte(s)",
- extern_func.name.size, extern_func.name.data, result->args_byte_size, (int)extern_func_get_total_param_size(&extern_func.extern_func));
+ if(extern_func.extern_func.flags & FUNC_FLAG_VARARGS) {
+ if(extern_func_get_total_param_size(&extern_func.extern_func) < result->args_byte_size) {
+ amal_log_error("Extern function %.*s was registered to take at least %u byte(s), but the program says it takes at least %u byte(s)",
+ extern_func.name.size, extern_func.name.data, result->args_byte_size, extern_func_get_total_param_size(&extern_func.extern_func));
+ return AMAL_PROGRAM_NO_SUCH_EXTERNAL_FUNCTION;
+ }
+ } else if(extern_func_get_total_param_size(&extern_func.extern_func) != result->args_byte_size) {
+ amal_log_error("Extern function %.*s was registered to take %u byte(s), but the program says it takes %u byte(s)",
+ extern_func.name.size, extern_func.name.data, result->args_byte_size, extern_func_get_total_param_size(&extern_func.extern_func));
return AMAL_PROGRAM_NO_SUCH_EXTERNAL_FUNCTION;
}
return 0;
diff --git a/src/tokenizer.c b/src/tokenizer.c
index 9ce1bba..d753b20 100644
--- a/src/tokenizer.c
+++ b/src/tokenizer.c
@@ -235,19 +235,6 @@ static CHECK_RESULT int __tokenizer_next(Tokenizer *self, Token *token) {
}
}
*token = TOK_IDENTIFIER;
- } else if(c == '"') {
- int string_end;
- ++self->index;
- string_end = find_end_of_string(self->code, self->index);
- if(string_end == -1) {
- tokenizer_print_error(self, self->prev_index, "String end not found. Did you forget '\"' or did you have a mismatch of number of '\"'?");
- return TOKENIZER_ERR;
- }
-
- self->value.string.data = &self->code.data[self->index];
- self->value.string.size = string_end - self->index;
- self->index = string_end + 1;
- *token = TOK_STRING;
} else if(isDigit(c)) {
int number_start;
int dot_index;
@@ -290,9 +277,31 @@ static CHECK_RESULT int __tokenizer_next(Tokenizer *self, Token *token) {
self->number_is_integer = bool_false;
}
*token = TOK_NUMBER;
+ } else if(c == '"') {
+ int string_end;
+ ++self->index;
+ string_end = find_end_of_string(self->code, self->index);
+ if(string_end == -1) {
+ tokenizer_print_error(self, self->prev_index, "String end not found. Did you forget '\"' or did you have a mismatch of number of '\"'?");
+ return TOKENIZER_ERR;
+ }
+
+ self->value.string.data = &self->code.data[self->index];
+ self->value.string.size = string_end - self->index;
+ self->index = string_end + 1;
+ *token = TOK_STRING;
} else if(c == '.') {
+ const char *start = self->code.data + self->index;
++self->index;
- SET_BINOP(BINOP_DOT);
+ /* ... */
+ if((usize)self->index + 2 < self->code.size && am_memcmp(self->code.data + self->index, "..", 2) == 0) {
+ self->index += 2;
+ self->value.identifier.data = start;
+ self->value.identifier.size = 3;
+ *token = TOK_C_VARARGS;
+ } else {
+ SET_BINOP(BINOP_DOT);
+ }
} else if(c == '+') {
++self->index;
SET_BINOP(BINOP_ADD);
@@ -351,6 +360,9 @@ static CHECK_RESULT int __tokenizer_next(Tokenizer *self, Token *token) {
} else if(c == ':') {
++self->index;
*token = TOK_COLON;
+ } else if(c == '?') {
+ ++self->index;
+ *token = TOK_QUESTION_MARK;
} else if(c == '@') {
const char *err_msg;
++self->index;
@@ -502,6 +514,12 @@ static BufferView tokenizer_expected_token_as_string(Token token) {
case TOK_RETURN:
str = "return";
break;
+ case TOK_QUESTION_MARK:
+ str = "?";
+ break;
+ case TOK_C_VARARGS:
+ str = "...";
+ break;
}
return create_buffer_view(str, strlen(str));
}