return count;
}
-typedef enum ArgState {
- AS_Expecting_Exact,
- AS_Expecting_Typed_VA,
- AS_Expecting_Untyped_VA,
-} ArgState;
+static CheckStatus check_resolve_callee(AstCall* call, AstTyped** effective_callee) {
+ if (call->kind == Ast_Kind_Intrinsic_Call) return Check_Success;
-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
- // 2. Check the callee expression (since it could be a variable or a field access, etc)
- // 3. Check all arguments
- // * Cannot pass overloaded functions (ROBUSTNESS)
- // 4. If callee is an overloaded function, use the argument types to determine which overload is used.
- // 5. If callee is polymorphic, use the arguments type to generate a polymorphic function.
- // 7. Fill in arguments
- // 8. If callee is an intrinsic, turn call into an Intrinsic_Call node
- // 9. Check types of formal and actual params against each other, handling varargs
- AstCall* call = *pcall;
-
- if (call->flags & Ast_Flag_Has_Been_Checked) return Check_Success;
+ while (call->callee->kind == Ast_Kind_Alias)
+ call->callee = ((AstAlias *) call->callee)->alias;
- u32 current_checking_level_store = current_checking_level;
- CHECK(expression, &call->callee);
- CHECK(arguments, &call->args);
- current_checking_level = current_checking_level_store;
-
- // SPEED CLEANUP: Keeping an original copy for basically no reason except that sometimes you
- // need to know the baked argument values in code generation.
- // This should only be done once, but right now it is being done everytime this is checked,
- // which can be multiple if we have to yield on a callee's type.
- arguments_clone(&call->original_args, &call->args);
-
- while (call->callee->kind == Ast_Kind_Alias) call->callee = ((AstAlias *) call->callee)->alias;
-
- AstTyped *effective_callee = call->callee;
-
- // If we are "calling" a macro, the callee on the call node should not be replaced
- // as then it would remove the macro from the callee, which would turn it into a
- // normal function call.
+ AstTyped* callee = call->callee;
b32 calling_a_macro = 0;
- if (effective_callee->kind == Ast_Kind_Macro) {
- calling_a_macro = 1;
- if (current_checking_level == EXPRESSION_LEVEL) {
- onyx_report_error(call->token->pos, "Macros calls are not allowed at the expression level yet.");
- return Check_Error;
- }
-
- effective_callee = ((AstMacro * ) effective_callee)->body;
- }
-
- if (effective_callee->kind == Ast_Kind_Overloaded_Function) {
+ if (callee->kind == Ast_Kind_Overloaded_Function) {
b32 should_yield = 0;
- AstTyped* new_callee = find_matching_overload_by_arguments(((AstOverloadedFunction *) effective_callee)->overloads, &call->args, &should_yield);
+ AstTyped* new_callee = find_matching_overload_by_arguments(
+ ((AstOverloadedFunction *) callee)->overloads,
+ &call->args,
+ &should_yield);
+
if (new_callee == NULL) {
- if (effective_callee->entity->state > Entity_State_Check_Types && !should_yield) {
+ if (callee->entity->state > Entity_State_Check_Types && !should_yield) {
report_unable_to_match_overload(call);
return Check_Error;
}
}
- effective_callee = new_callee;
- if (!calling_a_macro) call->callee = new_callee;
+ callee = new_callee;
}
- if (effective_callee->kind == Ast_Kind_Polymorphic_Proc) {
- AstTyped* new_callee = (AstTyped *) polymorphic_proc_lookup((AstPolyProc *) effective_callee, PPLM_By_Arguments, &call->args, call->token);
+ if (callee->kind == Ast_Kind_Macro) {
+ if (current_checking_level == EXPRESSION_LEVEL) {
+ onyx_report_error(call->token->pos, "Macros calls are not allowed at the expression level yet.");
+ return Check_Error;
+ }
+
+ calling_a_macro = 1;
+ call->callee = callee;
+ callee = ((AstMacro *) callee)->body;
+
+ if (callee->kind == Ast_Kind_Polymorphic_Proc) {
+ onyx_report_error(call->token->pos, "Cannot call polymorphic macros... yet.");
+ return Check_Error;
+ }
+
+ } else if (callee->kind == Ast_Kind_Polymorphic_Proc) {
+ AstTyped* new_callee = (AstTyped *) polymorphic_proc_lookup((AstPolyProc *) callee, PPLM_By_Arguments, &call->args, call->token);
if (new_callee == (AstTyped *) &node_that_signals_a_yield) return Check_Yield_Macro;
if (new_callee == NULL) return Check_Error;
arguments_remove_baked(&call->args);
- effective_callee = new_callee;
- if (!calling_a_macro) call->callee = new_callee;
+ callee = new_callee;
}
- AstFunction* callee = (AstFunction *) effective_callee;
+ if (!calling_a_macro) call->callee = callee;
// NOTE: Build callee's type
fill_in_type((AstTyped *) callee);
return Check_Error;
}
+ *effective_callee = callee;
+ 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
+ // 2. Check the callee expression (since it could be a variable or a field access, etc)
+ // 3. Check all arguments
+ // * Cannot pass overloaded functions (ROBUSTNESS)
+ // 4. If callee is an overloaded function, use the argument types to determine which overload is used.
+ // 5. If callee is polymorphic, use the arguments type to generate a polymorphic function.
+ // 7. Fill in arguments
+ // 8. If callee is an intrinsic, turn call into an Intrinsic_Call node
+ // 9. Check types of formal and actual params against each other, handling varargs
+ AstCall* call = *pcall;
+
+ if (call->flags & Ast_Flag_Has_Been_Checked) return Check_Success;
+
+ u32 current_checking_level_store = current_checking_level;
+ CHECK(expression, &call->callee);
+ CHECK(arguments, &call->args);
+ current_checking_level = current_checking_level_store;
+
+ // SPEED CLEANUP: Keeping an original copy for basically no reason except that sometimes you
+ // need to know the baked argument values in code generation.
+ // This should only be done once, but right now it is being done everytime this is checked,
+ // which can be multiple if we have to yield on a callee's type.
+ arguments_clone(&call->original_args, &call->args);
+
+ 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 &&
continue;
}
- // CLEANUP POTENTIAL BUG if the builtin_vararg_type_type is ever rebuilt
if ((i16) arg_pos == callee->type->Function.vararg_arg_pos) {
arg_state = AS_Expecting_Untyped_VA;
continue;
}
arg_arr[arg_pos]->va_kind = VA_Kind_Untyped;
- break;CheckStatus check_compound(AstCompound* compound);
-
+ break;
}
}
return Check_Error;
}
- if (!calling_a_macro) {
- callee->flags |= Ast_Flag_Function_Used;
+ callee->flags |= Ast_Flag_Function_Used;
- } else {
- // Macro expansion
+ if (call->kind == Ast_Kind_Call && call->callee->kind == Ast_Kind_Macro) {
+ expand_macro(pcall);
+ return Check_Return_To_Symres;
}
return Check_Success;
if (node->kind == Ast_Kind_Overloaded_Function) continue;
if ( node->kind != Ast_Kind_Function
- && node->kind != Ast_Kind_Polymorphic_Proc) {
- onyx_report_error(node->token->pos, "Overload option not procedure. Got '%s'",
+ && node->kind != Ast_Kind_Polymorphic_Proc
+ && node->kind != Ast_Kind_Macro) {
+ onyx_report_error(node->token->pos, "Overload option not procedure or macro. Got '%s'",
onyx_ast_node_kind_string(node->kind));
bh_imap_free(&all_overloads);
AstFunction* overload = NULL;
switch (node->kind) {
case Ast_Kind_Function: overload = (AstFunction *) node; break;
+ case Ast_Kind_Macro: overload = (AstFunction *) ((AstMacro *) node)->body; break;
case Ast_Kind_Polymorphic_Proc: overload = polymorphic_proc_build_only_header((AstPolyProc *) node, PPLM_By_Arguments, param_args); break;
}
}
+//
+// Macros
+//
+//
+// TODO: Write this documentation
+void expand_macro(AstCall** pcall) {
+ AstCall* call = *pcall;
+ AstMacro* macro = (AstMacro *) call->callee;
+ assert(macro->kind == Ast_Kind_Macro);
+
+ AstFunction* template = (AstFunction *) macro->body;
+ assert(template->kind == Ast_Kind_Function);
+ assert(template->type != NULL);
+
+ AstBlock* expansion = (AstBlock *) ast_clone(context.ast_alloc, template->body);
+ expansion->rules = Block_Rule_Macro;
+ expansion->scope = NULL;
+ expansion->next = call->next;
+
+ Scope* argument_scope = scope_create(context.ast_alloc, NULL, call->token->pos);
+ if (expansion->binding_scope != NULL)
+ scope_include(argument_scope, expansion->binding_scope, call->token->pos);
+ expansion->binding_scope = argument_scope;
+
+ // HACK HACK HACK This is probably very wrong. I don't know what guarentees that
+ // the paramters and arguments are going to be in the same order exactly.
+ fori (i, 0, bh_arr_length(call->args.values)) {
+ symbol_introduce(argument_scope,
+ template->params[i].local->token,
+ (AstNode *) ((AstArgument *) call->args.values[i])->value);
+ }
+
+ *(AstBlock **) pcall = expansion;
+ return;
+}
//
// Polymorphic Structures
// that types need to be known completely by the time symbol resolution is done, even though that
// information shouldn't need to be known until right before the types are checked.
//
+// The above documentation is very incorrect but I don't want to fix it right now. Basically, polymorphic
+// structures now have a delay instantiation phase and are not forced to be completed immediately.
char* build_poly_struct_name(AstPolyStructType* ps_type, Type* cs_type) {
char name_buf[256];