Special sentences for inserting low-level material written in Inform 6 notation.

§1. Very early on in the life of Inform 7, features were added to allow users to glue in pieces of raw Inform 6 code, as a way of easing the transition for them. In an ideal world, those features would now be removed entirely. The main use case now is that an extension wants to provide a feature with an Inform 7 API, but implemented under the hood with Inform 6. This would be better done with an accompanying kit of Inter code, but at present (2021) that makes such an extension more difficult to distribute.

What is true, however, is that the many nuanced ways to express how such an inclusion could be made were heavily curtailed in 2017. The syntax for these was not made illegal, but simply ignored. All instructions about where I6 code should now go are disregarded; the new code-generator locates such code wherever it wants to.

However, we continue to parse the old syntax, so:

define SEGMENT_LEVEL_INC 1      before, instead of, or after a segment of I6 template
define SECTION_LEVEL_INC 2      before, instead of, or after a section of I6 template
define WHEN_DEFINING_INC 3      as part of an Object or Class definition
define AS_PREFORM_INC 4         include it not as I6, but as Preform grammar
int inclusion_side, section_inclusion_wn, segment_inclusion_wn;

§2. Note that although Preform inclusions are syntactically like I6 inclusions, and share the grammar above, they're nevertheless a different thing and aren't handled here: if we see one, we ignore it.

<inform6-inclusion-location> ::=
    <inclusion-side> {<quoted-text-without-subs>} |     ==> Segment2.1
    <inclusion-side> {<quoted-text-without-subs>} in {<quoted-text-without-subs>} | ==> Section2.2
    when defining <s-type-expression> |                 ==> { WHEN_DEFINING_INC, RP[1] }
    when defining ... |                                 ==> Issue PM_WhenDefiningUnknown problem2.3
    before the library |                                ==> Issue PM_BeforeTheLibrary problem2.4
    in the preform grammar                              ==> { AS_PREFORM_INC, NULL }

<inclusion-side> ::=
    before |                                            ==> { BEFORE_LINK_STAGE, - }
    instead of |                                        ==> { INSTEAD_LINK_STAGE, - }
    after                                               ==> { AFTER_LINK_STAGE, - }

§2.1. Segment2.1 =

    inclusion_side = R[1]; segment_inclusion_wn = R[2];
    ==> { SEGMENT_LEVEL_INC, NULL };

§2.2. Section2.2 =

    inclusion_side = R[1]; section_inclusion_wn = R[2]; segment_inclusion_wn = R[3];
    ==> { SEGMENT_LEVEL_INC, NULL };

§2.3. Issue PM_WhenDefiningUnknown problem2.3 =

    StandardProblems::sentence_problem(Task::syntax_tree(), _p_(PM_WhenDefiningUnknown),
        "I do not understand what definition you're referring to",
        "so I can't make an Inform 6 inclusion there.");
    ==> { SEGMENT_LEVEL_INC, NULL };

§2.4. Issue PM_BeforeTheLibrary problem2.4 =

    StandardProblems::sentence_problem(Task::syntax_tree(), _p_(PM_BeforeTheLibrary),
        "this syntax was withdrawn in January 2008",
        "in favour of a more finely controlled I6 inclusion command. The effect "
        "you want can probably be achieved by writing 'after \"Definitions.i6t\".' "
        "instead of 'before the library.'");
    ==> { SEGMENT_LEVEL_INC, NULL };

§3. So, then, this function is called on inclusion sentences such as:

Include (- ... -) before "I6 Inclusions" in "Output.i6t".

Those references are now meaningless (I6T files in the sense meant by this syntax no longer exist), but we faithfully parse them before ignoring them.

void InterventionRequests::make(parse_node *PN) {
    current_sentence = PN;
    wording IW = Node::get_text(PN);
     skip to the instructions
    IW = Wordings::trim_first_word(Wordings::trim_first_word(Wordings::trim_first_word(IW)));

    if (Wordings::empty(IW)) {
        There are no specific instructions about where it goes3.1;
    } else {
        int problem = TRUE;
        if (<inform6-inclusion-location>(IW)) {
            problem = FALSE;
            switch (<<r>>) {
                case SEGMENT_LEVEL_INC:
                    It's positioned with respect to a template segment3.2; break;
                case SECTION_LEVEL_INC:
                    It's positioned with respect to a template section3.3; break;
                case WHEN_DEFINING_INC:
                    It's positioned in the middle of a class or object definition3.4; break;
                case AS_PREFORM_INC: return;
            }
        }
        if (problem) Issue problem message for bad inclusion instructions3.5;
    }
}

§3.1. There are no specific instructions about where it goes3.1 =

    InterventionRequests::remember(AFTER_LINK_STAGE, NULL, NULL, PN, NULL);

§3.2. It's positioned with respect to a template segment3.2 =

    Word::dequote(segment_inclusion_wn);
    TEMPORARY_TEXT(seg)
    WRITE_TO(seg, "%W", Wordings::one_word(segment_inclusion_wn));
    InterventionRequests::remember(inclusion_side, seg, NULL, PN, NULL);
    DISCARD_TEXT(seg)

§3.3. It's positioned with respect to a template section3.3 =

    Word::dequote(section_inclusion_wn);
    Word::dequote(segment_inclusion_wn);
    TEMPORARY_TEXT(sec)
    TEMPORARY_TEXT(seg)
    WRITE_TO(sec, "%W", Wordings::one_word(section_inclusion_wn));
    WRITE_TO(seg, "%W", Wordings::one_word(segment_inclusion_wn));
    InterventionRequests::remember(inclusion_side, seg, sec, PN, NULL);
    DISCARD_TEXT(sec)
    DISCARD_TEXT(seg)

§3.4. When it comes to class and object definitions, we don't give the Template code instructions; we remember what's needed ourselves:

It's positioned in the middle of a class or object definition3.4 =

    parse_node *spec = <<rp>>;
    inference_subject *infs = InferenceSubjects::from_specification(spec);
    if (infs) InterventionRequests::remember_for_subject(PN, infs);
    else problem = TRUE;

§3.5. Issue problem message for bad inclusion instructions3.5 =

    StandardProblems::sentence_problem(Task::syntax_tree(), _p_(PM_BadI6Inclusion),
        "this is not a form of I6 code inclusion I recognise",
        "because the clause at the end telling me where to put the code excerpt is not "
        "one of the possibilities I know. The clause can either be blank (in which case "
        "I'll find somewhere sensible to put it), or 'when defining' plus the name of "
        "an object or kind of object, or 'before', 'instead of' or 'after' a double-quoted "
        "name of a template layer segment, or of a part of one. For instance, "
        "'before \"Parser.i6t\".' or 'after \"Pronouns\" in \"Language.i6t\".'");

§4. These requests are not acted on here, they are simply remembered for later action: see Interventions (in runtime).

typedef struct source_text_intervention {
    int stage;  one of the *_LINK_STAGE enumerated constants
    struct text_stream *segment;
    struct text_stream *part;
    struct text_stream *seg;
    struct inference_subject *infs_to_include_with;
    struct text_stream *matter;
    struct parse_node *where_made;
    CLASS_DEFINITION
} source_text_intervention;

source_text_intervention *InterventionRequests::new_sti(parse_node *p) {
    source_text_intervention *sti = CREATE(source_text_intervention);
    sti->where_made = current_sentence;
    sti->stage = AFTER_LINK_STAGE;
    sti->segment = NULL;
    sti->part = NULL;
    wchar_t *sf = Lexer::word_raw_text(Wordings::first_wn(Node::get_text(p)) + 2);
    sti->matter = Str::new();
    WRITE_TO(sti->matter, "%w", sf);
    sti->seg = NULL;
    return sti;
}

void InterventionRequests::remember_for_subject(parse_node *p, inference_subject *infs) {
    source_text_intervention *sti = InterventionRequests::new_sti(p);
    sti->infs_to_include_with = infs;
}

void InterventionRequests::remember(int stage, text_stream *segment, text_stream *part,
    parse_node *p, text_stream *seg) {
    source_text_intervention *sti = InterventionRequests::new_sti(p);
    sti->stage = stage;
    sti->segment = Str::duplicate(segment);
    sti->part = Str::duplicate(part);
    sti->seg = Str::duplicate(seg);
}