§1.

typedef struct action_compilation_data {
    int translated;
    struct text_stream *translated_name;
    struct inter_name *an_base_iname;  e.g., Take
    struct inter_name *an_iname;  e.g., ##Take
    struct inter_name *an_routine_iname;  e.g., TakeSub
    struct package_request *an_package;
} action_compilation_data;

action_compilation_data RTActions::new_data(wording W) {
    action_compilation_data acd;
    acd.translated = FALSE;
    acd.translated_name = NULL;
    acd.an_iname = NULL;
    acd.an_base_iname = NULL;
    acd.an_routine_iname = NULL;
    acd.an_package = Hierarchy::local_package(ACTIONS_HAP);
    Hierarchy::apply_metadata_from_wording(acd.an_package, ACTION_NAME_METADATA_HL, W);
    return acd;
}

package_request *RTActions::rulebook_package(action_name *an, int RB) {
    return Hierarchy::make_package_in(RB, an->compilation_data.an_package);
}

void RTActions::translate(action_name *an, wording W) {
    if (an->compilation_data.translated) {
        StandardProblems::sentence_problem(Task::syntax_tree(),
            _p_(PM_TranslatesActionAlready),
            "this action has already been translated",
            "so there must be some duplication somewhere.");
        return;
    }
    if (an->compilation_data.an_base_iname)
        internal_error("too late for action base name translation");

    an->compilation_data.translated = TRUE;
    an->compilation_data.translated_name = Str::new();
    WRITE_TO(an->compilation_data.translated_name, "%N", Wordings::first_wn(W));
    LOGIF(ACTION_CREATIONS, "Translated action: $l as %W\n", an, W);
}

inter_name *RTActions::base_iname(action_name *an) {
    if (an->compilation_data.an_base_iname == NULL) {
        if (waiting_action == an)
            an->compilation_data.an_base_iname =
                Hierarchy::make_iname_in(WAIT_HL, an->compilation_data.an_package);
        else if (Str::len(an->compilation_data.translated_name) > 0)
            an->compilation_data.an_base_iname =
                Hierarchy::make_iname_with_specific_translation(TRANSLATED_BASE_NAME_HL, an->compilation_data.translated_name, an->compilation_data.an_package);
        else
            an->compilation_data.an_base_iname =
                Hierarchy::make_iname_with_memo(ACTION_BASE_NAME_HL, an->compilation_data.an_package, ActionNameNames::tensed(an, IS_TENSE));
    }
    return an->compilation_data.an_base_iname;
}

inter_name *RTActions::double_sharp(action_name *an) {
    if (an->compilation_data.an_iname == NULL) {
        an->compilation_data.an_iname =
            Hierarchy::derive_iname_in(DOUBLE_SHARP_NAME_HL, RTActions::base_iname(an), an->compilation_data.an_package);
        Emit::unchecked_numeric_constant(an->compilation_data.an_iname, (inter_ti) an->allocation_id);
        Hierarchy::make_available(an->compilation_data.an_iname);
        Produce::annotate_i(an->compilation_data.an_iname, ACTION_IANN, 1);
    }
    return an->compilation_data.an_iname;
}

inter_name *RTActions::Sub(action_name *an) {
    if (an->compilation_data.an_routine_iname == NULL) {
        an->compilation_data.an_routine_iname =
            Hierarchy::derive_iname_in(PERFORM_FN_HL, RTActions::base_iname(an), an->compilation_data.an_package);
        Hierarchy::make_available(an->compilation_data.an_routine_iname);
    }
    return an->compilation_data.an_routine_iname;
}

inter_name *RTActions::iname(action_name *an) {
    return RTActions::double_sharp(an);
}

text_stream *RTActions::identifier(action_name *an) {
    return InterNames::to_text(RTActions::base_iname(an));
}

void RTActions::compile_action_name_var_creators(void) {
    action_name *an;
    LOOP_OVER(an, action_name) {
        if ((an->action_variables) &&
            (SharedVariables::set_empty(an->action_variables) == FALSE)) {
            inter_name *iname = Hierarchy::make_iname_in(ACTION_STV_CREATOR_FN_HL,
                an->compilation_data.an_package);
            RTVariables::set_shared_variables_creator(an->action_variables, iname);
            RTVariables::compile_frame_creator(an->action_variables);
        }
    }
}

void RTActions::ActionCoding_array(void) {
    inter_name *iname = Hierarchy::find(ACTIONCODING_HL);
    packaging_state save = EmitArrays::begin(iname, K_value);
    action_name *an;
    LOOP_OVER(an, action_name) {
        if (Str::get_first_char(RTActions::identifier(an)) == '_')
            EmitArrays::numeric_entry(0);
        else RTActions::action_array_entry(an);
    }
    EmitArrays::end(save);
    Hierarchy::make_available(iname);
}

parse_node *RTActions::compile_action_bitmap_property(instance *I) {
    package_request *R = NULL;
    inter_name *N = NULL;
    if (I) {
        R = RTInstances::package(I);
        package_request *PR = Hierarchy::package_within(INLINE_PROPERTIES_HAP, R);
        N = Hierarchy::make_iname_in(INLINE_PROPERTY_HL, PR);
    } else {
        R = Kinds::Behaviour::package(K_object);
        package_request *PR = Hierarchy::package_within(KIND_INLINE_PROPERTIES_HAP, R);
        N = Hierarchy::make_iname_in(KIND_INLINE_PROPERTY_HL, PR);
    }
    packaging_state save = EmitArrays::begin(N, K_number);
    for (int i=0; i<=((NUMBER_CREATED(action_name))/16); i++) EmitArrays::numeric_entry(0);
    EmitArrays::end(save);
    Produce::annotate_i(N, INLINE_ARRAY_IANN, 1);
    return Rvalues::from_iname(N);
}

void RTActions::ActionHappened(void) {
    inter_name *iname = Hierarchy::find(ACTIONHAPPENED_HL);
    packaging_state save = EmitArrays::begin(iname, K_number);
    for (int i=0; i<=((NUMBER_CREATED(action_name))/16); i++)
        EmitArrays::numeric_entry(0);
    EmitArrays::end(save);
    Hierarchy::make_available(iname);
}

§2. Compiling data about actions. In I6, there was no common infrastructure for the implementation of actions: each defined its own -Sub routine. Here, we do have a common infrastructure, and we access it with a single call.

void RTActions::compile_action_routines(void) {
    action_name *an;
    LOOP_OVER(an, action_name) {
        inter_name *iname = RTActions::Sub(an);
        packaging_state save = Functions::begin(iname);
        EmitCode::inv(RETURN_BIP);
        EmitCode::down();
            inter_name *generic_iname = Hierarchy::find(GENERICVERBSUB_HL);
            EmitCode::call(generic_iname);
            EmitCode::down();
                EmitCode::val_iname(K_value, an->check_rules->compilation_data.rb_id_iname);
                EmitCode::val_iname(K_value, an->carry_out_rules->compilation_data.rb_id_iname);
                EmitCode::val_iname(K_value, an->report_rules->compilation_data.rb_id_iname);
            EmitCode::up();
        EmitCode::up();
        Functions::end(save);
    }
}

void RTActions::ActionData(void) {
    RTActions::compile_action_name_var_creators();
    action_name *an;
    int mn, ms, ml, mnp, msp, hn, hs, record_count = 0;

    inter_name *iname = Hierarchy::find(ACTIONDATA_HL);
    packaging_state save = EmitArrays::begin_table(iname, K_value);
    LOOP_OVER(an, action_name) {
        mn = 0; ms = 0; ml = 0; mnp = 1; msp = 1; hn = 0; hs = 0;
        if (ActionSemantics::requires_light(an)) ml = 1;
        if (ActionSemantics::noun_access(an) == REQUIRES_ACCESS) mn = 1;
        if (ActionSemantics::second_access(an) == REQUIRES_ACCESS) ms = 1;
        if (ActionSemantics::noun_access(an) == REQUIRES_POSSESSION) { mn = 1; hn = 1; }
        if (ActionSemantics::second_access(an) == REQUIRES_POSSESSION) { ms = 1; hs = 1; }
        if (ActionSemantics::can_have_noun(an) == FALSE) mnp = 0;
        if (ActionSemantics::can_have_second(an) == FALSE) msp = 0;
        record_count++;
        RTActions::action_array_entry(an);
        inter_ti bitmap = (inter_ti) (mn + ms*0x02 + ml*0x04 + mnp*0x08 +
            msp*0x10 + ((ActionSemantics::is_out_of_world(an))?1:0)*0x20 + hn*0x40 + hs*0x80);
        EmitArrays::numeric_entry(bitmap);
        RTKinds::emit_strong_id(ActionSemantics::kind_of_noun(an));
        RTKinds::emit_strong_id(ActionSemantics::kind_of_second(an));
        if ((an->action_variables) &&
                (SharedVariables::set_empty(an->action_variables) == FALSE))
            EmitArrays::iname_entry(RTVariables::get_shared_variables_creator(an->action_variables));
        else EmitArrays::numeric_entry(0);
        EmitArrays::numeric_entry((inter_ti) (RTActions::action_variable_set_ID(an)));
    }
    EmitArrays::end(save);
    Hierarchy::make_available(iname);

    inter_name *ad_iname = Hierarchy::find(AD_RECORDS_HL);
    Emit::numeric_constant(ad_iname, (inter_ti) record_count);
    Hierarchy::make_available(ad_iname);

    inter_name *DB_Action_Details_iname = Hierarchy::find(DB_ACTION_DETAILS_HL);
    save = Functions::begin(DB_Action_Details_iname);
    inter_symbol *act_s = LocalVariables::new_other_as_symbol(I"act");
    inter_symbol *n_s = LocalVariables::new_other_as_symbol(I"n");
    inter_symbol *s_s = LocalVariables::new_other_as_symbol(I"s");
    inter_symbol *for_say_s = LocalVariables::new_other_as_symbol(I"for_say");
    EmitCode::inv(SWITCH_BIP);
    EmitCode::down();
        EmitCode::val_symbol(K_value, act_s);
        EmitCode::code();
        EmitCode::down();

    LOOP_OVER(an, action_name) {
            EmitCode::inv(CASE_BIP);
            EmitCode::down();
                EmitCode::val_iname(K_value, RTActions::double_sharp(an));
                EmitCode::code();
                EmitCode::down();

                int j = Wordings::first_wn(ActionNameNames::tensed(an, IS_TENSE)), j0 = -1, somethings = 0, clc = 0;
                while (j <= Wordings::last_wn(ActionNameNames::tensed(an, IS_TENSE))) {
                    if (<object-pronoun>(Wordings::one_word(j))) {
                        if (j0 >= 0) {
                            Insert a space here if needed to break up the action name2.1;

                            TEMPORARY_TEXT(AT)
                            RTActions::print_action_text_to(Wordings::new(j0, j-1), Wordings::first_wn(ActionNameNames::tensed(an, IS_TENSE)), AT);
                            EmitCode::inv(PRINT_BIP);
                            EmitCode::down();
                                EmitCode::val_text(AT);
                            EmitCode::up();
                            DISCARD_TEXT(AT)

                            j0 = -1;
                        }
                        Insert a space here if needed to break up the action name2.1;
                        EmitCode::inv(IFELSE_BIP);
                        EmitCode::down();
                            EmitCode::inv(EQ_BIP);
                            EmitCode::down();
                                EmitCode::val_symbol(K_value, for_say_s);
                                EmitCode::val_number(2);
                            EmitCode::up();
                            EmitCode::code();
                            EmitCode::down();
                                EmitCode::inv(PRINT_BIP);
                                EmitCode::down();
                                    EmitCode::val_text(I"it");
                                EmitCode::up();
                            EmitCode::up();
                            EmitCode::code();
                            EmitCode::down();
                                RTActions::cat_something2(an, somethings++, n_s, s_s);
                            EmitCode::up();
                        EmitCode::up();
                    } else {
                        if (j0<0) j0 = j;
                    }
                    j++;
                }
                if (j0 >= 0) {
                    Insert a space here if needed to break up the action name2.1;
                    TEMPORARY_TEXT(AT)
                    RTActions::print_action_text_to(Wordings::new(j0, j-1), Wordings::first_wn(ActionNameNames::tensed(an, IS_TENSE)), AT);
                    EmitCode::inv(PRINT_BIP);
                    EmitCode::down();
                        EmitCode::val_text(AT);
                    EmitCode::up();
                    DISCARD_TEXT(AT)
                }
                if (somethings < ActionSemantics::max_parameters(an)) {
                    EmitCode::inv(IF_BIP);
                    EmitCode::down();
                        EmitCode::inv(NE_BIP);
                        EmitCode::down();
                            EmitCode::val_symbol(K_value, for_say_s);
                            EmitCode::val_number(2);
                        EmitCode::up();
                        EmitCode::code();
                        EmitCode::down();
                            Insert a space here if needed to break up the action name2.1;
                            RTActions::cat_something2(an, somethings++, n_s, s_s);
                        EmitCode::up();
                    EmitCode::up();
                }

                EmitCode::up();
            EmitCode::up();
    }

        EmitCode::up();
    EmitCode::up();
    Functions::end(save);
    Hierarchy::make_available(DB_Action_Details_iname);
}

§2.1. Insert a space here if needed to break up the action name2.1 =

    if (clc++ > 0) {
        EmitCode::inv(PRINT_BIP);
        EmitCode::down();
            EmitCode::val_text(I" ");
        EmitCode::up();
    }

§3.

void RTActions::action_array_entry(action_name *an) {
    EmitArrays::iname_entry(RTActions::iname(an));
}

§4.

void RTActions::print_action_text_to(wording W, int start, OUTPUT_STREAM) {
    if (Wordings::first_wn(W) == start) {
        WRITE("%W", Wordings::first_word(W));
        W = Wordings::trim_first_word(W);
        if (Wordings::empty(W)) return;
        WRITE(" ");
    }
    WRITE("%+W", W);
}

§5.

void RTActions::cat_something2(action_name *an, int n, inter_symbol *n_s, inter_symbol *s_s) {
    kind *K = ActionSemantics::kind_of_noun(an);
    inter_symbol *var = n_s;
    if (n > 0) {
        K = ActionSemantics::kind_of_second(an); var = s_s;
    }
    if (Kinds::Behaviour::is_object(K) == FALSE)
        var = InterNames::to_symbol(Hierarchy::find(PARSED_NUMBER_HL));
    EmitCode::inv(INDIRECT1V_BIP);
    EmitCode::down();
        EmitCode::val_iname(K_value, Kinds::Behaviour::get_name_of_printing_rule_ACTIONS(K));
        if ((K_understanding) && (Kinds::eq(K, K_understanding))) {
            EmitCode::inv(PLUS_BIP);
            EmitCode::down();
                EmitCode::inv(TIMES_BIP);
                EmitCode::down();
                    EmitCode::val_number(100);
                    EmitCode::val_iname(K_number, Hierarchy::find(CONSULT_FROM_HL));
                EmitCode::up();
                EmitCode::val_iname(K_number, Hierarchy::find(CONSULT_WORDS_HL));
            EmitCode::up();
        } else {
            EmitCode::val_symbol(K_value, var);
        }
    EmitCode::up();
}

int RTActions::actions_compile_constant(value_holster *VH, kind *K, parse_node *spec) {
    if (PluginManager::active(actions_plugin) == FALSE)
        internal_error("actions plugin inactive");
    if (Kinds::eq(K, K_action_name)) {
        action_name *an = ARvalues::to_action_name(spec);
        if (Holsters::non_void_context(VH)) {
            inter_name *N = RTActions::iname(an);
            if (N) Emit::holster_iname(VH, N);
        }
        return TRUE;
    }
    if (Kinds::eq(K, K_description_of_action)) {
        action_pattern *ap = Node::get_constant_action_pattern(spec);
        RTActionPatterns::compile_pattern_match(VH, ap, FALSE);
        return TRUE;
    }
    if (Kinds::eq(K, K_stored_action)) {
        explicit_action *ea = Node::get_constant_explicit_action(spec);
        if (CompileValues::compiling_in_constant_mode())
            RTActionPatterns::as_stored_action(VH, ea);
        else {
            RTActionPatterns::emit_try(ea, TRUE);
        }
        return TRUE;
    }
    return FALSE;
}

int RTActions::action_variable_set_ID(action_name *an) {
    return 20000 + an->allocation_id;
}

void RTActions::emit_anl(action_name_list *head) {
    int C = ActionNameLists::length(head);
    if (C == 0) return;
    LOGIF(ACTION_PATTERN_COMPILATION, "Emitting action name list: $L", head);

    int neg = ActionNameLists::itemwise_negated(head);
    if (neg) { EmitCode::inv(NOT_BIP); EmitCode::down(); }

    int N = 0, downs = 0;
    LOOP_THROUGH_ANL(L, head) {
        N++;
        if (N < C) { EmitCode::inv(OR_BIP); EmitCode::down(); downs++; }
        if (L->item.nap_listed) {
            EmitCode::inv(INDIRECT0_BIP);
            EmitCode::down();
                EmitCode::val_iname(K_value, RTNamedActionPatterns::identifier(L->item.nap_listed));
            EmitCode::up();
        } else {
            EmitCode::inv(EQ_BIP);
            EmitCode::down();
                EmitCode::val_iname(K_value, Hierarchy::find(ACTION_HL));
                EmitCode::val_iname(K_value, RTActions::double_sharp(L->item.action_listed));
            EmitCode::up();
        }
    }
    while (downs > 0) { EmitCode::up(); downs--; }

    if (neg) EmitCode::up();
}

§6.

int RTActions::is_an_action_variable(parse_node *spec) {
    nonlocal_variable *nlv;
    if (spec == NULL) return FALSE;
    if (Lvalues::get_storage_form(spec) != NONLOCAL_VARIABLE_NT) return FALSE;
    nlv = Node::get_constant_nonlocal_variable(spec);
    if (nlv == Inter_noun_VAR) return TRUE;
    if (nlv == Inter_second_noun_VAR) return TRUE;
    if (nlv == Inter_actor_VAR) return TRUE;
    return FALSE;
}