A plugin to provide some support for the SHOWME testing command.


§1. Initialising. This doesn't in fact do anything, except to provide one service when it's plugged in.

    void PL::Showme::start(void) {
    }

The function PL::Showme::start appears nowhere else.

§2. Support for the SHOWME command. And here is the one service. We must compile I6 code which looks at the object in the local variable t_0 and prints out useful diagnostic data about its current state. We get to use a local variable na, which stands for "number of attributes", though that's really I6-speak: what we mean is "number of either-or properties in the semicolon-separated list we are currently printing out".

We will show either/or properties first, on their own line, and then value properties.

    void PL::Showme::compile_SHOWME_details(void) {
        if (Plugins::Manage::plugged_in(showme_plugin) == FALSE) return;
        inter_name *iname = Hierarchy::find(SHOWMEDETAILS_HL);
        packaging_state save = Routines::begin(iname);
        inter_symbol *t_0_s = LocalVariables::add_named_call_as_symbol(I"t_0");
        inter_symbol *na_s = LocalVariables::add_named_call_as_symbol(I"na");
        Produce::inv_primitive(Emit::tree(), IFDEBUG_BIP);
        Produce::down(Emit::tree());
            Produce::code(Emit::tree());
            Produce::down(Emit::tree());
                PL::Showme::compile_SHOWME_type(FALSE, t_0_s, na_s);
                PL::Showme::compile_SHOWME_type(TRUE, t_0_s, na_s);
            Produce::up(Emit::tree());
        Produce::up(Emit::tree());
        Routines::end(save);
        Hierarchy::make_available(Emit::tree(), iname);
    }

    void PL::Showme::compile_SHOWME_type(int val, inter_symbol *t_0_s, inter_symbol *na_s) {
        kind *K;
        LOOP_OVER_BASE_KINDS(K)
            if (Kinds::Compare::le(K, K_object))
                PL::Showme::compile_SHOWME_type_subj(val, Kinds::Knowledge::as_subject(K), t_0_s, na_s);
        instance *I;
        LOOP_OVER_OBJECT_INSTANCES(I)
            PL::Showme::compile_SHOWME_type_subj(val, Instances::as_subject(I), t_0_s, na_s);
    }

    void PL::Showme::compile_SHOWME_type_subj(int val, inference_subject *subj, inter_symbol *t_0_s, inter_symbol *na_s) {
        <Skip if this object's definition has nothing to offer SHOWME 2.1>;

        Produce::inv_primitive(Emit::tree(), IF_BIP);
        Produce::down(Emit::tree());
            InferenceSubjects::emit_element_of_condition(subj, t_0_s);
            Produce::code(Emit::tree());
            Produce::down(Emit::tree());
                <Divide up the sublists of either/or properties in a SHOWME 2.2>;
                <Compile code which shows properties inherited from this object's definition 2.3>;
            Produce::up(Emit::tree());
        Produce::up(Emit::tree());
    }

The function PL::Showme::compile_SHOWME_details appears nowhere else.

The function PL::Showme::compile_SHOWME_type appears nowhere else.

The function PL::Showme::compile_SHOWME_type_subj appears nowhere else.

§2.1. This simply avoids compiling redundant empty if statements.

<Skip if this object's definition has nothing to offer SHOWME 2.1> =

        int todo = FALSE;
        property *prn;
        LOOP_OVER(prn, property)
            if (Properties::is_value_property(prn) == val)
                if (PL::Showme::is_property_worth_SHOWME(subj, prn, t_0_s, na_s))
                    todo = TRUE;
        if (todo == FALSE) return;

This code is used in §2.

§2.2. In the code running at this point, na holds the number of either/or properties listed since the last time it was zeroed. If it's positive, we need either a semicolon or a line break. If we're about to work on another definition contributing either/or properties, the former; otherwise the latter. Thus we end up with printed output such as

        unlit, inedible, portable; male

where the first sublist of three either/ors comes from "thing", and the second of just one from "person".

<Divide up the sublists of either/or properties in a SHOWME 2.2> =

        text_stream *divider = I"; ";
        if (val) divider = I"\n";
        Produce::inv_primitive(Emit::tree(), IF_BIP);
        Produce::down(Emit::tree());
            Produce::inv_primitive(Emit::tree(), GT_BIP);
            Produce::down(Emit::tree());
                Produce::val_symbol(Emit::tree(), K_value, na_s);
                Produce::val(Emit::tree(), K_number, LITERAL_IVAL, 0);
            Produce::up(Emit::tree());
            Produce::code(Emit::tree());
            Produce::down(Emit::tree());
                Produce::inv_primitive(Emit::tree(), STORE_BIP);
                Produce::down(Emit::tree());
                    Produce::ref_symbol(Emit::tree(), K_value, na_s);
                    Produce::val(Emit::tree(), K_number, LITERAL_IVAL, 0);
                Produce::up(Emit::tree());
                Produce::inv_primitive(Emit::tree(), PRINT_BIP);
                Produce::down(Emit::tree());
                    Produce::val_text(Emit::tree(), divider);
                Produce::up(Emit::tree());
            Produce::up(Emit::tree());
        Produce::up(Emit::tree());

This code is used in §2.

§2.3. <Compile code which shows properties inherited from this object's definition 2.3> =

        property *prn;
        LOOP_OVER(prn, property)
            if (Properties::is_value_property(prn) == val)
                PL::Showme::compile_property_SHOWME(subj, prn, t_0_s, na_s);

This code is used in §2.

§3. We actually use the same routine for both testing and compiling:

    int PL::Showme::is_property_worth_SHOWME(inference_subject *subj, property *prn, inter_symbol *t_0_s, inter_symbol *na_s) {
        return PL::Showme::SHOWME_primitive(subj, prn, FALSE, t_0_s, na_s);
    }

    void PL::Showme::compile_property_SHOWME(inference_subject *subj, property *prn, inter_symbol *t_0_s, inter_symbol *na_s) {
        PL::Showme::SHOWME_primitive(subj, prn, TRUE, t_0_s, na_s);
    }

The function PL::Showme::is_property_worth_SHOWME is used in §2.1.

The function PL::Showme::compile_property_SHOWME is used in §2.3.

§4. So here goes.

    int PL::Showme::SHOWME_primitive(inference_subject *subj, property *prn, int comp, inter_symbol *t_0_s, inter_symbol *na_s) {
        if (Properties::is_shown_in_index(prn) == FALSE) return FALSE;
        if (Properties::can_be_compiled(prn) == FALSE) return FALSE;

        inference_subject *parent = InferenceSubjects::narrowest_broader_subject(subj);

        if ((World::Permissions::find(subj, prn, FALSE)) &&
            (World::Permissions::find(parent, prn, TRUE) == FALSE)) {
            if (comp) {
                if (Properties::is_value_property(prn))
                    <Compile the SHOWME printing code for a value property 4.1>
                else
                    <Compile the SHOWME printing code for an either/or property 4.2>;
            }
            return TRUE;
        }
        return FALSE;
    }

The function PL::Showme::SHOWME_primitive is used in §3.

§4.1. In general we print the property value even if it's boringly equal to the default value for the property's kind. For instance, we would print a "number" property even if its value is 0. But we make two exceptions:

<Compile the SHOWME printing code for a value property 4.1> =

        kind *K = Properties::Valued::kind(prn);
        if (K) {
            int require_nonzero = FALSE;
            if ((Properties::Valued::is_used_for_non_typesafe_relation(prn)) ||
                (Kinds::Compare::le(K, K_object)))
                require_nonzero = TRUE;
            if (require_nonzero) {
                Produce::inv_primitive(Emit::tree(), IF_BIP);
                Produce::down(Emit::tree());
                    inter_name *iname = Hierarchy::find(GPROPERTY_HL);
                    Produce::inv_call_iname(Emit::tree(), iname);
                    Produce::down(Emit::tree());
                        Kinds::RunTime::emit_weak_id_as_val(K_object);
                        Produce::val_symbol(Emit::tree(), K_value, t_0_s);
                        Produce::val_iname(Emit::tree(), K_value, Properties::iname(prn));
                    Produce::up(Emit::tree());
                    Produce::code(Emit::tree());
                    Produce::down(Emit::tree());
            }
            <Compile the SHOWME printing of the value of a value property 4.1.1>;
            if (require_nonzero) {
                    Produce::up(Emit::tree());
                Produce::up(Emit::tree());
            }
        }

This code is used in §4.

§4.1.1. <Compile the SHOWME printing of the value of a value property 4.1.1> =

        TEMPORARY_TEXT(T);
        WRITE_TO(T, "%+W: ", prn->name);
        Produce::inv_primitive(Emit::tree(), PRINT_BIP);
        Produce::down(Emit::tree());
            Produce::val_text(Emit::tree(), T);
        Produce::up(Emit::tree());
        DISCARD_TEXT(T);

        if (Kinds::Compare::eq(K, K_text)) {
            Produce::inv_primitive(Emit::tree(), IFELSE_BIP);
            Produce::down(Emit::tree());
                Produce::inv_primitive(Emit::tree(), EQ_BIP);
                Produce::down(Emit::tree());
                    Produce::inv_call_iname(Emit::tree(), Hierarchy::find(TEXT_TY_COMPARE_HL));
                    Produce::down(Emit::tree());
                        Produce::inv_call_iname(Emit::tree(), Hierarchy::find(GPROPERTY_HL));
                        Produce::down(Emit::tree());
                            Kinds::RunTime::emit_weak_id_as_val(K_object);
                            Produce::val_symbol(Emit::tree(), K_value, t_0_s);
                            Produce::val_iname(Emit::tree(), K_value, Properties::iname(prn));
                        Produce::up(Emit::tree());
                        Produce::val_iname(Emit::tree(), K_value, Hierarchy::find(EMPTY_TEXT_VALUE_HL));
                    Produce::up(Emit::tree());
                    Produce::val(Emit::tree(), K_number, LITERAL_IVAL, 0);
                Produce::up(Emit::tree());
                Produce::code(Emit::tree());
                Produce::down(Emit::tree());
                    Produce::inv_primitive(Emit::tree(), PRINT_BIP);
                    Produce::down(Emit::tree());
                        Produce::val_text(Emit::tree(), I"none");
                    Produce::up(Emit::tree());
                Produce::up(Emit::tree());
                Produce::code(Emit::tree());
                Produce::down(Emit::tree());
                    Produce::inv_primitive(Emit::tree(), PRINTCHAR_BIP);
                    Produce::down(Emit::tree());
                        Produce::val(Emit::tree(), K_number, LITERAL_IVAL, '\"');
                    Produce::up(Emit::tree());
                    <Compile the SHOWME of the actual value 4.1.1.1>;
                    Produce::inv_primitive(Emit::tree(), PRINTCHAR_BIP);
                    Produce::down(Emit::tree());
                        Produce::val(Emit::tree(), K_number, LITERAL_IVAL, '\"');
                    Produce::up(Emit::tree());
                Produce::up(Emit::tree());
            Produce::up(Emit::tree());
        } else {
            <Compile the SHOWME of the actual value 4.1.1.1>;
        }

        Produce::inv_primitive(Emit::tree(), PRINT_BIP);
        Produce::down(Emit::tree());
            Produce::val_text(Emit::tree(), I"\n");
        Produce::up(Emit::tree());

This code is used in §4.1.

§4.1.1.1. <Compile the SHOWME of the actual value 4.1.1.1> =

        Produce::inv_primitive(Emit::tree(), INDIRECT1V_BIP);
        Produce::down(Emit::tree());
            Produce::val_iname(Emit::tree(), K_value, Kinds::Behaviour::get_iname(K));
            Produce::inv_call_iname(Emit::tree(), Hierarchy::find(GPROPERTY_HL));
            Produce::down(Emit::tree());
                Kinds::RunTime::emit_weak_id_as_val(K_object);
                Produce::val_symbol(Emit::tree(), K_value, t_0_s);
                Produce::val_iname(Emit::tree(), K_value, Properties::iname(prn));
            Produce::up(Emit::tree());
        Produce::up(Emit::tree());

This code is used in §4.1.1 (twice).

§4.2. The I6 template code is allowed to bar certain either/or properties using AllowInShowme; it typically uses this to block distracting temporary-workspace properties like "marked for listing" whose values have no significance turn by turn.

<Compile the SHOWME printing code for an either/or property 4.2> =

        property *allow = prn;
        if (Properties::EitherOr::stored_in_negation(prn))
            allow = Properties::EitherOr::get_negation(prn);

        Produce::inv_primitive(Emit::tree(), IF_BIP);
        Produce::down(Emit::tree());
            Produce::inv_primitive(Emit::tree(), AND_BIP);
            Produce::down(Emit::tree());
                if (TargetVMs::debug_enabled(Task::vm())) {
                    Produce::inv_call_iname(Emit::tree(), Hierarchy::find(ALLOWINSHOWME_HL));
                    Produce::down(Emit::tree());
                        Produce::val_iname(Emit::tree(), K_value, Properties::iname(prn));
                    Produce::up(Emit::tree());
                } else {
                    Produce::val(Emit::tree(), K_number, LITERAL_IVAL, 0);
                }
                Properties::Emit::emit_has_property(K_value, t_0_s, prn);
            Produce::up(Emit::tree());
            Produce::code(Emit::tree());
            Produce::down(Emit::tree());
                <Compile the comma as needed 4.2.1>;
                TEMPORARY_TEXT(T);
                WRITE_TO(T, "%+W", prn->name);
                Produce::inv_primitive(Emit::tree(), PRINT_BIP);
                Produce::down(Emit::tree());
                    Produce::val_text(Emit::tree(), T);
                Produce::up(Emit::tree());
                DISCARD_TEXT(T);
            Produce::up(Emit::tree());
        Produce::up(Emit::tree());

This code is used in §4.

§4.2.1. <Compile the comma as needed 4.2.1> =

        Produce::inv_primitive(Emit::tree(), IF_BIP);
        Produce::down(Emit::tree());
            Produce::inv_primitive(Emit::tree(), GT_BIP);
            Produce::down(Emit::tree());
                Produce::inv_primitive(Emit::tree(), POSTINCREMENT_BIP);
                Produce::down(Emit::tree());
                    Produce::ref_symbol(Emit::tree(), K_value, na_s);
                Produce::up(Emit::tree());
                Produce::val(Emit::tree(), K_number, LITERAL_IVAL, 0);
            Produce::up(Emit::tree());
            Produce::code(Emit::tree());
            Produce::down(Emit::tree());
                Produce::inv_primitive(Emit::tree(), PRINT_BIP);
                Produce::down(Emit::tree());
                    Produce::val_text(Emit::tree(), I", ");
                Produce::up(Emit::tree());
            Produce::up(Emit::tree());
        Produce::up(Emit::tree());

This code is used in §4.2.