Another way phrases can be invoked is as timed events, which need no special Inform data structure and are simply compiled into a pair of timetable I6 arrays to be processed at run-time.


§1. Definitions.

§2. The timing of an event records the time at which a phrase should spontaneously happen. This is ordinarily a time value, in minutes from 12 midnight, for a phrase happening at a specific time — for instance, one defined as "At 9:00 AM: ..." But two values are special:

    define NOT_A_TIMED_EVENT -1 as for the vast majority of phrases
    define NO_FIXED_TIME -2 for phrases like "When the clock strikes: ..."
    define NOT_AN_EVENT -3 not even syntactically

§3. And here we record where events are used:

    typedef struct use_as_event {
        struct parse_node *where_triggered; sentence which specifies when this occurs
        struct use_as_event *next;
        MEMORY_MANAGEMENT
    } use_as_event;

The structure use_as_event is accessed in 3/pd, 5/lp, 5/ut, 5/un, 5/ins, 6/rlt, 6/nv, 7/ns, 7/oaf, 7/rs, 9/tfa, 9/tbath, 9/rpt, 9/tc, 9/ma, 9/rk, 9/ass, 9/imp, 9/pd, 10/teav, 10/cap, 11/ap, 11/pr, 11/bas, 11/tc, 11/sm, 12/dtd, 12/cdp, 14/rv, 14/lv, 14/cn, 14/ds, 14/ds2, 15/cp, 16/is, 16/in, 19/tb, 19/rsft, 19/tod, 20/eq, 21/rl, 21/rl2, 21/fao, 21/rps, 21/sv, 21/ac, 22/ph, 22/tp, 23/ad, 24/lv, 24/sf, 25/in, 25/pi, 25/cii, 25/cp, 26/uo, 26/tti, 26/pc, 26/ts, 27/cm and here.

§4. Timed events are stored in two simple arrays, processed by run-time code.

    void Phrases::Timed::TimedEventsTable(void) {
        inter_name *iname = Hierarchy::find(TIMEDEVENTSTABLE_HL);
        packaging_state save = Emit::named_table_array_begin(iname, K_value);
        int when_count = 0;
        phrase *ph;
        LOOP_OVER(ph, phrase) {
            int t = Phrases::Usage::get_timing_of_event(&(ph->usage_data));
            if (t == NOT_A_TIMED_EVENT) continue;
            if (t == NO_FIXED_TIME) when_count++;
            else Emit::array_iname_entry(Phrases::iname(ph));
        }

        for (int i=0; i<when_count+1; i++) {
            Emit::array_numeric_entry(0);
            Emit::array_numeric_entry(0);
        }
        Emit::array_end(save);
        Hierarchy::make_available(Emit::tree(), iname);
    }

    void Phrases::Timed::TimedEventTimesTable(void) {
        inter_name *iname = Hierarchy::find(TIMEDEVENTTIMESTABLE_HL);
        packaging_state save = Emit::named_table_array_begin(iname, K_number);
        int when_count = 0;
        phrase *ph;
        LOOP_OVER(ph, phrase) {
            int t = Phrases::Usage::get_timing_of_event(&(ph->usage_data));
            if (t == NOT_A_TIMED_EVENT) continue;
            if (t == NO_FIXED_TIME) when_count++;
            else Emit::array_numeric_entry((inter_t) t);
        }

        for (int i=0; i<when_count+1; i++) {
            Emit::array_numeric_entry(0);
            Emit::array_numeric_entry(0);
        }
        Emit::array_end(save);
        Hierarchy::make_available(Emit::tree(), iname);
    }

The function Phrases::Timed::TimedEventsTable is used in 1/htc (§2.8), 22/cs (§11).

The function Phrases::Timed::TimedEventTimesTable is used in 1/htc (§2.8), 22/cs (§11).

§5. That's it, really: everything else is just indexing.

    void Phrases::Timed::note_usage(phrase *ph, parse_node *at) {
        int t = Phrases::Usage::get_timing_of_event(&(ph->usage_data));
        if (t == NO_FIXED_TIME) {
            use_as_event *uae = CREATE(use_as_event);
            uae->where_triggered = at;
            uae->next = NULL;
            use_as_event *prev = ph->usage_data.uses_as_event;
            if (prev == NULL) ph->usage_data.uses_as_event = uae;
            else {
                while ((prev) && (prev->next)) prev = prev->next;
                prev->next = uae;
            }
        }
    }

The function Phrases::Timed::note_usage is used in 25/cii (§3.1.1.4.12).

§6. An interesting case where the Problem is arguably only a warning and arguably shouldn't block compilation. Then again...

    void Phrases::Timed::check_for_unused(void) {
        phrase *ph;
        LOOP_OVER(ph, phrase)
            if (Phrases::Usage::get_timing_of_event(&(ph->usage_data)) == NO_FIXED_TIME) {
                if (ph->usage_data.uses_as_event == NULL) {
                    current_sentence = ph->declaration_node;
                    Problems::Issue::sentence_problem(Task::syntax_tree(), _p_(PM_UnusedTimedEvent),
                        "this sets up a timed event which is never used",
                        "since you never use any of the phrases which could cause it. "
                        "(A timed event is just a name, and it needs other instructions "
                        "elsewhere before it can have any effect.)");
                }
            }
    }

The function Phrases::Timed::check_for_unused is used in 1/htc (§2.8).

§7. And here's the actual index segment.

    void Phrases::Timed::index(OUTPUT_STREAM) {
        int when_count = 0, tt_count = 0;
        <Index events with no specific time 7.1>;
        <Index timetabled events 7.2>;
        if ((when_count == 0) && (tt_count == 0)) {
            HTML_OPEN("p"); WRITE("<i>None.</i>"); HTML_CLOSE("p");
        }
    }

The function Phrases::Timed::index appears nowhere else.

§7.1. <Index events with no specific time 7.1> =

        phrase *ph;
        LOOP_OVER(ph, phrase) {
            int t = Phrases::Usage::get_timing_of_event(&(ph->usage_data));
            if (t == NO_FIXED_TIME) {
                if (when_count == 0) {
                    HTML_OPEN("p");
                    WRITE("<i>Events with no specific time</i>");
                    HTML_CLOSE("p");
                }
                when_count++;
                HTML_OPEN_WITH("p", "class=\"tightin2\"");
                Phrases::Usage::index_preamble(OUT, &(ph->usage_data));
                if ((ph->declaration_node) &&
                    (Wordings::nonempty(ParseTree::get_text(ph->declaration_node))))
                    Index::link(OUT, Wordings::first_wn(ParseTree::get_text(ph->declaration_node)));
                WRITE(" (where triggered: ");
                use_as_event *uae;
                for (uae = ph->usage_data.uses_as_event; uae; uae=uae->next)
                    Index::link(OUT, Wordings::first_wn(ParseTree::get_text(uae->where_triggered)));
                WRITE(")");
                HTML_CLOSE("p");
            }
        }

This code is used in §7.

§7.2. <Index timetabled events 7.2> =

        phrase *ph;
        LOOP_OVER(ph, phrase) {
            int t = Phrases::Usage::get_timing_of_event(&(ph->usage_data));
            if (t >= 0) { i.e., an actual time of day in minutes since midnight
                if (tt_count == 0) {
                    HTML_OPEN("p");
                    WRITE("<i>Timetable</i>");
                    HTML_CLOSE("p");
                }
                tt_count++;
                HTML_OPEN_WITH("p", "class=\"in2\"");
                Phrases::Usage::index_preamble(OUT, &(ph->usage_data));
                if ((ph->declaration_node) &&
                    (Wordings::nonempty(ParseTree::get_text(ph->declaration_node))))
                    Index::link(OUT, Wordings::first_wn(ParseTree::get_text(ph->declaration_node)));
                HTML_CLOSE("p");
            }
        }

This code is used in §7.