#include "lex.h"
#include "types.h"
+#include "errors.h"
#define AST_NODES \
NODE(Node) \
struct Arguments {
bh_arr(AstTyped *) values;
bh_arr(AstNamedValue *) named_values;
+
+ // How many arguments were not baked.
+ i32 used_argument_count;
};
void arguments_clone(Arguments* dest, Arguments* src);
void arguments_deep_clone(bh_allocator a, Arguments* dest, Arguments* src);
void arguments_remove_baked(Arguments* args);
+b32 check_arguments_against_type(Arguments* args, TypeFunction* func_type, VarArgKind* va_kind,
+ OnyxToken* location, char* func_name, struct OnyxError* error);
+i32 function_get_minimum_argument_count(TypeFunction* type, Arguments* args);
// GROSS: Using void* to avoid having to cast everything.
const char* node_get_type_name(void* node);
extern OnyxErrors msgs;
void onyx_errors_init(bh_arr(bh_file_contents)* files);
+void onyx_submit_error(OnyxError error);
void onyx_report_error(OnyxFilePos pos, char * format, ...);
+void onyx_submit_warning(OnyxError error);
void onyx_report_warning(OnyxFilePos pos, char* format, ...);
void onyx_errors_print();
b32 onyx_has_errors();
args->values[i] = NULL;
args->named_values[i] = NULL;
}
+
+ args->used_argument_count = -1;
}
void arguments_ensure_length(Arguments* args, u32 count) {
}
void arguments_copy(Arguments* dest, Arguments* src) {
+ dest->used_argument_count = -1;
dest->named_values = src->named_values;
- arguments_ensure_length(dest, bh_arr_length(src->values));
+ bh_arr_grow(dest->values, (u32) bh_arr_length(src->values));
+ bh_arr_set_length(dest->values, (u32) bh_arr_length(src->values));
bh_arr_each(AstTyped*, arg, dest->values) *arg = NULL;
fori (i, 0, bh_arr_length(src->values)) dest->values[i] = src->values[i];
}
// In clone, the named_values are not copied. This is used in find_matching_overload_by_arguments since it doesn't need them to be copied.
void arguments_clone(Arguments* dest, Arguments* src) {
+ dest->used_argument_count = -1;
dest->named_values = src->named_values;
dest->values = bh_arr_copy(global_heap_allocator, src->values);
}
void arguments_deep_clone(bh_allocator a, Arguments* dest, Arguments* src) {
+ dest->used_argument_count = -1;
dest->values = NULL;
dest->named_values = NULL;
return Check_Success;
}
-static i32 non_baked_argument_count(Arguments* args) {
- i32 count = 0;
-
- bh_arr_each(AstTyped *, actual, args->values) {
- assert((*actual)->kind == Ast_Kind_Argument);
- if (!((AstArgument *) (*actual))->is_baked) count++;
- }
-
- bh_arr_each(AstNamedValue *, named_value, args->named_values) {
- assert((*named_value)->value->kind == Ast_Kind_Argument);
- if (!((AstArgument *) (*named_value)->value)->is_baked) count++;
- }
-
- return count;
-}
-
static CheckStatus check_resolve_callee(AstCall* call, AstTyped** effective_callee) {
if (call->kind == Ast_Kind_Intrinsic_Call) return Check_Success;
return Check_Success;
}
-typedef enum ArgState {
- AS_Expecting_Exact,
- AS_Expecting_Typed_VA,
- AS_Expecting_Untyped_VA,
-} ArgState;
-
CheckStatus check_call(AstCall** pcall) {
// All the things that need to be done when checking a call node.
// 1. Ensure the callee is not a symbol
AstFunction* callee=NULL;
CHECK(resolve_callee, call, (AstTyped **) &callee);
- // CLEANUP maybe make function_get_expected_arguments?
- i32 non_vararg_param_count = (i32) callee->type->Function.param_count;
- if (non_vararg_param_count > 0 &&
- callee->type->Function.params[callee->type->Function.param_count - 1] == builtin_vararg_type_type)
- non_vararg_param_count--;
-
- i32 arg_count = bh_max(non_vararg_param_count, non_baked_argument_count(&call->args));
+ i32 arg_count = function_get_minimum_argument_count(&callee->type->Function, &call->args);
arguments_ensure_length(&call->args, arg_count);
char* err_msg = NULL;
YIELD(call->token->pos, "Waiting for auto-return type to be solved.");
}
- Type **formal_params = callee->type->Function.params;
-
- Type* variadic_type = NULL;
- AstParam* variadic_param = NULL;
-
- // SPEED CLEANUP: Caching the any type here.
- Type* any_type = type_build_from_ast(context.ast_alloc, builtin_any_type);
-
- ArgState arg_state = AS_Expecting_Exact;
- u32 arg_pos = 0;
- while (1) {
- switch (arg_state) {
- case AS_Expecting_Exact: {
- if (arg_pos >= callee->type->Function.param_count) goto type_checking_done;
-
- if (formal_params[arg_pos]->kind == Type_Kind_VarArgs) {
- variadic_type = formal_params[arg_pos]->VarArgs.elem;
- variadic_param = &callee->params[arg_pos];
- arg_state = AS_Expecting_Typed_VA;
- continue;
- }
-
- if ((i16) arg_pos == callee->type->Function.vararg_arg_pos) {
- arg_state = AS_Expecting_Untyped_VA;
- continue;
- }
-
- if (arg_pos >= (u32) bh_arr_length(arg_arr)) goto type_checking_done;
- if (!unify_node_and_type(&arg_arr[arg_pos]->value, formal_params[arg_pos])) {
- ERROR_(arg_arr[arg_pos]->token->pos,
- "The procedure '%s' expects a value of type '%s' for %d%s parameter, got '%s'.",
- get_function_name(callee),
- type_get_name(formal_params[arg_pos]),
- arg_pos + 1,
- bh_num_suffix(arg_pos + 1),
- node_get_type_name(arg_arr[arg_pos]->value));
- }
-
- arg_arr[arg_pos]->va_kind = VA_Kind_Not_VA;
- break;
- }
-
- case AS_Expecting_Typed_VA: {
- if (variadic_type->id == any_type->id) call->va_kind = VA_Kind_Any;
- if (arg_pos >= (u32) bh_arr_length(arg_arr)) goto type_checking_done;
-
- if (variadic_type->id == any_type->id) {
- resolve_expression_type(arg_arr[arg_pos]->value);
- arg_arr[arg_pos]->va_kind = VA_Kind_Any;
- break;
- }
-
- call->va_kind = VA_Kind_Typed;
-
- if (!unify_node_and_type(&arg_arr[arg_pos]->value, variadic_type)) {
- onyx_report_error(arg_arr[arg_pos]->token->pos,
- "The procedure '%s' expects a value of type '%s' for the variadic parameter, '%b', got '%s'.",
- get_function_name(callee),
- type_get_name(variadic_type),
- variadic_param->local->token->text,
- variadic_param->local->token->length,
- node_get_type_name(arg_arr[arg_pos]->value));
- return Check_Error;
- }
-
- arg_arr[arg_pos]->va_kind = VA_Kind_Typed;
- break;
- }
-
- case AS_Expecting_Untyped_VA: {
- call->va_kind = VA_Kind_Untyped;
-
- if (arg_pos >= (u32) bh_arr_length(arg_arr)) goto type_checking_done;
-
- resolve_expression_type(arg_arr[arg_pos]->value);
- if (arg_arr[arg_pos]->value->type == NULL) {
- ERROR(arg_arr[arg_pos]->token->pos, "Unable to resolve type for argument.");
- }
-
- arg_arr[arg_pos]->va_kind = VA_Kind_Untyped;
- break;
- }
- }
-
- arg_pos++;
+ OnyxError error;
+ if (!check_arguments_against_type(&call->args, &callee->type->Function, &call->va_kind,
+ call->token, get_function_name(callee), &error)) {
+ onyx_submit_error(error);
+ return Check_Error;
}
-type_checking_done:
-
- call->flags |= Ast_Flag_Has_Been_Checked;
-
- if (arg_pos < callee->type->Function.needed_param_count)
- ERROR(call->token->pos, "Too few arguments to function call.");
-
- if (arg_pos < (u32) arg_count)
- ERROR(call->token->pos, "Too many arguments to function call.");
-
+ call->flags |= Ast_Flag_Has_Been_Checked;
callee->flags |= Ast_Flag_Function_Used;
if (call->kind == Ast_Kind_Call && call->callee->kind == Ast_Kind_Macro) {
Arguments args = ((Arguments) { NULL, NULL });
bh_arr_new(global_heap_allocator, args.values, 2);
- bh_arr_push(args.values, binop->left);
- bh_arr_push(args.values, binop->right);
+ bh_arr_push(args.values, (AstTyped *) make_argument(context.ast_alloc, binop->left));
+ bh_arr_push(args.values, (AstTyped *) make_argument(context.ast_alloc, binop->right));
+
+ u32 current_checking_level_store = current_checking_level;
+ check_argument((AstArgument **) &args.values[0]);
+ check_argument((AstArgument **) &args.values[1]);
+ current_checking_level = current_checking_level_store;
if (binop_is_assignment(binop->operation)) {
args.values[0] = (AstTyped *) make_address_of(context.ast_alloc, binop->left);
if (cs == Check_Error) {
return NULL;
}
+
+ args.values[0] = (AstTyped *) make_argument(context.ast_alloc, args.values[0]);
+ current_checking_level_store = current_checking_level;
+ check_argument((AstArgument **) &args.values[0]);
+ current_checking_level = current_checking_level_store;
}
b32 should_yield = 0;
implicit_call->callee = overload;
implicit_call->va_kind = VA_Kind_Not_VA;
- bh_arr_each(AstTyped *, arg, args.values)
- *arg = (AstTyped *) make_argument(context.ast_alloc, *arg);
-
implicit_call->args = args;
return implicit_call;
}
bh_arr_set_length(errors.errors, 0);
}
+void onyx_submit_error(OnyxError error) {
+ bh_arr_push(errors.errors, error);
+}
+
void onyx_report_error(OnyxFilePos pos, char * format, ...) {
va_list vargs;
bh_arr_push(errors.errors, err);
}
+void onyx_submit_warning(OnyxError error) {
+ bh_file_contents file_contents = { 0 };
+ bh_arr_each(bh_file_contents, fc, *errors.file_contents) {
+ if (!strcmp(fc->filename, error.pos.filename)) {
+ file_contents = *fc;
+ break;
+ }
+ }
+
+ print_detailed_message(&error, &file_contents);
+}
+
+// This definitely doesn't do what I thought it did?
void onyx_report_warning(OnyxFilePos pos, char* format, ...) {
va_list vargs;
va_start(vargs, format);
#include "errors.h"
#include "parser.h"
#include "astnodes.h"
+#include "errors.h"
bh_scratch global_scratch;
bh_allocator global_scratch_allocator;
}
assert(overload->type->kind == Type_Kind_Function);
+ arguments_remove_baked(&args);
+ arguments_ensure_length(&args, function_get_minimum_argument_count(&overload->type->Function, &args));
+
// NOTE: If the arguments cannot be placed successfully in the parameters list
if (!fill_in_arguments(&args, (AstNode *) overload, NULL)) continue;
-
- TypeFunction* ol_type = &overload->type->Function;
- if (bh_arr_length(args.values) < (i32) ol_type->needed_param_count) continue;
-
- b32 all_arguments_work = 1;
- fori (i, 0, bh_arr_length(args.values)) {
- if (i >= ol_type->param_count) {
- all_arguments_work = 0;
- break;
- }
-
- Type* type_to_match = ol_type->params[i];
- AstTyped** value = &args.values[i];
-
- if (type_to_match->kind == Type_Kind_VarArgs) type_to_match = type_to_match->VarArgs.elem;
- if ((*value)->kind == Ast_Kind_Argument) {
- // :ArgumentResolvingIsComplicated
- if (((AstArgument *) (*value))->is_baked) continue;
- value = &((AstArgument *) *value)->value;
- }
-
- if (!unify_node_and_type_(value, type_to_match, 0)) {
- all_arguments_work = 0;
- break;
- }
- }
-
- if (all_arguments_work) {
+
+ VarArgKind va_kind;
+ if (check_arguments_against_type(&args, &overload->type->Function, &va_kind, NULL, NULL, NULL)) {
matched_overload = node;
break;
}
return 0x7fffffff;
}
+static i32 non_baked_argument_count(Arguments* args) {
+ if (args->used_argument_count >= 0) return args->used_argument_count;
+
+ i32 count = 0;
+
+ bh_arr_each(AstTyped *, actual, args->values) {
+ if ((*actual)->kind != Ast_Kind_Argument) count++;
+ else if (!((AstArgument *) (*actual))->is_baked) count++;
+ }
+
+ bh_arr_each(AstNamedValue *, named_value, args->named_values) {
+ if ((*named_value)->value->kind != Ast_Kind_Argument) count++;
+ else if (!((AstArgument *) (*named_value)->value)->is_baked) count++;
+ }
+
+ args->used_argument_count = count;
+ return count;
+}
+
+i32 function_get_minimum_argument_count(TypeFunction* type, Arguments* args) {
+ i32 non_vararg_param_count = (i32) type->param_count;
+ if (non_vararg_param_count > 0 && type->params[type->param_count - 1] == builtin_vararg_type_type)
+ non_vararg_param_count--;
+
+ return bh_max(non_vararg_param_count, non_baked_argument_count(args));
+}
+
// NOTE: The values array can be partially filled out, and is the resulting array.
// Returns if all the values were filled in.
b32 fill_in_arguments(Arguments* args, AstNode* provider, char** err_msg) {
// assert(idx < bh_arr_length(args->values));
if (idx >= bh_arr_length(args->values)) {
+ if (err_msg) *err_msg = bh_aprintf(global_scratch_allocator, "Error placing value with name '%s' at index '%d'.", named_value->token->text, idx);
token_toggle_end(named_value->token);
return 0;
}
fori (idx, 0, bh_arr_length(args->values)) {
if (args->values[idx] == NULL) args->values[idx] = (AstTyped *) lookup_default_value_by_idx(provider, idx);
if (args->values[idx] == NULL) {
- *err_msg = bh_aprintf(global_scratch_allocator, "No value given for %d%s argument.", idx + 1, bh_num_suffix(idx + 1));
+ if (err_msg) *err_msg = bh_aprintf(global_scratch_allocator, "No value given for %d%s argument.", idx + 1, bh_num_suffix(idx + 1));
success = 0;
}
}
i32 maximum_arguments = maximum_argument_count(provider);
if (bh_arr_length(args->values) > maximum_arguments) {
- *err_msg = bh_aprintf(global_scratch_allocator, "Too many values provided. Expected at most %d.", maximum_arguments);
+ if (err_msg) *err_msg = bh_aprintf(global_scratch_allocator, "Too many values provided. Expected at most %d.", maximum_arguments);
success = 0;
}
return success;
}
+
+//
+// Argument checking
+//
+
+typedef enum ArgState {
+ AS_Expecting_Exact,
+ AS_Expecting_Typed_VA,
+ AS_Expecting_Untyped_VA,
+} ArgState;
+
+b32 check_arguments_against_type(Arguments* args, TypeFunction* func_type, VarArgKind* va_kind,
+ OnyxToken* location, char* func_name, OnyxError* error) {
+ b32 permanent = location != NULL;
+ if (func_name == NULL) func_name = "UNKNOWN FUNCTION";
+
+ bh_arr(AstArgument *) arg_arr = (bh_arr(AstArgument *)) args->values;
+ i32 arg_count = function_get_minimum_argument_count(func_type, args);
+
+ Type **formal_params = func_type->params;
+ Type* variadic_type = NULL;
+ i64 any_type_id = type_build_from_ast(context.ast_alloc, builtin_any_type)->id;
+
+ ArgState arg_state = AS_Expecting_Exact;
+ u32 arg_pos = 0;
+ while (1) {
+ switch (arg_state) {
+ case AS_Expecting_Exact: {
+ if (arg_pos >= func_type->param_count) goto type_checking_done;
+
+ if (formal_params[arg_pos]->kind == Type_Kind_VarArgs) {
+ variadic_type = formal_params[arg_pos]->VarArgs.elem;
+ arg_state = AS_Expecting_Typed_VA;
+ continue;
+ }
+
+ if ((i16) arg_pos == func_type->vararg_arg_pos) {
+ arg_state = AS_Expecting_Untyped_VA;
+ continue;
+ }
+
+ if (arg_pos >= (u32) bh_arr_length(arg_arr)) goto type_checking_done;
+
+ assert(arg_arr[arg_pos]->kind == Ast_Kind_Argument);
+ if (!unify_node_and_type_(&arg_arr[arg_pos]->value, formal_params[arg_pos], permanent)) {
+ if (error != NULL) {
+ error->pos = arg_arr[arg_pos]->token->pos,
+ error->text = bh_aprintf(global_heap_allocator,
+ "The procedure '%s' expects a value of type '%s' for %d%s parameter, got '%s'.",
+ func_name,
+ type_get_name(formal_params[arg_pos]),
+ arg_pos + 1,
+ bh_num_suffix(arg_pos + 1),
+ node_get_type_name(arg_arr[arg_pos]->value));
+ }
+ return 0;
+ }
+
+ arg_arr[arg_pos]->va_kind = VA_Kind_Not_VA;
+ break;
+ }
+
+ case AS_Expecting_Typed_VA: {
+ if (variadic_type->id == any_type_id) *va_kind = VA_Kind_Any;
+
+ if (arg_pos >= (u32) bh_arr_length(arg_arr)) goto type_checking_done;
+
+ if (variadic_type->id == any_type_id) {
+ resolve_expression_type(arg_arr[arg_pos]->value);
+ arg_arr[arg_pos]->va_kind = VA_Kind_Any;
+ break;
+ }
+
+ *va_kind = VA_Kind_Typed;
+
+ assert(arg_arr[arg_pos]->kind == Ast_Kind_Argument);
+ if (!unify_node_and_type_(&arg_arr[arg_pos]->value, variadic_type, permanent)) {
+ if (error != NULL) {
+ error->pos = arg_arr[arg_pos]->token->pos,
+ error->text = bh_aprintf(global_heap_allocator,
+ "The procedure '%s' expects a value of type '%s' for the variadic parameter, got '%s'.",
+ func_name,
+ type_get_name(variadic_type),
+ node_get_type_name(arg_arr[arg_pos]->value));
+ }
+ return 0;
+ }
+
+ arg_arr[arg_pos]->va_kind = VA_Kind_Typed;
+ break;
+ }
+
+ case AS_Expecting_Untyped_VA: {
+ *va_kind = VA_Kind_Untyped;
+
+ if (arg_pos >= (u32) bh_arr_length(arg_arr)) goto type_checking_done;
+
+ assert(arg_arr[arg_pos]->kind == Ast_Kind_Argument);
+ resolve_expression_type(arg_arr[arg_pos]->value);
+ if (arg_arr[arg_pos]->value->type == NULL) {
+ if (error != NULL) {
+ error->pos = arg_arr[arg_pos]->token->pos;
+ error->text = "Unable to resolve type for argument.";
+ }
+ return 0;
+ }
+
+ arg_arr[arg_pos]->va_kind = VA_Kind_Untyped;
+ break;
+ }
+ }
+
+ arg_pos++;
+ }
+
+type_checking_done:
+ if (arg_pos < func_type->needed_param_count) {
+ if (error != NULL) {
+ error->pos = location->pos;
+ error->text = "Too few arguments to function call.";
+ }
+ return 0;
+ }
+
+ if (arg_pos < (u32) arg_count) {
+ if (error != NULL) {
+ error->pos = location->pos;
+ error->text = bh_aprintf(global_heap_allocator, "Too many arguments to function call. %d %d", arg_pos, arg_count);
+ }
+ return 0;
+ }
+
+ return 1;
+}
+
+
+
+
+
//
// String parsing helpers
//
// Clear the normal deferred statements
emit_deferred_stmts(mod, &code);
- // Clear the rest of the deferred statements
- if (bh_arr_length(mod->deferred_stmts) > 0) {
- i32 i = bh_arr_length(mod->deferred_stmts) - 1;
- while (i >= 0) {
- emit_deferred_stmt(mod, &code, mod->deferred_stmts[i]);
- i--;
- }
- }
-
i64 jump_label = get_structured_jump_label(mod, Jump_Type_Return, 1);
if (jump_label >= 0) {
WIL(WI_JUMP, jump_label);
} else {
+ // Clear the rest of the deferred statements
+ if (bh_arr_length(mod->deferred_stmts) > 0) {
+ i32 i = bh_arr_length(mod->deferred_stmts) - 1;
+ while (i >= 0) {
+ emit_deferred_stmt(mod, &code, mod->deferred_stmts[i]);
+ i--;
+ }
+ }
+
// Make a patch for the two instructions needed to restore the stack pointer
SUBMIT_PATCH(mod->stack_leave_patches, 0);
WI(WI_NOP);
=========================
false true false true true false true
true false false true true false true
+MATCHED X
+MATCHED Y
+MATCHED Z [ 10, 40, 90 ]
// This currently does not work and would require a lot of rewriting of compiler internals to make work.
- // named_baked_overloaded_parameters :: proc {
- // ($T: type_expr, x: T) do { println("MATCHED X"); },
- // ($T: type_expr, y: [$N] T) do { println("MATCHED X"); },
- // ($T: type_expr, z: T) do { println("MATCHED X"); },
- // }
-
- // named_baked_overloaded_parameters(i32, 10);
- // named_baked_overloaded_parameters(i32, u32.[ 10, 20, 30 ]);
- // named_baked_overloaded_parameters(i32, z = u32.[ 10, 20, 30 ]);
+ named_baked_overloaded_parameters :: #match {
+ ($T: type_expr, x: T) { println("MATCHED X"); },
+ ($T: type_expr, y: [$N] T) { println("MATCHED Y"); },
+ ($T: type_expr, z: [$N] T) { printf("MATCHED Z {}\n", z); },
+ }
+
+ named_baked_overloaded_parameters(i32, 10);
+ named_baked_overloaded_parameters(i32, u32.[ 10, 20, 30 ]);
+ named_baked_overloaded_parameters(i32, z = u32.[ 10, 40, 90 ]);
}