§1. The following set of functions is an API for the main compiler to consult
with the plugins; put another way, it is also an API for the plugins to
@@ -529,7 +529,24 @@ regions plugin does with the "region" kind.
PLUGINS_CALL(SET_SUBKIND_NOTIFY_PLUG, sub, super);}
-
§34. Influencing the actions plugin. We now have a whole run of functions called only by the actions plugin, and
+
§34. Influencing the imperative plugin. Called from Rule Bookings (in imperative) to give plugins a chance to move
+automatically placed rules from one rulebook to another. The actions plugin
+uses this to break up what would otherwise be unwieldy before and after
+rulebooks into smaller ones for each action.
+
+
+
If making a diversion, the plugin should write the new rulebook into new_owner
+and return TRUE; and otherwise FALSE.
+
§36. Called from Action Pattern Clauses (in if) to invite plugins to change the
action pattern clause ID associated with a given action variable. This may be
needed in order to cross-reference between multiple such clauses, as with
the going action variables.
@@ -558,7 +575,7 @@ the going action variables.
PLUGINS_CALL(DIVERT_AP_CLAUSE_PLUG, stv, id);}
-
§37. Called from Action Pattern Clauses (in if) to ask plugins to print a helpful
name for the debugging log for any new clause ID C which they have created.
@@ -569,7 +586,7 @@ name for the debugging log for any new clause ID PLUGINS_CALL(WRITE_AP_CLAUSE_ID_PLUG, OUT, C);}
-
§38. Called from Action Pattern Clauses (in if) to ask for the *_APCA aspect
for the clause ID C, where C is a new clause ID created by the plugin. If
this is not given, then the aspect will be MISC_APCA.
@@ -581,7 +598,7 @@ this is not given, then the aspect will be PLUGINS_CALL(ASPECT_OF_AP_CLAUSE_ID_PLUG, C, A);}
-
§39. Called from Action Pattern Clauses (in if) to give plugins a chance to
decide which AP is more specific, on the basis of the extra clauses defined
in the plugin.
@@ -605,7 +622,7 @@ to let the usual machinery take its course.
PLUGINS_CALL(COMPARE_AP_SPECIFICITY_PLUG, ap1, ap2, rv, ignore_in);}
-
§41. Called from Parse Clauses (in if) to give plugins a chance to intervene in
the normal process of evaluating the meaning of text in an action pattern
clause: for example, in parsing "going nowhere", the going plugin uses this
to detect that the NOUN_AP_CLAUSE, with text "nowhere", should not be parsed
@@ -635,7 +652,7 @@ text of the clause in the normal way.
PLUGINS_CALL(PARSE_AP_CLAUSE_PLUG, an, c, bits);}
-
§42. Called from Parse Clauses (in if) to give plugins a chance to intervene in
the type-checking process for a clause. Ordinarily, this would just check that
the contents have the right kind: if matching an action variable of kind K
then it must be a value compatible with K or a description of such.
@@ -653,7 +670,7 @@ or FALSE (it is
PLUGINS_CALL(VALIDATE_AP_CLAUSE_PLUG, an, c, outcome);}
-
§44. Called from Action Patterns (in runtime) when assembling the requirement
clauses for compiling a mattern match; this gives plugins a chance to act
extra stipulations, which are not explicit in clauses already in the pattern.
@@ -677,7 +694,7 @@ extra stipulations, which are not explicit in clauses already in the pattern.
PLUGINS_CALL(SET_PATTERN_MATCH_REQUIREMENTS_PLUG, ap, cpm, needed, needed_apoc);}
-
§46. Influencing index. Called from Index Physical World (in index) to add something (if it wishes)
to the index description of an instance in the spatial model. For example,
the regions plugin uses this to put colour chips next to names of regions.
@@ -701,7 +718,7 @@ the regions plugin uses this to put colour chips next to names of regions.
PLUGINS_CALL(ADD_TO_WORLD_INDEX_PLUG, OUT, O);}
-
§47. Called from Index Physical World (in index) to add something (if it wishes)
to the textual description of an instance in the spatial model. For example,
the mapping plugin uses this to say where a door leads.
diff --git a/docs/if-module/4-act.html b/docs/if-module/4-act.html
index 0101d2c4f..663dc578d 100644
--- a/docs/if-module/4-act.html
+++ b/docs/if-module/4-act.html
@@ -157,32 +157,98 @@ a given action:
+Problems::quote_source(1, current_sentence);
+Problems::quote_wording(2, PW);
+StandardProblems::handmade_problem(Task::syntax_tree(), _p_(PM_MultipleCCR));
+Problems::issue_problem_segment(
+"You wrote %1, but the situation this refers to ('%2') is not a single "
+"action. Rules in the form of 'check', 'carry out' and 'report' are "
+"tied to specific actions, and must give a single explicit action name - "
+"even if they then go on to very complicated conditions about any nouns "
+"also involved. So 'Check taking something: ...' is fine, but not 'Check "
+"taking or dropping something: ...' or 'Check doing something: ...' - "
+"the former names two actions, the latter none.");
+Problems::issue_problem_end();
+returnFALSE;
+
§6. Most actions are given automatically generated Inter identifiers, but a few
+
§7. Most actions are given automatically generated Inter identifiers, but a few
have to correspond to names referenced in WorldModelKit, so:
diff --git a/docs/if-module/4-anl.html b/docs/if-module/4-anl.html
index 644e76f13..293f5c37b 100644
--- a/docs/if-module/4-anl.html
+++ b/docs/if-module/4-anl.html
@@ -638,7 +638,7 @@ is no best action. (For example, in "throwing or removing something".)
-action_name *ActionNameLists::get_best_action(action_name_list *list) {
+action_name *ActionNameLists::get_best_action(action_name_list *list) {if (ActionNameLists::positive(list) == FALSE) returnNULL;intposn = -1;action_name *choice = NULL;
@@ -657,7 +657,7 @@ is no best action. (For example, in "throwing or removing something".)
§25. Duplication.
-anl_entry *ActionNameLists::duplicate_entry(anl_entry *entry) {
+anl_entry *ActionNameLists::duplicate_entry(anl_entry *entry) {anl_entry *new_entry = ActionNameLists::new_entry_at(EMPTY_WORDING);new_entry->parsing_data = entry->parsing_data;new_entry->parsing_data.anl_clauses = NULL;
@@ -672,7 +672,7 @@ is no best action. (For example, in "throwing or removing something".)
§26. Logging.
-voidActionNameLists::log(action_name_list *list) {
+voidActionNameLists::log(action_name_list *list) {if (list == NULL) {LOG("<null-anl>"); } else {
@@ -695,7 +695,7 @@ is no best action. (For example, in "throwing or removing something".)
}}
-voidActionNameLists::log_entry(anl_entry *entry) {
+voidActionNameLists::log_entry(anl_entry *entry) {if (entry == NULL) {LOG("<null-entry>"); } else {
@@ -708,13 +708,13 @@ is no best action. (For example, in "throwing or removing something".)
}}
-voidActionNameLists::log_clause(anl_clause *c) {
+voidActionNameLists::log_clause(anl_clause *c) {LOG("[");APClauses::write_clause_ID(DL, c->clause_ID, c->stv_to_match);LOG(": %W]", c->clause_text);}
-voidActionNameLists::log_briefly(action_name_list *list) {
+voidActionNameLists::log_briefly(action_name_list *list) {if (list == NULL) {LOG("<null-anl>"); } else {
@@ -758,7 +758,7 @@ something other than something — or intanl_parsing_tense = IS_TENSE;
-action_name_list *ActionNameLists::parse(wordingW, inttense, int *sense) {
+action_name_list *ActionNameLists::parse(wordingW, inttense, int *sense) {if (Wordings::mismatched_brackets(W)) returnNULL;intt = anl_parsing_tense;anl_parsing_tense = tense;
@@ -891,7 +891,7 @@ or "irreverent behaviour [in-presence: the Bishop]".
-anl_entry *ActionNameLists::nap_entry(named_action_pattern *nap, wordingW, wordingTW) {
+anl_entry *ActionNameLists::nap_entry(named_action_pattern *nap, wordingW, wordingTW) {anl_entry *entry = ActionNameLists::new_entry_at(W);entry->item.nap_listed = nap;if (Wordings::nonempty(TW))
@@ -1094,7 +1094,7 @@ still has a TAIL_AP_CLAUSE
-action_name *ActionNameNames::longest_nounless(wordingW, inttense, int *posn) {
+action_name *ActionNameNames::longest_nounless(wordingW, inttense, int *posn) {action_name *an;LOOP_OVER(an, action_name)if (ActionSemantics::can_have_noun(an) == FALSE) {
diff --git a/docs/if-module/4-ap.html b/docs/if-module/4-ap.html
index f61cd54b0..421df4ede 100644
--- a/docs/if-module/4-ap.html
+++ b/docs/if-module/4-ap.html
@@ -114,6 +114,7 @@ description of an action which may have happened in the past: for example,
PluginManager::plug(OFFERED_PROPERTY_PLUG, ActionVariables::actions_offered_property);PluginManager::plug(OFFERED_SPECIFICATION_PLUG, ActionsPlugin::actions_offered_specification);PluginManager::plug(TYPECHECK_EQUALITY_PLUG, ARvalues::actions_typecheck_equality);
+PluginManager::plug(DIVERT_RULE_PLUG, Actions::divert_rule);PluginManager::plug(PRODUCTION_LINE_PLUG, ActionsPlugin::production_line);PluginManager::plug(COMPLETE_MODEL_PLUG, ActionsPlugin::complete_model);
diff --git a/docs/if-module/4-nap.html b/docs/if-module/4-nap.html
index ee8bc333f..2502abb89 100644
--- a/docs/if-module/4-nap.html
+++ b/docs/if-module/4-nap.html
@@ -134,7 +134,7 @@ an action.
returnnap;}
-named_action_pattern *NamedActionPatterns::by_name(wordingW) {
+named_action_pattern *NamedActionPatterns::by_name(wordingW) {parse_node *p = Lexicon::retrieve(NAMED_AP_MC, W);if (p) returnARvalues::to_named_action_pattern(p);returnNULL;
diff --git a/docs/if-module/4-pap.html b/docs/if-module/4-pap.html
index 8fe83f4f9..528af8b4e 100644
--- a/docs/if-module/4-pap.html
+++ b/docs/if-module/4-pap.html
@@ -182,7 +182,7 @@ still be incomprehensible.
-action_name_list *ParseActionPatterns::list_of_actions_only(wordingW, int *anyone) {
+action_name_list *ParseActionPatterns::list_of_actions_only(wordingW, int *anyone) { *anyone = FALSE;action_name_list *anl = NULL;intsaved = ParseActionPatterns::enter_mode(PERMIT_TRYING_OMISSION + SCANNING_ANL_ONLY);
@@ -450,7 +450,7 @@ what passes down to Level Four.
-action_pattern *ParseActionPatterns::level_three(wordingW) {
+action_pattern *ParseActionPatterns::level_three(wordingW) {There has to be a participle here somewhere11.1;LOGIF(ACTION_PATTERN_PARSING, "Parse action pattern (tense %d): %W\n",ParseActionPatterns::current_tense(), W);
@@ -504,7 +504,7 @@ That said, it does enable, for example, the cool rule:
-voidCommandGrammars::remove_action(command_grammar *cg, action_name *an) {
+voidCommandGrammars::remove_action(command_grammar *cg, action_name *an) {if (cg->cg_is == CG_IS_COMMAND)CGLines::list_remove(cg, an);}
diff --git a/docs/if-module/5-cgl.html b/docs/if-module/5-cgl.html
index 0282a7b59..7dcf61aff 100644
--- a/docs/if-module/5-cgl.html
+++ b/docs/if-module/5-cgl.html
@@ -169,7 +169,7 @@ removing it from action. That's a feature only seen in lines for
cgl->compilation_data = RTCommandGrammarLines::new_cd(cgl);cgl->indexing_data = CommandsIndex::new_id(cgl);
-if (ac) Actions::add_gl(ac, cgl);
+if (ac) Actions::add_gl(ac, cgl);returncgl;}
diff --git a/docs/if-module/5-us.html b/docs/if-module/5-us.html
index aee4b8e31..da4f567f8 100644
--- a/docs/if-module/5-us.html
+++ b/docs/if-module/5-us.html
@@ -816,7 +816,7 @@ it, one at a time, by previous Understand sentences.
}
diff --git a/docs/if-module/P-wtmd.html b/docs/if-module/P-wtmd.html
index b41eb6f50..ad9cbf27e 100644
--- a/docs/if-module/P-wtmd.html
+++ b/docs/if-module/P-wtmd.html
@@ -106,34 +106,6 @@ picking things up, or going from place to place.
provides for command parsing. Projects using other mechanisms for having
the reader interact with them do not need this, and can deactivate the plugin.
-
§3. Grammar is organised in a three-level hierarchy:
-
-
-
(a) A command grammar (CG) is a small independent grammar of alternative
-formulations for some concept: for instance, the possible commands beginning
-TAKE, or the possible verbal forms of numbers. Each CG is a list of CGLs, and
-an individual CGL must belong to exactly one CG. There are five different
-types of CG, differentiated mostly by the purpose to which the CG is put:
-
(1) CG_IS_COMMAND. An imperative verbal command at run-time.
-
(2) CG_IS_TOKEN. A square-bracketed token in other grammar.
-
(3) CG_IS_SUBJECT. A noun phrase at run time: a name for an object.
-
(4) CG_IS_VALUE. A noun phrase at run time: a name for a value.
-
(5) CG_IS_CONSULT. A pattern to match in part of a command (such as "consult").
-
(6) CG_IS_PROPERTY_NAME. A noun phrase at run time: a name for one
-possibility for an either/or property, say "open" or "fixed in place".
-
-
(b) A grammar line (CGL) is a single possibility within a CG: for
-example, the line matching "take [something]" in the CG for the TAKE
-command. Each CGL is a list of tokens, and an individual token must belong
-to exactly one CGL.
-
(c) A grammar token (GTOK) is a single particle of a CGL: for
-example, 'take' and something are tokens.
-
-
The picture is not quite so hierarchical as it looks, though, because
-a CG naming a token can be used as a token inside other CGs. We need to
-be careful that this does not lead to infinite regress: see below.
-
-
diff --git a/docs/imperative-module/2-act.html b/docs/imperative-module/2-act.html
index 2429288f0..f086353fe 100644
--- a/docs/imperative-module/2-act.html
+++ b/docs/imperative-module/2-act.html
@@ -788,7 +788,7 @@ values, of the kind to which the activity applies.
}
§1. Introduction. Bookings are intended to be bound together in linked lists, each of which
+represents the interior pages of a single rulebook.
+
+
+
+typedefstructbooking_list {
+structbooking *list_head; the dummy entry at the front
+CLASS_DEFINITION
+} booking_list;
+
+
The structure booking_list is private to this section.
+
§2. There are only three operations on lists: creation, addition of a booking,
+and removal of a booking. The following invariants are preserved:
+
+
+
(a) The list head is a dummy, i.e., meaningless, booking which has never been
+the subject of any addition operation and has never moved.
+
(b) The only FIRST_PLACEMENT entries in the list immediately follow the list
+head. Those which were added explicitly as first-placed are in reverse order
+of addition to the list.
+
(c) The only LAST_PLACEMENT entries in the list are at the end. Those which
+were added explicitly as last-placed are in order of addition to the list.
+
(d) If R and S are middle-placed rules which were placed in the list within
+the same range (say, both anywhere, or both "after T" or "before U") and R
+precedes S, then either R is more specific than S, or they are equally specific
+and R was added to the list before S.
+
(e) The list never contains duplicates, that is, never contains two bookings
+whose rules are equal, in the sense of Rules::eq.
+
+
§3. These macros are useful for iterating through the contents in sequence;
+note that br is never equal to the dummy head, and that pr is never NULL —
+though it is initially equal to the dummy, which of course is the point of
+having the dummy.
+
§5. Addition. The following is called when a booking br for the rule R needs to be placed
+into list L, which is the contents of a rulebook we will call B. This happens,
+for example, in response to an an assertion like "R is listed after S in B";
+in that cast the side would be AFTER_SIDE, and the ref_rule would be S.
+
+
+
It is also possible to specify a placing. For example, for a rule described
+as "First every turn rule: ...", this would be added to the every turn rulebook
+with placing FIRST_PLACEMENT. There are three possible placings: see booking
+for what they are.
+
+
+
And since there are four possible sides, the following function effectively has
+12 different modes to get right.
+
+
+
Each "addition" leaves the list either the same size or longer by 1.
+
+
+
defineBEFORE_SIDE -1 before the reference rule
+defineIN_SIDE0 if no mention is made of where to put the new booking
+defineAFTER_SIDE1 after the reference rule
+defineINSTEAD_SIDE2 in place of the reference rule
+
§5.1. Make some sanity checks on the addition instructions5.1 =
+
+
+
+if ((side != IN_SIDE) && (ref_rule == NULL))
+internal_error("tried to add before or after or instead of non-rule");
+if ((side == IN_SIDE) && (ref_rule != NULL))
+internal_error("tried to add in middle but with ref rule");
+if ((side != IN_SIDE) && (placing != MIDDLE_PLACEMENT))
+internal_error("tried to add before or after but with non-middle placement");
+if (L == NULL)
+internal_error("tried to add rule to null list");
+switch(placing) {
+caseMIDDLE_PLACEMENT:break;
+caseFIRST_PLACEMENT:LOGIF(RULE_ATTACHMENTS, "Placed first\n"); break;
+caseLAST_PLACEMENT:LOGIF(RULE_ATTACHMENTS, "Placed last\n"); break;
+default:internal_error("invalid placing of rule");
+ }
+
§5.2. If R is already in B, the assertion may still have an effect.
+
+
+
If our instructions specify no particular position for R to take, we return
+because nothing need be done: the rule's there already, so be happy. Otherwise,
+we remove R's existing booking in order that it can be rebooked in a new position.
+
+
+
This is a change in semantics from the original Inform 7 design for rulebooks,
+under which a rule could be booked multiple times in the same rulebook — which
+was then called "duplication". Following debate on the Usenet newsgroup
+rec.arts.int-fiction in February and March 2009, it was decided to abolish
+duplication in favour of the clean principle that a rule can only be in a
+single rulebook once. This makes it easier to place rules with tricky preambles,
+though there were arguments on both sides.
+
+
+
Handle the case where the new rule is already in the list5.2 =
+
+
+
+LOOP_OVER_BOOKINGS_WITH_PREV(pos, prev, L)
+if (Rules::eq(RuleBookings::get_rule(pos), RuleBookings::get_rule(new_br))) {
+if ((side == IN_SIDE) && (placing == MIDDLE_PLACEMENT)) return;
+prev->next_booking = pos->next_booking;
+pos->next_booking = NULL;
+LOGIF(RULE_ATTACHMENTS, "Removing previous entry from rulebook\n");
+break; rule can only appear once, so no need to keep checking
+ }
+
§5.4. If we insert a rule as first-placed rule when there already is a first-placed
+rule, the new one displaces it to go first, but both continue to be labelled as
+having FIRST_PLACEMENT, so that subsequent rule insertions of middle-placed rules
+will still go after both of them.
+
+
+
Handle all placements made with the FIRST placement5.4 =
+
+
+
+if (placing == FIRST_PLACEMENT) { first in valid interval (must be whole list)
+booking *previously_first = L->list_head->next_booking;
+L->list_head->next_booking = new_br;
+new_br->next_booking = previously_first; pushes any existing first rule forward
+new_br->placement = placing;
+return;
+ }
+
§5.6.3. Find insertion point, keeping the valid interval in specificity order5.6.3 =
+
+
+
+intlog = FALSE; if (Log::aspect_switched_on(SPECIFICITIES_DA)) log = TRUE;
+
+ move forward to final valid first rule (if any exist)
+while ((insert_after->next_booking != end_rule)
+ && (insert_after->next_booking->placement == FIRST_PLACEMENT))
+insert_after = insert_after->next_booking;
+
+ move forward past other middle rules if they are not less specific
+while ((insert_after->next_booking != end_rule) stop before \(p\) leaves valid range
+ && (insert_after->next_booking->placement != LAST_PLACEMENT) or reaches a last rule
+ && (RuleBookings::cmp(insert_after->next_booking, new_br,
+log) >= 0)) or a rule less specific than the new one
+insert_after = insert_after->next_booking;
+
§5.6.4. Since this part of the algorithm is used only when we've requested MIDDLE
+placement, it might seem that new_br->placement should always be set to
+that. This does indeed mostly happen, but not always. To preserve rulebook
+invariants (b) and (c), we need to force anything added after a LAST rule
+to be LAST as well, and similarly for FIRSTs. (This will only happen in
+cases where the source text called for placements AFTER a LAST rule, or
+BEFORE a FIRST one.)
+
+
+
Set the placement for the new rule booking5.6.4 =
+
+
+
+new_br->placement = MIDDLE_PLACEMENT;
+if ((insert_after != L->list_head) &&
+ (insert_after->placement == LAST_PLACEMENT))
+new_br->placement =
+LAST_PLACEMENT; happens if valid interval is after a last rule
+
+if ((subseq) &&
+ (subseq->placement == FIRST_PLACEMENT))
+new_br->placement =
+FIRST_PLACEMENT; happens if valid interval is before a first rule
+
§8. Compilation of rule definitions for rulebook. There's no real need to do so, but we compile rule definitions in rulebook
+order to make the compiled code more legible, and for the same reason we add
+plenty of commentary.
+
+
+
+
+
+
+
diff --git a/docs/imperative-module/2-fao.html b/docs/imperative-module/2-fao.html
index 70b511a4b..7d5f0cbdd 100644
--- a/docs/imperative-module/2-fao.html
+++ b/docs/imperative-module/2-fao.html
@@ -425,7 +425,7 @@ can be used in a void context as a sort of return-from-rule phrase.
rulebook_outcome *ro;for (ro = outs->named_outcomes; ro; ro = ro->next) {if (ro->outcome_name == rbno) {
-if (Rules::Bookings::list_contains_ph(Rulebooks::first_booking(rb), ph))
+if (BookingLists::contains_ph(rb->rule_list, ph))returnro; } }
@@ -440,7 +440,7 @@ can be used in a void context as a sort of return-from-rule phrase.
rulebook *rb;LOOP_OVER(rb, rulebook) {outcomes *outs = Rulebooks::get_outcomes(rb);
-if (Rules::Bookings::list_contains_ph(Rulebooks::first_booking(rb), ph)) {
+if (BookingLists::contains_ph(rb->rule_list, ph)) {intokay = FALSE;rulebook_outcome *ro;for (ro = outs->named_outcomes; ro; ro = ro->next)
@@ -626,7 +626,7 @@ can be used in a void context as a sort of return-from-rule phrase.
}
§3. Indexing of lists. There's a division of labour: here we arrange the index of the rules and
+show the linkage between them, while the actual content for each rule is
+handled in the "Rules" section.
+
§4. The "index links" are not hypertextual: they're the little icons showing
+the order of precedence of rules in the list. On some index pages we don't
+want this, so:
+
diff --git a/docs/knowledge-module/1-km.html b/docs/knowledge-module/1-km.html
index 6c7824c9d..f74cfe501 100644
--- a/docs/knowledge-module/1-km.html
+++ b/docs/knowledge-module/1-km.html
@@ -75,7 +75,7 @@ which use this module:
-COMPILE_WRITER(booking *, Rules::Bookings::log)
+COMPILE_WRITER(booking *, RuleBookings::log)COMPILE_WRITER(inference *, Inferences::log)COMPILE_WRITER(inference_subject *, InferenceSubjects::log)COMPILE_WRITER(property *, Properties::log)
@@ -107,7 +107,7 @@ which use this module:
SettingPropertyRelations::start();ComparativeRelations::start();ProvisionRelation::start();
-REGISTER_WRITER('b', Rules::Bookings::log);
+REGISTER_WRITER('b', RuleBookings::log);REGISTER_WRITER('I', Inferences::log);REGISTER_WRITER('j', InferenceSubjects::log);REGISTER_WRITER('K', Rulebooks::log);
diff --git a/docs/runtime-module/2-emt.html b/docs/runtime-module/2-emt.html
index e7a90a884..dce48610b 100644
--- a/docs/runtime-module/2-emt.html
+++ b/docs/runtime-module/2-emt.html
@@ -84,7 +84,7 @@ function togglePopup(material_id) {
inter_tree *I7_generation_tree = NULL;
-inter_tree *Emit::tree(void) {
+inter_tree *Emit::tree(void) {returnI7_generation_tree;}
@@ -502,7 +502,7 @@ insert them into the Inter stream close to the top.
returnsave;}
-packaging_stateEmit::named_array_begin(inter_name *N, kind *K) {
+packaging_stateEmit::named_array_begin(inter_name *N, kind *K) {packaging_statesave = Packaging::enter_home_of(N);inter_symbol *symb = Produce::define_symbol(N);Emit::push_array();
@@ -523,7 +523,7 @@ insert them into the Inter stream close to the top.
Emit::add_entry(val1, val2);}
-voidEmit::array_null_entry(void) {
+voidEmit::array_null_entry(void) {Emit::array_iname_entry(Hierarchy::find(NULL_HL));}
@@ -537,7 +537,7 @@ insert them into the Inter stream close to the top.
}#ifdefIF_MODULE
-voidEmit::array_action_entry(action_name *an) {
+voidEmit::array_action_entry(action_name *an) {if (current_A == NULL) internal_error("entry outside of inter array");inter_tiv1 = 0, v2 = 0;inter_symbol *symb = InterNames::to_symbol(RTActions::iname(an));
@@ -568,7 +568,7 @@ insert them into the Inter stream close to the top.
Emit::add_entry(v1, v2);}
-voidEmit::array_numeric_entry(inter_tiN) {
+voidEmit::array_numeric_entry(inter_tiN) {if (current_A == NULL) internal_error("entry outside of inter array");Emit::add_entry(LITERAL_IVAL, N);}
@@ -586,7 +586,7 @@ insert them into the Inter stream close to the top.
returnIBM;}
-voidEmit::array_end(packaging_statesave) {
+voidEmit::array_end(packaging_statesave) {if (current_A == NULL) internal_error("inter array not opened");inter_symbol *con_name = current_A->array_name_symbol;inter_bookmark *IBM = Packaging::at(Emit::tree());
@@ -617,7 +617,7 @@ insert them into the Inter stream close to the top.
Packaging::exit(Emit::tree(), save);}
-inter_name *Emit::named_iname_constant(inter_name *name, kind *K, inter_name *iname) {
+inter_name *Emit::named_iname_constant(inter_name *name, kind *K, inter_name *iname) {packaging_statesave = Packaging::enter_home_of(name);inter_symbol *con_name = Produce::define_symbol(name);inter_symbol *val_kind = Produce::kind_to_symbol(K);
@@ -802,7 +802,7 @@ insert them into the Inter stream close to the top.
returnPackaging::enclosure(Emit::tree());}
-packaging_stateEmit::unused_packaging_state(void) {
+packaging_stateEmit::unused_packaging_state(void) {returnPackaging::stateless();}
diff --git a/docs/runtime-module/2-hrr.html b/docs/runtime-module/2-hrr.html
index dd2eccac6..f9a3ec2be 100644
--- a/docs/runtime-module/2-hrr.html
+++ b/docs/runtime-module/2-hrr.html
@@ -1723,11 +1723,11 @@ function togglePopup(material_id) {
@@ -435,6 +435,323 @@ failing; so it doesn't terminate the following of its rulebook.
Phrases::Usage::write_I6_comment_describing(&(R->defn_as_phrase->usage_data)); }}
+
+
§7. Compilation of I6-format rulebook. The following can generate both old-style array rulebooks and routine rulebooks,
+which were introduced in December 2010.
+
defineARRAY_RBF1 format as an array simply listing the rules
+defineGROUPED_ARRAY_RBF2 format as a grouped array, for quicker action testing
+defineROUTINE_RBF3 format as a routine which runs the rulebook
+defineRULE_OPTIMISATION_THRESHOLD20 group arrays when larger than this number of rules
+
§8.1. Grouping is the practice of gathering together rules which all rely on
+the same action going on; it's then efficient to test the action once rather
+than once for each rule.
+
+
+
Compile the rulebook in the given format8.1 =
+
+
+
+intgrouping = FALSE, group_cap = 0;
+switch (format) {
+caseGROUPED_ARRAY_RBF:grouping = TRUE; group_cap = 31; break;
+caseROUTINE_RBF:grouping = TRUE; group_cap = 2000000000; break;
+ }
+if (action_based == FALSE) grouping = FALSE;
+
+inter_symbol *forbid_breaks_s = NULL, *rv_s = NULL, *original_deadflag_s = NULL, *p_s = NULL;
+packaging_statesave_array = Emit::unused_packaging_state();
+
+Open the rulebook compilation8.1.1;
+intgroup_size = 0, group_started = FALSE, entry_count = 0, action_group_open = FALSE;
+LOOP_OVER_BOOKINGS(br, L) {
+parse_node *spec = Rvalues::from_rule(RuleBookings::get_rule(br));
+if (grouping) {
+if (group_size == 0) {
+if (group_started) End an action group in the rulebook8.1.4;
+ #ifdefIF_MODULE
+action_name *an = RTRules::br_required_action(br);
+booking *brg = br;
+while ((brg) && (an == RTRules::br_required_action(brg))) {
+group_size++;
+brg = brg->next_booking;
+ }
+ #endif
+ #ifndefIF_MODULE
+booking *brg = br;
+while (brg) {
+group_size++;
+brg = brg->next_booking;
+ }
+ #endif
+if (group_size > group_cap) group_size = group_cap;
+group_started = TRUE;
+Begin an action group in the rulebook8.1.2;
+ }
+group_size--;
+ }
+Compile an entry in the rulebook8.1.3;
+entry_count++;
+ }
+if (group_started) End an action group in the rulebook8.1.4;
+Close the rulebook compilation8.1.5;
+