Here we generate Inform 6 code to execute the phrase(s) called for by an invocation list.

§1. Compiling an invocation by a function call is simple:

void Invocations::AsCalls::csi_by_call(value_holster *VH, parse_node *inv,
    source_location *where_from, tokens_packet *tokens) {
    phrase *ph = Node::get_phrase_invoked(inv);

    inter_name *IS = Routines::Compile::iname(ph,
        Routines::ToPhrases::make_request(ph, tokens->as_requested,
            Node::get_kind_variable_declarations(inv), Node::get_text(inv)));
    LOGIF(MATCHING, "Calling routine %n with kind %u from $e\n", IS,
        tokens->as_requested, inv);

    int options_supplied = Invocations::get_phrase_options_bitmap(inv);
    if (Node::get_phrase_options_invoked(inv) == NULL) options_supplied = -1;

    if (VH->vhmode_wanted == INTER_VAL_VHMODE) VH->vhmode_provided = INTER_VAL_VHMODE;
    else VH->vhmode_provided = INTER_VOID_VHMODE;
    Invocations::AsCalls::emit_function_call(tokens, IS, options_supplied, NULL, FALSE);
}

§2. The following can be used to call any phrase compiled to an I6 routine, and it's used not only by the code above, but also when calling a phrase value stored dynamically at run-time.

void Invocations::AsCalls::emit_function_call(
    tokens_packet *tokens, inter_name *identifier, int phrase_options,
    parse_node *indirect_spec, int lookup_flag) {

    kind *return_kind = NULL;
    Compute the return kind of the phrase2.2;

    BEGIN_COMPILATION_MODE;
    COMPILATION_MODE_ENTER(DEREFERENCE_POINTERS_CMODE);

    if (identifier) {
        Produce::inv_call_iname(Emit::tree(), identifier);
        Produce::down(Emit::tree());
    } else if (indirect_spec) {
        int arity = tokens->tokens_count;
        if (Kinds::Behaviour::uses_pointer_values(return_kind)) arity++;
        switch (arity) {
            case 0: Produce::inv_primitive(Emit::tree(), INDIRECT0_BIP); break;
            case 1: Produce::inv_primitive(Emit::tree(), INDIRECT1_BIP); break;
            case 2: Produce::inv_primitive(Emit::tree(), INDIRECT2_BIP); break;
            case 3: Produce::inv_primitive(Emit::tree(), INDIRECT3_BIP); break;
            case 4: Produce::inv_primitive(Emit::tree(), INDIRECT4_BIP); break;
            default: internal_error("indirect function call with too many arguments");
        }
        Produce::down(Emit::tree());
        if (lookup_flag) {
            Produce::inv_primitive(Emit::tree(), LOOKUP_BIP);
            Produce::down(Emit::tree());
                Specifications::Compiler::emit_as_val(K_value, indirect_spec);
                Produce::val(Emit::tree(), K_number, LITERAL_IVAL, 1);
            Produce::up(Emit::tree());
        } else {
            Specifications::Compiler::emit_as_val(K_value, indirect_spec);
        }
    } else internal_error("emit function call improperly called");
        Emit the comma-separated list of arguments2.1;
    Produce::up(Emit::tree());

    END_COMPILATION_MODE;
}

§2.1. See the corresponding code for defining routines. If the return value of the phrase is a block value, we must call it with a pointer to a new value of that kind as the first argument. Arguments corresponding to the tokens then follow, and finally the optional bitmap of phrase options.

Emit the comma-separated list of arguments2.1 =

    if (Kinds::Behaviour::uses_pointer_values(return_kind))
        Frames::emit_allocation(return_kind);
    for (int k=0; k<tokens->tokens_count; k++)
        Specifications::Compiler::emit_to_kind(tokens->args[k], tokens->kind_required[k]);
    if (phrase_options != -1)
        Produce::val(Emit::tree(), K_number, LITERAL_IVAL, (inter_ti) phrase_options);

§2.2. Compute the return kind of the phrase2.2 =

    kind *K = tokens->as_requested;
    kind *args = NULL;
    if (Kinds::get_construct(K) != CON_phrase) internal_error("no function kind");
    Kinds::binary_construction_material(K, &args, &return_kind);