But we want to create just two imperative_defn objects, not three. So
+when the second IMPERATIVE_NT node is identified as belonging to us, we
+take the opportunity to change the type of the third node to DEFN_CONT_NT
+("definition continuation"). That means it will not lead to an imperative_defn
+of its own.
+
+
§3.
@@ -100,10 +127,10 @@ function togglePopup(material_id) {
we need to make the pronoun "it" a local variable of kind "container" in the
-stack frame used to compile the "..." part. If it uses a calling, like so:
-
-
-
-
Definition: A container (called the sack) is capacious if: ...
-
-
-
then we also want the name "sack" to refer to this. Here's where we take care
-of it:
+
§5. Since the "Definition:" node might have no code under it (because the code
+is actually under the continuation node):
§6. The body of code under a definition needs to be set up so that:
+
+
+
● The code expects to make a yes/no decision;
+
● The pronoun "it" is a local variable referring to the value being tested,
+perhaps also with a calling — consider the example "Definition: A
+container (called the sack) is capacious if...".
+
There are very few of them, and an Inform source text cannot create more.
+The following is called at startup, and then that's the lot.
+
+
+
The order of creation is important here, or at least, it's important that
+the rule family comes last, because this affects the order of the loop in
+ImperativeDefinitionFamilies::identify below.
§2. Such a family is little more than a set of methods:
@@ -97,7 +107,7 @@ The following is called at startup, and then that's the lot:
CLASS_DEFINITION} imperative_defn_family;
-imperative_defn_family *ImperativeDefinitionFamilies::new(text_stream *name, intlast) {
+imperative_defn_family *ImperativeDefinitionFamilies::new(text_stream *name, intlast) {imperative_defn_family *family = CREATE(imperative_defn_family);family->family_name = Str::duplicate(name);family->methods = Methods::new_set();
@@ -106,28 +116,31 @@ The following is called at startup, and then that's the lot:
}
The structure imperative_defn_family is accessed in 5/id, 7/am and here.
-
§3. So, then, the rest of this section provides an API, in effect, for different
+
§3. Identification. So, then, the rest of this section provides an API, in effect, for different
users of imperative definitions to get their work done.
-
CLAIM_IMP_DEFN_MTID is for deciding from the syntax of a preamble whether
-this definition should belong to the family or not.
+
IDENTIFY_IMP_DEFN_MTID is for deciding from the syntax of a preamble whether
+this definition should belong to the family or not. The recipient should set
+id->family to itself if it wants the definition.
§4. ASSESS_IMP_DEFN_MTID is for parsing it in more detail, later on.
+
§4. Assessment. ASSESS_IMP_DEFN_MTID is for parsing the preamble in more detail, later on.
+At the start of assessment, this is called on each of the IDs belonging to the
+family in turn.
enumASSESS_IMP_DEFN_MTID
@@ -139,53 +152,43 @@ this definition should belong to the family or not.
VOID_METHOD_CALL(id->family, ASSESS_IMP_DEFN_MTID, id);}
-
§5. REGISTER_IMP_DEFN_MTID is called on the family when everything has
-been assessed.
+
§5. GIVEN_BODY_IMP_DEFN_MTID is called on an ID just after id->body_of_defn
+has finally been created.
+
§10. Whether phrases which end the current rulebook are allowed in the definition body.
+
§9. What is allowed in the body. The body of the definition can for the most part be any Inform 7 code, but
+there are a few restrictions which depend on what the definition family is.
+
+
+
ALLOWS_RULE_ONLY_PHRASES_IMP_DEFN_MTID should reply TRUE if phrases
+intended to end rules or rulebooks can be used in the body; by default, not.
§11. Whether the definition body can be empty (as when a definition of an adjective
-does not go on to contain code).
+
§10. ALLOWS_EMPTY_IMP_DEFN_MTID should reply TRUE if the body is allowed to
+be empty, that is, for there to be no code at all. This happens for some
+adjective definitions which wrap up in a single line. The default is no.
enumALLOWS_EMPTY_IMP_DEFN_MTID
@@ -235,7 +246,8 @@ does not go on to contain code).
returnrv;}
-
§12. Whether the definition body can be given as (- inline -) material.
+
§11. ALLOWS_INLINE_IMP_DEFN_MTID should reply TRUE if the definition body can
+be given as (- inline -) material. The default is no.
enumALLOWS_INLINE_IMP_DEFN_MTID
@@ -249,7 +261,9 @@ does not go on to contain code).
returnrv;}
-
§13. COMPILE_IMP_DEFN_MTID is for .
+
§12. Compilation and indexing. COMPILE_IMP_DEFN_MTID is called to ask the family to perform its main round
+of compilation for any resources it will need — most obviously, of course,
+it may want to turn its definition bodies into Inter functions.
enumCOMPILE_IMP_DEFN_MTID
@@ -264,7 +278,9 @@ does not go on to contain code).
total_phrases_compiled, total_phrases_to_compile);}
-
§14. COMPILE_IMP_DEFN_MTID is for .
+
§13. COMPILE_AS_NEEDED_IMP_DEFN_MTID is then called as an opportunity to
+compile any remaining resources, and should pick up anything needed since the
+last time it was called: note that it can be called multiple times.
enumCOMPILE_AS_NEEDED_IMP_DEFN_MTID
@@ -279,7 +295,8 @@ does not go on to contain code).
total_phrases_compiled, total_phrases_to_compile);}
-
§15. PHRASEBOOK_INDEX_IMP_DEFN_MTID is for .
+
§14. PHRASEBOOK_INDEX_IMP_DEFN_MTID should reply TRUE if the definition should
+go into the Phrasebook page of the index.
enumPHRASEBOOK_INDEX_IMP_DEFN_MTID
diff --git a/docs/assertions-module/5-rf.html b/docs/assertions-module/5-rf.html
index e65742d73..2cad6afa9 100644
--- a/docs/assertions-module/5-rf.html
+++ b/docs/assertions-module/5-rf.html
@@ -73,63 +73,116 @@ function togglePopup(material_id) {
§1. Introduction. This family handles definitions of rules which give explicit Inform 7
+source text to show what they do. (It's also possible to create rules which
+are implemented by Inter-level functions only, and those do not fall under
+this section, because they have no imperative_defn.) For example:
+
-imperative_defn_family *RULE_EFF_family = NULL; "Before taking a container, ..."
-
-typedefstructrule_family_data {
-structwordingreduced_stem;
-structwordingconstant_name;
-structwordingpattern;
-intnot_in_rulebook;
-intevent_time;
-structwordingevent_name;
-structlinked_list *uses_as_event; of use_as_event
-structwordingrule_parameter; text of object or action parameter
-structwordingwhenwhile; when/while for action/activity rulebooks
- #ifdefIF_MODULE
-structparse_node *during_scene_spec; what scene is currently under way
- #endif
-structrulebook *owning_rulebook; the primary booking for the phrase will be here
-intowning_rulebook_placement; ...and with this placement value: see Rulebooks
-CLASS_DEFINITION
-} rule_family_data;
+Everyturn:
+say"The grandfather clock ticks reprovingly."
-
The structure rule_family_data is accessed in 5/tpf and here.
-
§2.
+
Some rules have names, some do not; some indicate explicitly what rulebook
+they belong to, and others are placed in rulebooks with separate sentences.
+So there's quite a lot to do.
+
§2. Each family member gets one of the following. In splitting up preambles,
+the "usage preamble" is the part indicating when the rule should happen, and
+this is divided up into smaller excerpts of text, as in the following examples:
+
+
+
+rule instead of taking or dropping when Miss Bianca is in the Embassy:
+<---------------------------- usage_preamble ----------------------------------->
+ <- stem ----> <------------------ applicability ------------------>
+ <- ps -> <- bud -> <--- prewhile ---> <-------- whenwhile -------->
+
+after examining an open door during the Hurricane (this is the exit hunting rule):
+<----------------- usage preamble -----------------> <- const name -->
+<---- stem -----> <-- appl --> <- during -->
+<- pruned stem -> <-- pw ---->
+
+
+typedefstructrule_family_data {
+structwordingusage_preamble;
+structwordingpruned_stem;
+structwordingconstant_name;
+structwordingprewhile_applicability;
+structwordingapplicability;
+structwordingwhenwhile;
+structparse_node *during_spec; what scene is currently under way
+
+intnot_in_rulebook;
+structrule *defines;
+structrulebook *owning_rulebook; the primary booking for the phrase will be here
+intowning_rulebook_placement; ...and with this placement value: see Rulebooks
+
+void *plugin_rfd[MAX_PLUGINS]; storage for plugins to attach, if they want to
+CLASS_DEFINITION
+} rule_family_data;
+
+rule_family_data *RuleFamily::new_data(void) {
+rule_family_data *rfd = CREATE(rule_family_data);
+rfd->pruned_stem = EMPTY_WORDING;
+rfd->constant_name = EMPTY_WORDING;
+rfd->usage_preamble = EMPTY_WORDING;
+rfd->applicability = EMPTY_WORDING;
+rfd->prewhile_applicability = EMPTY_WORDING;
+rfd->whenwhile = EMPTY_WORDING;
+rfd->during_spec = NULL;
+rfd->not_in_rulebook = FALSE;
+rfd->defines = NULL;
+rfd->owning_rulebook = NULL;
+rfd->owning_rulebook_placement = MIDDLE_PLACEMENT;
+for (inti=0; i<MAX_PLUGINS; i++) rfd->plugin_rfd[i] = NULL;
+returnrfd;
+}
+
+
The structure rule_family_data is accessed in 5/tpf and here.
+
§3. These two macros provide access to plugin-specific rule family data:
+
§4. Identification. We are going to claim as our own any definition whose name matches the
+following nonterminal — and because of the last production, this will always
+happen. (That's why it is important that we are the last family to claim.)
+
§5. Forms 1 and 2 give a rule name; forms 2 and 3 say which rulebook it goes into.
-StandardProblems::sentence_problem(Task::syntax_tree(), _p_(PM_AtTimeThat),
-"this seems to use 'that' where it should use 'when'",
-"assuming it's trying to apply a rule to an event. (The convention is "
-"that any rule beginning 'At' is a timed one. The time can either be a "
-"fixed time, as in 'At 11:10 AM: ...', or the time when some named "
-"event takes place, as in 'At the time when the clock chimes: ...'.)");
-
-StandardProblems::sentence_problem(Task::syntax_tree(), _p_(PM_AtWithoutTime),
-"'at' what time? No description of a time is given",
-"which means that this rule can never have effect. (The convention is "
-"that any rule beginning 'At' is a timed one. The time can either be a "
-"fixed time, as in 'At 11:10 AM: ...', or the time when some named "
-"event takes place, as in 'At the time when the clock chimes: ...'.)");
-
Problems::quote_source(1, current_sentence);StandardProblems::handmade_problem(Task::syntax_tree(), _p_(PM_BadRulePreambleWhen));Problems::issue_problem_segment(
-"The punctuation makes me think %1 should be a definition "
-"of a phrase or a rule, but it doesn't begin as it should, "
-"with either 'To' (e.g. 'To flood the riverplain:'), 'Definition:', "
-"a name for a rule (e.g. 'This is the devilishly cunning rule:'), "
-"'At' plus a time (e.g. 'At 11:12 PM:' or 'At the time when "
-"the clock chimes:') or the name of a rulebook. %P"
-"As your rule begins with 'When', it may be worth noting that in "
-"December 2006 the syntax used by Inform for timed events changed: "
-"the old syntax 'When the sky falls in:' to create a named "
-"event, the sky falls in, became 'At the time when the sky "
-"falls in:'. This was changed to avoid confusion with rules "
-"relating to when scenes begin or end. %P"
-"Or perhaps you meant to say that something would only happen "
-"when some condition held. Inform often allows this, but the "
-"'when...' part tends to be at the end, not up front - for "
-"instance, 'Understand \"blue\" as the deep crevasse when the "
-"location is the South Pole.'");
+"The punctuation makes me think %1 should be a definition of a phrase or a rule, "
+"but it doesn't begin as it should, with either 'To' (e.g. 'To flood the riverplain:'), "
+"'Definition:', a name for a rule (e.g. 'This is the devilishly cunning rule:'), "
+"'At' plus a time (e.g. 'At 11:12 PM:' or 'At the time when the clock chimes:') or "
+"the name of a rulebook. %P"
+"Perhaps you meant to say that something would only happen when some condition held. "
+"Inform often allows this, but the 'when...' part tends to be at the end, not up "
+"front - for instance, 'Understand \"blue\" as the deep crevasse when the location "
+"is the South Pole.'");Problems::issue_problem_end();
StandardProblems::sentence_problem(Task::syntax_tree(), _p_(PM_BadRulePreamble),
-"the punctuation here ':' makes me think this should be a definition "
-"of a phrase and it doesn't begin as it should",
-"with either 'To' (e.g. 'To flood the riverplain:'), 'Definition:', "
-"a name for a rule (e.g. 'This is the devilishly cunning rule:'), "
-"'At' plus a time (e.g. 'At 11:12 PM:' or 'At the time when "
-"the clock chimes') or the name of a rulebook, possibly followed "
-"by some description of the action or value to apply to (e.g. "
+"the punctuation here ':' makes me think this should be a definition of a phrase "
+"and it doesn't begin as it should",
+"with either 'To' (e.g. 'To flood the riverplain:'), 'Definition:', a name for a "
+"rule (e.g. 'This is the devilishly cunning rule:'), 'At' plus a time (e.g. 'At "
+"11:12 PM:' or 'At the time when the clock chimes') or the name of a rulebook, "
+"possibly followed by some description of the action or value to apply to (e.g. ""'Instead of taking something:' or 'Every turn:').");
§7. The crucial nonterminal in the above grammar is <rulebook-stem>, which tries
+to make the longest match it can of a rulebook name; if it matches successfully,
+then calling Rulebooks::match produces a detailed rundown of its findings,
+which are too elaborate to pass back in a simple pointer.
+
+
+
+voidRuleFamily::assess(imperative_defn_family *self, imperative_defn *id) {
+rule_family_data *rfd = RETRIEVE_POINTER_rule_family_data(id->family_specific_data);
+if (rfd->not_in_rulebook == FALSE) {
+wordingW = rfd->usage_preamble;
+<rule-preamble-fine>(W);
+parse_node *during_spec = <<rp>>;
+inthas_when = <<r>>;
+rulebook_match *parsed_rm = Rulebooks::match();
+W = GET_RW(<rule-preamble-finer>, 1);
+if (has_when == NOT_APPLICABLE) {
+<unrecognised-rule-stem-diagnosis>(W);
+ } else {
+if (has_when) rfd->whenwhile = GET_RW(<rule-preamble-finer>, 2);
+rfd->during_spec = during_spec;
+rfd->owning_rulebook = parsed_rm->matched_rulebook;
+rfd->owning_rulebook_placement = parsed_rm->placement_requested;
+Disallow the definite article for middling rules7.1;
+Cut off the bud from the stem7.2;
+Merge the when/while text back into applicability, for actions7.3;
+ }
+rfd->pruned_stem = W;
+ }
+}
+
+
§7.1. This is a super-pedantic problem message, and might cause problems in languages
+other than English.
+
+
+
Disallow the definite article for middling rules7.1 =
if ((parsed_rm->article_used == definite_article) && (parsed_rm->placement_requested == MIDDLE_PLACEMENT))
-StandardProblems::sentence_problem(Task::syntax_tree(), _p_(PM_RuleWithDefiniteArticle),
+StandardProblems::sentence_problem(Task::syntax_tree(),
+_p_(PM_RuleWithDefiniteArticle),"a rulebook can contain any number of rules",
-"so (e.g.) 'the before rule: ...' is disallowed; you should "
-"write 'a before rule: ...' instead.");
+"so (e.g.) 'the before rule: ...' is disallowed; you should write 'a before "
+"rule: ...' instead.");
§9. The late-morning creations. A little later on, we've made a rule phrase, and it now has a proper PHUD.
-If the rule is an anonymous one, such as:
+
§7.3. This unobvious manoeuvre puts the when/while text back again, so that:
+
+
+
+rule instead of taking or dropping when Miss Bianca is in the Embassy:
+ <----- appl -----> <---------- whenwhile ----------->
+ ||
+\||/
+rule instead of taking or dropping when Miss Bianca is in the Embassy:
+ <----- appl ---------------------------------------->
+
+
This is done only where we now know that the stem specified a rulebook based
+on actions, and the reason it's done is that action applicabilities are parsed
+with a grammar much more sensitive to ambiguities, and in which "when..."
+clauses are therefore better recognised.
+
+
+
Merge the when/while text back into applicability, for actions7.3 =
+
§8. Every rule corresponds to a rule structure. If the rule is an anonymous
+one, such as:
@@ -505,41 +469,37 @@ connect this existing one to the phrase.
-rule *RuleFamily::to_rule(imperative_defn *id) {
+voidRuleFamily::given_body(imperative_defn_family *self, imperative_defn *id) {rule_family_data *rfd = RETRIEVE_POINTER_rule_family_data(id->family_specific_data);
-wordingW = EMPTY_WORDING;
-intexplicitly = FALSE;
-Find the name of the phrase, and whether or not it's explicitly given9.1;
-
rule *R = NULL;
-if (Wordings::nonempty(W)) R = Rules::by_name(W);
-if (R) Check that this isn't duplicating the name of a rule already made9.2
-elseR = Rules::obtain(W, explicitly);
-if (Wordings::empty(W))
-Hierarchy::markup_wording(R->compilation_data.rule_package, RULE_NAME_HMD, Node::get_text(id->at));
-Rules::set_imperative_definition(R, id);
-phrase *ph = id->body_of_defn;
-package_request *P = RTRules::package(R);
-ph->ph_iname = Hierarchy::make_localised_iname_in(RULE_FN_HL, P, ph->owning_module);
+Set R to a corresponding rule structure8.1;
+rfd->defines = R;
+ if (rfd->not_in_rulebook == FALSE) Rules::request_automatic_placement(R);
-Do some tedious business for indexing the rule later on9.3;
-
-returnR;
+id->body_of_defn->compile_with_run_time_debugging = TRUE;
+Phrases::TypeData::set_mor(&(id->body_of_defn->type_data),
+DECIDES_NOTHING_AND_RETURNS_MOR, NULL);}
-
§9.1. Find the name of the phrase, and whether or not it's explicitly given9.1 =
+
§8.1. Set R to a corresponding rule structure8.1 =
-if (Wordings::nonempty(rfd->event_name)) {
-W = Articles::remove_the(rfd->event_name);
- } elseif (Wordings::nonempty(rfd->constant_name)) {
+rule_family_data *rfd = RETRIEVE_POINTER_rule_family_data(id->family_specific_data);
+wordingW = EMPTY_WORDING;
+intexplicitly = FALSE;
+if (Wordings::nonempty(rfd->constant_name)) {W = Articles::remove_the(rfd->constant_name);explicitly = TRUE; }
+if (Wordings::nonempty(W)) R = Rules::by_name(W);
+if (R) Check that this isn't duplicating the name of a rule already made8.1.1
+elseR = Rules::obtain(W, explicitly);
+Rules::set_imperative_definition(R, id);
+Merge the applicability and when/while text for indexing purposes8.1.2;
§9. At the end of the assessment process, we can finally put the rules into their
+rulebooks. We make "automatic placements" first — i.e., those where the usage
+preamble specified which rulebook the rule belonged to; and then we make manual
+placements, which may move or remove rules already place. See Rule Placement Requests
+for how sentences specifying this are parsed.
+
§13.1.1.1. All that's left is to issue a "good" problem message, but this is quite
-a large undertaking, because the situation as we currently know it is just
-that something's wrong with the rule preamble — which covers an enormous
-range of different faults.
+
§10.1.1. All that's left is to issue a "good" problem message, but this is quite a
+large undertaking, because the situation as we currently know it is just that
+something's wrong with the rule preamble — which covers an enormous range of
+different faults.
-
The "PAP failure reason" is a sort of error code set by the action pattern
+
The pap_failure_reason is a sort of error code set by the action pattern
parser, recording how it most recently failed.
-
Issue a problem message for a bad action13.1.1.1 =
+
StandardProblems::handmade_problem(Task::syntax_tree(), _p_(PM_APWithDisjunction));Problems::issue_problem_segment(
-"You wrote %1, which seems to introduce a rule, but the "
-"circumstances ('%2') seem to be too general for me to "
-"understand in a single rule. I can understand a choice of "
-"of actions, in a list such as 'taking or dropping the ball', "
-"but there can only be one set of noun(s) supplied. So 'taking "
-"the ball or taking the bat' is disallowed. You can get around "
-"this by using named actions ('Taking the ball is being "
-"mischievous. Taking the bat is being mischievous. Instead of "
-"being mischievous...'), or it may be less bother just to "
-"write more than one rule.");
+"You wrote %1, which seems to introduce a rule, but the circumstances ('%2') seem "
+"to be too general for me to understand in a single rule. I can understand a "
+"choice of actions, in a list such as 'taking or dropping the ball', but there "
+"can only be one set of noun(s) supplied. So 'taking the ball or taking the bat' "
+"is disallowed. You can get around this by using named actions ('Taking the ball "
+"is being mischievous. Taking the bat is being mischievous. Instead of being "
+"mischievous...'), or it may be less bother just to write more than one rule.");Problems::issue_problem_end();
StandardProblems::handmade_problem(Task::syntax_tree(), _p_(PM_APWithNoParticiple));Problems::issue_problem_segment(
-"You wrote %1, which seems to introduce a rule taking effect "
-"only '%2'. But this does not look like an action, since "
-"there is no sign of a participle ending '-ing' (as in "
-"'taking the brick', say) - which makes me think I have "
-"badly misunderstood what you intended.");
+"You wrote %1, which seems to introduce a rule taking effect only '%2'. But this "
+"does not look like an action, since there is no sign of a participle ending '-ing' "
+"(as in 'taking the brick', say) - which makes me think I have badly misunderstood "
+"what you intended.");Problems::issue_problem_end();
StandardProblems::handmade_problem(Task::syntax_tree(), _p_(PM_APWithImmiscible));Problems::issue_problem_segment(
-"You wrote %1, which seems to introduce a rule taking effect "
-"only '%2'. But this is a combination of actions which cannot "
-"be mixed. The only alternatives where 'or' is allowed are "
-"cases where a choice of actions is given but applying to "
-"the same objects in each case. (So 'taking or dropping the "
-"CD' is allowed, but 'dropping the CD or inserting the CD "
-"into the jewel box' is not, because the alternatives there "
-"would make different use of objects from each other.)");
+"You wrote %1, which seems to introduce a rule taking effect only '%2'. But this "
+"is a combination of actions which cannot be mixed. The only alternatives where "
+"'or' is allowed are cases where a choice of actions is given but applying to "
+"the same objects in each case. (So 'taking or dropping the CD' is allowed, but "
+"'dropping the CD or inserting the CD into the jewel box' is not, because the "
+"alternatives there would make different use of objects from each other.)");Problems::issue_problem_end();
StandardProblems::handmade_problem(Task::syntax_tree(), _p_(PM_APWithBadWhen));
-wordingQ = rfd->rule_parameter;
+wordingQ = rfd->applicability;intdiagnosis = 0;if (<action-when-diagnosis>(Q)) {
-Q = Wordings::new(<<cw1>>, <<cw2>>);
+if (<<r>> == 1) Q = GET_RW(<action-when-diagnosis>, 3);
+elseQ = GET_RW(<action-when-diagnosis>, 2);diagnosis = <<r>>; }Problems::quote_wording(2, Q);
@@ -818,98 +711,93 @@ parser, recording how it most recently failed.
"(Whereas 'no room' is usually allowed.)"); }Problems::issue_problem_segment(
-"You wrote %1, which seems to introduce a rule taking effect "
-"only '%2'. But this condition did not make sense, %3");
+"You wrote %1, which seems to introduce a rule taking effect only '%2'. But this "
+"condition did not make sense, %3");if (diagnosis == 1)Problems::issue_problem_segment("%PIt might be worth mentioning that a 'when' condition tacked on to ""an action like this is not allowed to mention or use 'called' values.");if (diagnosis == 4)Problems::issue_problem_segment(
-"%PThe problem might be that 'and' has been followed by 'when' or "
-"'while'. For example, to make a rule with two conditions, this is "
-"okay: 'Instead of jumping when Peter is happy and Peter is in the "
-"location'; but the same thing with '...and when Peter is...' is not allowed.");
+"%PThe problem might be that 'and' has been followed by 'when' or 'while'. "
+"For example, to make a rule with two conditions, this is okay: 'Instead of "
+"jumping when Peter is happy and Peter is in the location'; but the same thing "
+"with '...and when Peter is...' is not allowed.");Problems::issue_problem_end();
§10.1.1.5.1. See if it starts with a valid action name, at least10.1.1.5.1 =
action_name *an;LOOP_OVER(an, action_name)
-if ((Wordings::length(rfd->rule_parameter) < Wordings::length(ActionNameNames::tensed(an, IS_TENSE))) &&
- (Wordings::match(rfd->rule_parameter,
-Wordings::truncate(ActionNameNames::tensed(an, IS_TENSE), Wordings::length(rfd->rule_parameter))))) {
+if ((Wordings::length(rfd->applicability) <
+Wordings::length(ActionNameNames::tensed(an, IS_TENSE))) &&
+ (Wordings::match(rfd->applicability,
+Wordings::truncate(ActionNameNames::tensed(an, IS_TENSE),
+Wordings::length(rfd->applicability))))) {Problems::quote_wording(3, ActionNameNames::tensed(an, IS_TENSE));Problems::issue_problem_segment(
-" I notice that there's an action called '%3', though: perhaps "
-"this is what you meant?");
+" I notice that there's an action called '%3', though: perhaps this is "
+"what you meant?");break; }
§10.1.1.5.2. See if this might be a when-for confusion10.1.1.5.2 =
if (pap_failure_reason == WHENOKAY_PAPF) {
-time_period *duration = Occurrence::parse(rfd->reduced_stem);
+time_period *duration = Occurrence::parse(rfd->pruned_stem);if (duration) {Problems::quote_wording(3, Occurrence::used_wording(duration));Problems::issue_problem_segment(
-" (I wonder if this might be because '%3', which looks like a "
-"condition on the timing, is the wrong side of the 'when...' "
-"clause?)");
+" (I wonder if this might be because '%3', which looks like a condition "
+"on the timing, is the wrong side of the 'when...' clause?)"); } }
§10.1.1.5.3. If the action pattern contains what looks like a list of action names, as for example
+"Instead of taking or dropping the magnet: ..." then the <anl-diagnosis> grammar will
+ parse this and return N equal to 2, the apparent number of action names. We then
+ run the grammar again, but this time allowing it to print comments on each apparent
+ action name it sees.
-
-
Instead of taking or dropping the magnet: ...
-
-
-
then the anl-diagnosis grammar will parse this and return N equal to 2, the
-apparent number of action names. We then run the grammar again, but this time
-allowing it to print comments on each apparent action name it sees.
-
-
-
Break down the action list and say which are okay13.1.1.1.5.3 =
+
Break down the action list and say which are okay10.1.1.5.3 =
issuing_ANL_problem = FALSE; NAP_problem_explained = FALSE;
-<anl-diagnosis>(rfd->rule_parameter);
+<anl-diagnosis>(rfd->applicability);intN = <<r>>;if (N > 1) {intpositive = TRUE;
-ActionNameLists::parse(rfd->rule_parameter, IS_TENSE, &positive);
+ActionNameLists::parse(rfd->applicability, IS_TENSE, &positive);if (positive == FALSE)Problems::issue_problem_segment(" This looks like a list of actions to avoid: ");
@@ -917,105 +805,100 @@ allowing it to print comments on each apparent action name it sees.
Problems::issue_problem_segment(" Looking at this as a list of alternative actions: ");issuing_ANL_problem = TRUE; NAP_problem_explained = FALSE;
-<anl-diagnosis>(rfd->rule_parameter);
+<anl-diagnosis>(rfd->applicability);Problems::issue_problem_segment(" so"); }
StandardProblems::sentence_problem(Task::syntax_tree(), _p_(PM_WhenThePlay),"there's no scene called 'the play'",
-"so I think you need to remove 'the' - Inform has two "
-"special rulebooks, 'When play begins' and 'When play ends', "
-"and I think you probably mean to refer to one of those.");
+"so I think you need to remove 'the' - Inform has two special rulebooks, 'When "
+"play begins' and 'When play ends', and I think you probably mean to refer to "
+"one of those.");
StandardProblems::handmade_problem(Task::syntax_tree(), _p_(PM_BadParameter));Problems::issue_problem_segment(
-"You wrote %1, but the description of the thing(s) to which the rule "
-"applies ('%2') did not make sense. This is %3 based rulebook, so "
-"that should have described %3.");
+"You wrote %1, but the description of the thing(s) to which the rule applies ('%2') "
+"did not make sense. This is %3 based rulebook, so that should have described %3.");Problems::issue_problem_end();
StandardProblems::handmade_problem(Task::syntax_tree(), _p_(PM_NonActionInPresenceOf));Problems::issue_problem_segment(
-"You wrote %1, but 'in the presence of...' is a clause which can "
-"only be used to talk about an action: so, for instance, 'waiting "
-"in the presence of...' is needed. "
-"This problem arises especially with 'every turn' rules, where "
-"'every turn in the presence of...' looks plausible but doesn't "
-"work. This could be fixed by writing 'Every turn doing something "
-"in the presence of...', but a neater solution talks about the "
-"current situation instead: 'Every turn when the player can "
-"see...'.");
+"You wrote %1, but 'in the presence of...' is a clause which can only be used to "
+"talk about an action: so, for instance, 'waiting in the presence of...' is needed. "
+"This problem arises especially with 'every turn' rules, where 'every turn in the "
+"presence of...' looks plausible but doesn't work. This could be fixed by writing "
+"'Every turn doing something in the presence of...', but a neater solution talks "
+"about the current situation instead: 'Every turn when the player can see...'.");Problems::issue_problem_end();
StandardProblems::handmade_problem(Task::syntax_tree(), _p_(PM_NonActionIn));Problems::issue_problem_segment(
-"You wrote %1, but 'in...' used in this way should really belong "
-"to an action: for instance, 'Before waiting in the Library'. "
-"Rules like 'Every turn in the Library' don't work, because "
-"'every turn' is not an action; what's wanted is 'Every turn "
+"You wrote %1, but 'in...' used in this way should really belong to an action: for "
+"instance, 'Before waiting in the Library'. Rules like 'Every turn in the Library' "
+"don't work, because 'every turn' is not an action; what's wanted is 'Every turn ""when in the Library'.");Problems::issue_problem_end();
§14. The following is used to choose a problem when the trouble with the rule
occurred in a when/while condition at the end; while all five cases produce
the PM_APWithBadWhen problem, they each provide different clues as to what
might have gone wrong.
@@ -1023,16 +906,12 @@ might have gone wrong.
§18.1. Diagnose problem with this ANL entry18.1 =
+
§14.1. Diagnose problem with this ANL entry14.1 =
if ((issuing_ANL_problem) && (!preform_lookahead_mode)) {Problems::quote_wording(4, W);
- #ifdefIF_MODULEif (<action-pattern>(W) == FALSE) {Problems::issue_problem_segment("'%4' did not make sense; ");returnTRUE;
@@ -1092,20 +970,18 @@ might have gone wrong.
"which isn't allowed in a list like this; ");returnTRUE; }
- #endifProblems::issue_problem_segment("'%4' was okay; "); } ==> { 1, - };
§15. Compilation. We compile these in rulebook order first, and then pick up any rules not in
+rulebooks. This is really just to make the Inter output tidily arranged;
+any order would have done just as well.
+
diff --git a/docs/assertions-module/5-tpf.html b/docs/assertions-module/5-tpf.html
index c53def4a6..e5938baa4 100644
--- a/docs/assertions-module/5-tpf.html
+++ b/docs/assertions-module/5-tpf.html
@@ -87,7 +87,8 @@ function togglePopup(material_id) {
structwordingpattern;structwordingprototype_text;structwordingconstant_name;
-structconstant_phrase *constant_phrase_holder;
+structwordingph_documentation_symbol; the documentation reference, if any
+structconstant_phrase *constant_phrase_holder;intexplicit_name_used_in_maths; if so, this flag means it's like log() or sin()structwordingexplicit_name_for_inverse; e.g. exp for logintto_begin; used in Basic mode only: this is to be the main phrase
@@ -100,12 +101,11 @@ function togglePopup(material_id) {
@@ -231,9 +233,9 @@ mode, we can get that value back again if we look it up by name.
wordingNW = tfd->constant_name;
-constant_phrase *cphr = Phrases::Constants::parse(NW);
-if (Kinds::Behaviour::definite(cphr->cphr_kind) == FALSE) {
-phrase *ph = Phrases::Constants::as_phrase(cphr);
+constant_phrase *cphr = ToPhraseFamily::parse_constant(NW);
+if (Kinds::Behaviour::definite(cphr->cphr_kind) == FALSE) {
+phrase *ph = ToPhraseFamily::body_of_constant(cphr);if (ph) current_sentence = Phrases::declaration_node(ph);Problems::quote_source(1, Diagrams::new_UNPARSED_NOUN(Nouns::nominative_singular(cphr->name)));Problems::quote_wording(2, Nouns::nominative_singular(cphr->name));
@@ -246,7 +248,7 @@ mode, we can get that value back again if we look it up by name.
"for every setting where it might be needed, and we can't ""predict in advance which one '%2' might need to be.");Problems::issue_problem_end();
-LOG("CPHR failed at %d, %u\n", cphr->allocation_id, cphr->cphr_kind);
+LOG("CPHR failed at %d, %u\n", cphr->allocation_id, cphr->cphr_kind); }tfd->constant_phrase_holder = cphr;
@@ -254,29 +256,31 @@ mode, we can get that value back again if we look it up by name.
§9.
-voidToPhraseFamily::register(imperative_defn_family *self, intinitial_problem_count) {
+voidToPhraseFamily::register(imperative_defn_family *self) {Routines::ToPhrases::register_all();}
-voidToPhraseFamily::new_phrase(imperative_defn_family *self, imperative_defn *id, phrase *new_ph) {
+voidToPhraseFamily::given_body(imperative_defn_family *self, imperative_defn *id) {to_family_data *tfd = RETRIEVE_POINTER_to_family_data(id->family_specific_data);
-if (tfd->to_begin) new_ph->to_begin = TRUE;
-Routines::ToPhrases::new(new_ph);
+if (tfd->to_begin) id->body_of_defn->to_begin = TRUE;
+
+wordingXW = ToPhraseFamily::get_prototype_text(id);
+wordingOW = EMPTY_WORDING;
+Phrases::TypeData::Textual::parse(&(id->body_of_defn->type_data), XW, &OW);
+Phrases::Options::parse_declared_options(&(id->body_of_defn->options_data), OW);
+
+Routines::ToPhrases::new(id->body_of_defn);}intToPhraseFamily::allows_inline(imperative_defn_family *self, imperative_defn *id) {returnTRUE;}
-voidToPhraseFamily::to_phtd(imperative_defn_family *self, imperative_defn *id, ph_type_data *phtd, wordingXW, wording *OW) {
-Phrases::TypeData::Textual::parse(phtd, XW, OW);
-}
-
-intToPhraseFamily::include_in_Phrasebook_index(imperative_defn_family *self, imperative_defn *id) {
+intToPhraseFamily::include_in_Phrasebook_index(imperative_defn_family *self, imperative_defn *id) {returnTRUE;}
-phrase *ToPhraseFamily::inverse(imperative_defn *id) {
+phrase *ToPhraseFamily::inverse(imperative_defn *id) {if (id->family != TO_PHRASE_EFF_family) returnNULL;to_family_data *tfd = RETRIEVE_POINTER_to_family_data(id->family_specific_data);if (Wordings::nonempty(tfd->explicit_name_for_inverse)) {
@@ -291,7 +295,7 @@ mode, we can get that value back again if we look it up by name.
returnNULL;}
-constant_phrase *ToPhraseFamily::constant_phrase(imperative_defn *id) {
+constant_phrase *ToPhraseFamily::constant_phrase(imperative_defn *id) {if (id->family != TO_PHRASE_EFF_family) returnNULL;to_family_data *tfd = RETRIEVE_POINTER_to_family_data(id->family_specific_data);returntfd->constant_phrase_holder;
@@ -319,18 +323,24 @@ mode, we can get that value back again if we look it up by name.
returnWordings::first_word(Nouns::nominative_singular(tfd->constant_phrase_holder->name));returnEMPTY_WORDING;}
+
+wordingToPhraseFamily::doc_ref(imperative_defn *id) {
+if (id->family != TO_PHRASE_EFF_family) returnEMPTY_WORDING;
+to_family_data *tfd = RETRIEVE_POINTER_to_family_data(id->family_specific_data);
+returntfd->ph_documentation_symbol;
+}
§10. Extracting the stem. A couple of routines to read but not really parse the stem and the bud.
-wordingToPhraseFamily::get_prototype_text(imperative_defn *id) {
+wordingToPhraseFamily::get_prototype_text(imperative_defn *id) {if (id->family != TO_PHRASE_EFF_family) returnEMPTY_WORDING;to_family_data *tfd = RETRIEVE_POINTER_to_family_data(id->family_specific_data);returntfd->prototype_text;}
-voidToPhraseFamily::compile(imperative_defn_family *self,
+voidToPhraseFamily::compile(imperative_defn_family *self,int *total_phrases_compiled, inttotal_phrases_to_compile) {Mark To... phrases which have definite kinds for future compilation10.1;Throw problems for phrases with return kinds too vaguely defined10.2;
@@ -465,7 +475,7 @@ hand over to the others to generate more work.
-voidToPhraseFamily::compile_as_needed(imperative_defn_family *self,
+voidToPhraseFamily::compile_as_needed(imperative_defn_family *self,int *total_phrases_compiled, inttotal_phrases_to_compile) {intrepeat = TRUE;while (repeat) {
@@ -486,6 +496,97 @@ hand over to the others to generate more work.
}}
+
§12. A few "To..." phrases have names, and can therefore be used as values in their
+own right, a functional-programming sort of device. For example:
+
+
+
+
To decide what number is double (N - a number) (this is doubling):
+
+
+
has the name "doubling". Such a name is recorded here:
+
+
+
+typedefstructconstant_phrase {
+structnoun *name;
+structphrase *phrase_meant; if known at this point
+structkind *cphr_kind; ditto
+structinter_name *cphr_iname;
+structwordingassociated_preamble_text;
+CLASS_DEFINITION
+} constant_phrase;
+
+
The structure constant_phrase is accessed in 3/nuor, 3/dbtr, 3/rpr, 4/ass, 6/tc, 6/tbl, 6/eqt and here.
+
§13. Here we create a new named phrase ("doubling", say):
+
+
+
+constant_phrase *ToPhraseFamily::create_constant(wordingNW, wordingRW) {
+constant_phrase *cphr = CREATE(constant_phrase);
+cphr->phrase_meant = NULL; we won't know until later
+cphr->cphr_kind = NULL; nor this
+cphr->associated_preamble_text = RW;
+cphr->name = Nouns::new_proper_noun(NW, NEUTER_GENDER, ADD_TO_LEXICON_NTOPT,
+PHRASE_CONSTANT_MC, Rvalues::from_constant_phrase(cphr), Task::language_of_syntax());
+cphr->cphr_iname = NULL;
+returncphr;
+}
+
§15. As often happens with Inform constants, the kind of a constant phrase can't
+be known when its name first comes up, and must be filled in later. (In
+particular, before the second traverse many kinds do not yet exist.) So
+the following takes a patch-it-later approach.
+
diff --git a/docs/core-module/1-cp.html b/docs/core-module/1-cp.html
index 11f952e64..48dde19c3 100644
--- a/docs/core-module/1-cp.html
+++ b/docs/core-module/1-cp.html
@@ -87,6 +87,7 @@ We begin with core itself.
enumadjective_meaning_family_CLASSenumapplication_CLASSenumby_routine_bp_data_CLASS
+enumconstant_phrase_CLASSenumequivalence_bp_data_CLASSenumexplicit_bp_data_CLASSenumgeneralisation_CLASS
@@ -106,6 +107,7 @@ We begin with core itself.
DECLARE_CLASS(adjective_meaning)DECLARE_CLASS(adjective_meaning_family)DECLARE_CLASS_ALLOCATED_IN_ARRAYS(application, 100)
+DECLARE_CLASS(constant_phrase)DECLARE_CLASS(generalisation)DECLARE_CLASS(by_routine_bp_data)DECLARE_CLASS(equivalence_bp_data)
@@ -227,8 +229,7 @@ We begin with core itself.
enuminvocation_options_CLASSenumlocal_variable_CLASSenumpast_tense_action_record_CLASSenumpast_tense_condition_record_CLASS
@@ -238,10 +239,8 @@ We begin with core itself.
enumphrase_option_CLASSenumpointer_allocation_CLASSenumto_phrase_request_CLASS
-enumuse_as_event_CLASS
-DECLARE_CLASS(constant_phrase)DECLARE_CLASS_ALLOCATED_IN_ARRAYS(invocation_options, 100)DECLARE_CLASS_ALLOCATED_IN_ARRAYS(local_variable, 100)DECLARE_CLASS(past_tense_action_record)
@@ -252,7 +251,6 @@ We begin with core itself.
DECLARE_CLASS_ALLOCATED_IN_ARRAYS(phrase_option, 100)DECLARE_CLASS(pointer_allocation)DECLARE_CLASS(to_phrase_request)
-DECLARE_CLASS(use_as_event)
@@ -347,6 +345,7 @@ We begin with core itself.
enumrelease_instructions_CLASSenumscene_CLASSenumspatial_data_CLASS
+enumtimed_rules_rfd_data_CLASSenumanl_clause_CLASSenumanl_entry_CLASSenumaction_pattern_CLASS
@@ -380,6 +379,7 @@ We begin with core itself.
DECLARE_CLASS(release_instructions)DECLARE_CLASS(scene)DECLARE_CLASS(spatial_data)
+DECLARE_CLASS(timed_rules_rfd_data)DECLARE_CLASS_ALLOCATED_IN_ARRAYS(anl_clause, 1000)DECLARE_CLASS_ALLOCATED_IN_ARRAYS(anl_entry, 1000)
diff --git a/docs/core-module/1-htc.html b/docs/core-module/1-htc.html
index ab1b22995..d4a745b62 100644
--- a/docs/core-module/1-htc.html
+++ b/docs/core-module/1-htc.html
@@ -369,9 +369,6 @@ so on. Those absolute basics are made here.
BENCH(Phrases::Constants::compile_closures)BENCH(RTKinds::compile_structures)BENCH(Rules::check_response_usages)
-BENCH(Phrases::Timed::check_for_unused)
-BENCH(Phrases::Timed::TimedEventsTable)
-BENCH(Phrases::Timed::TimedEventTimesTable)BENCH(RTUseOptions::configure_template)BENCH(RTBibliographicData::IFID_text);
diff --git a/docs/core-module/3-pc.html b/docs/core-module/3-pc.html
index e288f3794..a10f7a734 100644
--- a/docs/core-module/3-pc.html
+++ b/docs/core-module/3-pc.html
@@ -72,7 +72,7 @@ function togglePopup(material_id) {
§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
@@ -285,7 +285,18 @@ is now being assigned a value by an explicit assertion sentence.
PLUGINS_CALL(VARIABLE_VALUE_NOTIFY_PLUG, q, val);}
-
§16. Influencing values. Called from Rvalues (in values) to allow plugins to help decide whether values
+
§16. Called from Rule Family (in assertions) to warn plugins that a new rule
+definition has been found in the source text.
+
§17. Influencing values. Called from Rvalues (in values) to allow plugins to help decide whether values
of the same kind would be equal if evaluated at runtime. For example, the
"scenes" plugin uses this to determine if two K_scene constants are equal.
To make a decision, set rv to either TRUE or FALSE and return TRUE.
@@ -299,7 +310,7 @@ To make no decision, return F
PLUGINS_CALL(COMPARE_CONSTANT_PLUG, c1, c2, rv);}
-
§17. Called from Rvalues (in values) to allow plugins to compile rvalues in
+
§18. Called from Rvalues (in values) to allow plugins to compile rvalues in
eccentric ways of their own: not in fact just for the whimsy of it, but to
make it possible for plugins to support base kinds of their own. For example,
the "actions" plugin needs this to deal with the "stored action" kind.
@@ -312,7 +323,7 @@ the "actions" plugin needs this to deal with the "stored action" kind.
PLUGINS_CALL(COMPILE_CONSTANT_PLUG, VH, K, spec);}
-
§19. Called from Conditions (in values) to allow plugins to compile conditions in
their own way. For example, the "actions" plugin needs this to compile matches
of the current action against an action pattern.
@@ -324,7 +335,7 @@ of the current action against an action pattern.
PLUGINS_CALL(COMPILE_CONDITION_PLUG, VH, spec);}
-
§20. Called from Specifications (in values) to ask if there is some reason why
a rule about I1 should be thought broader in scope than one about I2. This
is used by the regions plugin when one is a sub-region of the other. This is
expected to behave as a strcmp-like sorting function, with a positive
@@ -338,7 +349,7 @@ return value saying I1PLUGINS_CALL(MORE_SPECIFIC_PLUG, I1, I2);}
-
§21. Called from Constants and Descriptions (in values) to give plugins a chance
to parse text which might otherwise be meaningless (or mean something different)
and make it a "composite noun-quantifier" such as "everywhere" or "nothing".
The main compiler does not recognise "everywhere" because it has no concept
@@ -353,7 +364,7 @@ of space, but the spatial plugin does, and this is how.
PLUGINS_CALL(PARSE_COMPOSITE_NQS_PLUG, W, DW, quantifier_used, some_kind);}
-
§22. Influencing knowledge. Called from The Model World (in knowledge) to invite the plugin to participate
in stages I to V of the completion process. This may involve using contextual
reasoning to draw further inferences.
@@ -365,7 +376,7 @@ reasoning to draw further inferences.
PLUGINS_CALL(COMPLETE_MODEL_PLUG, stage);}
-
§23. Called from Inference Subjects (in knowledge) to invite the plugin to
create any additional inference subjects it might want to reason about. In
practice, this tends to be used to create preliminary subjects to stand in
for significant kinds before those kinds are ready to be created.
@@ -378,7 +389,7 @@ for significant kinds before those kinds are ready to be created.
PLUGINS_CALLV(CREATE_INFERENCE_SUBJECTS_PLUG);}
-
§24. Called from Indefinite Appearance (in knowledge) to ask the plugins what
inferences, if any, to draw from a double-quoted text standing as an entire
sentence. The infs is the subject which was being talked about at the time
the text was quoted, and therefore presumably is what the text should describe.
@@ -391,7 +402,7 @@ the text was quoted, and therefore presumably is what the text should describe.
PLUGINS_CALL(DEFAULT_APPEARANCE_PLUG, infs, txt);}
-
§25. Called from Inferences (in knowledge) when an inference is drawn about
something. This does not, of course, necessarily mean that this will actually
be the property of something: the inference might turn out to be mistaken. The
mapping plugin uses this to infer further that if something is said to be a
@@ -405,7 +416,7 @@ map connection to somewhere else, then it is probably a room.
PLUGINS_CALL(INFERENCE_DRAWN_NOTIFY_PLUG, I, subj);}
-
§26. Called from Kind Subjects (in knowledge). Early in the run, before some kinds
are created, placeholder inference subjects are created to stand in for them;
this call enables plugins to recognise certain texts as referring to those.
@@ -417,7 +428,7 @@ this call enables plugins to recognise certain texts as referring to those.
PLUGINS_CALL(NAME_TO_EARLY_INFS_PLUG, W, infs);}
-
§27. Called from Kind Subjects (in knowledge) to warn plugins about a new kind,
which in practice enables them to spot from the name that it is actually a kind
they want to provide built-in support for: thus the actions plugin reacts to
the name "stored action", for example. K is the newcomer, super its super-kind,
@@ -433,7 +444,7 @@ source text (such as "container").
PLUGINS_CALL(NEW_BASE_KIND_NOTIFY_PLUG, K, d, W);}
-
§28. Called from Instances (in knowledge) to warn plugins that a new instance has
been created. For example, the figures plugin needs to know this so that it
can see when a new illustration has been created.
@@ -450,7 +461,7 @@ sure you're not dealing with an object.
PLUGINS_CALL(NEW_INSTANCE_NOTIFY_PLUG, nc);}
-
§29. Called from Property Permissions (in knowledge) to warn plugins that a subject
has been given permission to hold a property; the parsing plugin, for example,
uses this to attach a visibility flag.
@@ -462,7 +473,7 @@ uses this to attach a visibility flag.
PLUGINS_CALL(NEW_PERMISSION_NOTIFY_PLUG, pp);}
-
§30. Called from Properties (in knowledge) to warn plugins that a property has
been created, which they can use to spot properties with special significance
to them.
@@ -474,7 +485,7 @@ to them.
PLUGINS_CALL(NEW_PROPERTY_NOTIFY_PLUG, prn);}
-
§31. Called from Inference Subjects (in knowledge) to warn plugins that a subject
has been created, which they can use to spot subjects with special significance
to them.
@@ -486,7 +497,7 @@ to them.
PLUGINS_CALL(NEW_SUBJECT_NOTIFY_PLUG, subj);}
-
§32. Called from Nonlocal Variables (in knowledge) to warn plugins that a new
variable has been created, which they can use to spot variables with special
significance to them.
@@ -498,7 +509,7 @@ significance to them.
PLUGINS_CALL(NEW_VARIABLE_NOTIFY_PLUG, q);}
-
§33. Called from Instances (in knowledge) to warn plugins that the kind of an
instance is about to be set. This happens most often when the instance is
created, but can also happen again, refining the kind to a subkind, when
the instance is an object.
@@ -511,7 +522,7 @@ the instance is an object.
PLUGINS_CALL(SET_KIND_NOTIFY_PLUG, I, k);}
-
§34. Called from Kind Subjects (in knowledge) when one kind of object is made a
subkind of another, as for example when "container" is a made a subkind of
"thing". The plugin should return TRUE if it wishes to forbid this,
and if so, it had better throw a problem message, or the user will be
@@ -529,7 +540,7 @@ regions plugin does with the "region" kind.
PLUGINS_CALL(SET_SUBKIND_NOTIFY_PLUG, sub, super);}
-
§34. Influencing the imperative plugin. Called from Rule Bookings (in imperative) to give plugins a chance to move
+
§35. 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.
@@ -546,7 +557,7 @@ and return TRUEPLUGINS_CALL(PLACE_RULE_PLUG, R, original_owner, new_owner);}
-
§41. 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.
@@ -604,7 +627,7 @@ the going action variables.
PLUGINS_CALL(DIVERT_AP_CLAUSE_PLUG, stv, id);}
-
§42. 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.
@@ -615,7 +638,7 @@ name for the debugging log for any new clause ID PLUGINS_CALL(WRITE_AP_CLAUSE_ID_PLUG, OUT, C);}
-
§43. 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.
@@ -627,7 +650,7 @@ this is not given, then the aspect will be PLUGINS_CALL(ASPECT_OF_AP_CLAUSE_ID_PLUG, C, A);}
-
§44. 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.
@@ -651,7 +674,7 @@ to let the usual machinery take its course.
PLUGINS_CALL(COMPARE_AP_SPECIFICITY_PLUG, ap1, ap2, rv, ignore_in);}
-
§46. 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
@@ -681,7 +704,7 @@ text of the clause in the normal way.
PLUGINS_CALL(PARSE_AP_CLAUSE_PLUG, an, c, bits);}
-
§47. 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.
@@ -699,7 +722,7 @@ or FALSE (it is
PLUGINS_CALL(VALIDATE_AP_CLAUSE_PLUG, an, c, outcome);}
-
§49. 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.
@@ -723,7 +746,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);}
-
§51. 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.
@@ -747,7 +770,7 @@ the regions plugin uses this to put colour chips next to names of regions.
PLUGINS_CALL(ADD_TO_WORLD_INDEX_PLUG, OUT, O);}
-
§52. 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/1-im.html b/docs/if-module/1-im.html
index 069c75984..2fad16b3d 100644
--- a/docs/if-module/1-im.html
+++ b/docs/if-module/1-im.html
@@ -167,7 +167,7 @@ nothing except to be a parent to them; it has no activation function.
*backdrops_plugin, *bibliographic_plugin, *chronology_plugin, *devices_plugin, *map_plugin, *parsing_plugin, *persons_plugin, *player_plugin, *regions_plugin, *scenes_plugin, *scoring_plugin, *showme_plugin, *spatial_plugin,
- *times_plugin;
+ *timed_rules_plugin, *times_plugin;
§5.
@@ -188,6 +188,7 @@ nothing except to be a parent to them; it has no activation function.
regions_plugin = PluginManager::new(&Regions::start, I"regions", ifp);scenes_plugin = PluginManager::new(&Scenes::start, I"scenes", ifp);scoring_plugin = PluginManager::new(&TheScore::start, I"scoring", ifp);
+timed_rules_plugin = PluginManager::new(TimedRules::start, I"timed rules", ifp);times_plugin = PluginManager::new(TimesOfDay::start, I"times of day", ifp);actions_plugin = PluginManager::new(&ActionsPlugin::start, I"actions", ifp);
diff --git a/docs/if-module/3-bck.html b/docs/if-module/3-bck.html
index 03fd9e771..3b820520e 100644
--- a/docs/if-module/3-bck.html
+++ b/docs/if-module/3-bck.html
@@ -405,7 +405,7 @@ backdrop.
}
diff --git a/docs/if-module/3-dvc.html b/docs/if-module/3-dvc.html
index 6ce846a51..f44518a23 100644
--- a/docs/if-module/3-dvc.html
+++ b/docs/if-module/3-dvc.html
@@ -117,7 +117,7 @@ is no need to translate this.
}
diff --git a/docs/if-module/3-enah.html b/docs/if-module/3-enah.html
index 872e9668b..4020b04c9 100644
--- a/docs/if-module/3-enah.html
+++ b/docs/if-module/3-enah.html
@@ -304,7 +304,7 @@ and put the issue aside for now.
}
diff --git a/docs/if-module/3-mcr.html b/docs/if-module/3-mcr.html
index e5bc17725..874822b65 100644
--- a/docs/if-module/3-mcr.html
+++ b/docs/if-module/3-mcr.html
@@ -337,7 +337,7 @@ such.
}
diff --git a/docs/if-module/3-prs.html b/docs/if-module/3-prs.html
index 8b8bbfa90..cdd049dcf 100644
--- a/docs/if-module/3-prs.html
+++ b/docs/if-module/3-prs.html
@@ -102,7 +102,7 @@ tomfoolery.
}
diff --git a/docs/if-module/3-rgn.html b/docs/if-module/3-rgn.html
index b4900ead2..4e340b93f 100644
--- a/docs/if-module/3-rgn.html
+++ b/docs/if-module/3-rgn.html
@@ -450,7 +450,7 @@ to be a region already:
§1. This plugin makes a special set of rules for timed events; the :timedrules
+test group may be useful in testing it.
+
+
+
Each such rule has a time at which it should spontaneously happen. This is
+ordinarily a time of day, such as "At 9:00 AM: ...", represented by a number
+from 0 to 1439, measuring minutes since midnight. These negative values have
+special significance:
+
+
+
defineNOT_A_TIMED_EVENT -1 as for the vast majority of rules
+defineNO_FIXED_TIME -2 for phrases like "When the clock strikes: ..."
+defineNOT_AN_EVENT -3 not even syntactically
+
+StandardProblems::sentence_problem(Task::syntax_tree(), _p_(PM_AtTimeThat),
+"this seems to use 'that' where it should use 'when'",
+"assuming it's trying to apply a rule to an event. (The convention is that any "
+"rule beginning 'At' is a timed one. The time can either be a fixed time, as in "
+"'At 11:10 AM: ...', or the time when some named event takes place, as in 'At the "
+"time when the clock chimes: ...'.)");
+
+StandardProblems::sentence_problem(Task::syntax_tree(), _p_(PM_AtWithoutTime),
+"'at' what time? No description of a time is given",
+"which means that this rule can never have effect. (The convention is that any "
+"rule beginning 'At' is a timed one. The time can either be a fixed time, as in "
+"'At 11:10 AM: ...', or the time when some named event takes place, as in 'At the "
+"time when the clock chimes: ...'.)");
+
§4. The above therefore attaches one of these to each set of rule data:
+
+
+
+typedefstructtimed_rules_rfd_data {
+intevent_time; 0 to 1339, or one of the special values above
+structwordingevent_name; if one is given
+structlinked_list *uses_as_event; of parse_node
+CLASS_DEFINITION
+} timed_rules_rfd_data;
+
+timed_rules_rfd_data *TimedRules::new_rfd_data(rule_family_data *rfd) {
+timed_rules_rfd_data *trfd = CREATE(timed_rules_rfd_data);
+trfd->event_time = NOT_A_TIMED_EVENT;
+trfd->event_name = EMPTY_WORDING;
+trfd->uses_as_event = NEW_LINKED_LIST(parse_node);
+returntrfd;
+}
+
+
The structure timed_rules_rfd_data is private to this section.
§6. When a rule has no explicit timing, it needs to be triggered by a phrase
+like "spawn fresh zombies in 4 turns from now". Here, "spawn fresh zombies"
+is the name of the rule. But this has the same kind as any other rule, so
+the Dash typechecker is not able to make sure "spawn fresh zombies" is indeed
+timed, and not some other rule.
+
+
+
We fix this by defining the trigger phrase to use the inline annotation
+{-mark-event-used:R} on the rule R. That in turn results in the following
+being called:
+
+Problems::quote_source(1, current_sentence);
+Problems::quote_wording(2, Node::get_text(supplied));
+StandardProblems::handmade_problem(Task::syntax_tree(), _p_(PM_NonconstantEvent));
+Problems::issue_problem_segment(
+"You wrote %1, but '%2' isn't the name of any timed event that I know of. "
+"(These need to be set up in a special way, like so - 'At the time when stuff "
+"happens: ...' creates a timed event called 'stuff happens'.)");
+Problems::issue_problem_end();
+
§7. An interesting case where the Problem is arguably only a warning and arguably
+shouldn't block compilation. Then again...
+
+
+
+voidTimedRules::check_for_unused(void) {
+imperative_defn *id;
+LOOP_OVER(id, imperative_defn)
+if (TimedRules::get_timing_of_event(id) == NO_FIXED_TIME)
+if (LinkedLists::len(TimedRules::get_uses_as_event(id)) == 0) {
+current_sentence = id->at;
+StandardProblems::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.)");
+ }
+}
+
+
+
+
+
+
+
diff --git a/docs/if-module/3-ts.html b/docs/if-module/3-ts.html
index 4451cef94..8bf0a56a9 100644
--- a/docs/if-module/3-ts.html
+++ b/docs/if-module/3-ts.html
@@ -173,7 +173,7 @@ be the score corresponding to successful completion and the highest rank.
}
diff --git a/docs/if-module/4-ap2.html b/docs/if-module/4-ap2.html
index 420d5e746..f9da908c6 100644
--- a/docs/if-module/4-ap2.html
+++ b/docs/if-module/4-ap2.html
@@ -193,11 +193,22 @@ of the text they came from; for which, see }}
-
§6. This simple parser converts text to a parametric AP of kind K. The parser
-for action-based APs is very much more complicated: see Parse Action Patterns.
+
§6. These functions are used when parsing rule applicability:
-
+ A plugin to support rules like "At 12:03AM: ...".
+
Scenes -
diff --git a/docs/imperative-module/1-im.html b/docs/imperative-module/1-im.html
index 26c768767..bfce8c4f8 100644
--- a/docs/imperative-module/1-im.html
+++ b/docs/imperative-module/1-im.html
@@ -88,7 +88,7 @@ which use this module:
COMPILE_WRITER(parse_node *, Invocations::log)COMPILE_WRITER(ph_type_data *, Phrases::TypeData::Textual::log)COMPILE_WRITER(local_variable *, LocalVariables::log)
-COMPILE_WRITER(phrase *, Phrases::log)
+COMPILE_WRITER(phrase *, Phrases::log)voidImperativeModule::start(void) {Writers::register_writer('L', &LocalVariables::writer);
@@ -96,7 +96,7 @@ which use this module:
REGISTER_WRITER('e', Invocations::log);REGISTER_WRITER('h', Phrases::TypeData::Textual::log);REGISTER_WRITER('k', LocalVariables::log);
-REGISTER_WRITER('R', Phrases::log);
+REGISTER_WRITER('R', Phrases::log);Memory::reason_name(INV_LIST_MREASON, "lists for type-checking invocations");Log::declare_aspect(DESCRIPTION_COMPILATION_DA, L"description compilation", FALSE, FALSE);Log::declare_aspect(EXPRESSIONS_DA, L"expressions", FALSE, FALSE);
diff --git a/docs/imperative-module/2-act.html b/docs/imperative-module/2-act.html
index 4f2d8a841..be051f9d6 100644
--- a/docs/imperative-module/2-act.html
+++ b/docs/imperative-module/2-act.html
@@ -92,7 +92,7 @@ and a shared set of variables, so this will not be a long section of code.
CLASS_DEFINITION} activity;
-
The structure activity is accessed in 2/rls, 2/rlb, 2/fao, 3/prcd, 3/po, 3/pav, 4/sv, 6/cii, 6/cste and here.
+
The structure activity is accessed in 2/rls, 2/rlb, 2/fao, 3/prcd, 3/po, 4/sv, 6/cii, 6/cste and here.
§2. Whereas rulebooks can turn values into other values, activities are more like
void functions: they work on a value, but produce nothing.
§5. That awkward distinction between a rulebook_outcome and a named_rulebook_outcome
brings us edge cases if a rule has been written for use in one rulebook, but then
has been explicitly listed in another, or is more than one rulebook.
diff --git a/docs/imperative-module/2-rls.html b/docs/imperative-module/2-rls.html
index c29e1cc89..a35be068d 100644
--- a/docs/imperative-module/2-rls.html
+++ b/docs/imperative-module/2-rls.html
@@ -124,7 +124,7 @@ different dynamics altogether. In short, then: rules are not phrases.
CLASS_DEFINITION} rule;
-
The structure rule is accessed in 2/rlb, 2/fao, 2/act, 3/prcd, 3/po, 3/pav, 4/sv, 6/cii, 6/cste and here.
+
The structure rule is accessed in 2/rlb, 2/fao, 2/act, 3/prcd, 3/po, 4/sv, 6/cii, 6/cste and here.
§2. Rules are created before their definitions can be parsed or compiled. A
typical rule like so:
voidRules::set_imperative_definition(rule *R, imperative_defn *id) {R->defn_as_I7_source = id;
+RTRules::prepare_rule(id, R);}
-imperative_defn *Rules::get_imperative_definition(rule *R) {
+imperative_defn *Rules::get_imperative_definition(rule *R) {if (R == NULL) returnNULL;returnR->defn_as_I7_source;}
@@ -651,7 +652,7 @@ possibility we store one of these:
returnR->responses[code].used;}
-
The structure rule_response is accessed in 3/prcd and here.
+
The structure rule_response is private to this section.
§21. When a response is defined in the body of a rule, the message is
created with Rules::set_response:
diff --git a/docs/imperative-module/3-dptd.html b/docs/imperative-module/3-dptd.html
index 91491c21e..510cd1565 100644
--- a/docs/imperative-module/3-dptd.html
+++ b/docs/imperative-module/3-dptd.html
@@ -119,7 +119,7 @@ The debugging log is simple:
-voidPhrases::TypeData::Textual::log_briefly(ph_type_data *phtd) {
+voidPhrases::TypeData::Textual::log_briefly(ph_type_data *phtd) {if (phtd == NULL) { LOG("NULL-PHTD"); return; }LOG("\"%W\"", phtd->registration_text);switch(phtd->manner_of_return) {
@@ -142,7 +142,7 @@ match is shown.
defineINDEX_PHRASE_FORMAT2 a simpler version good enough for most purposes
-voidPhrases::TypeData::Textual::write_HTML_representation(OUTPUT_STREAM,
+voidPhrases::TypeData::Textual::write_HTML_representation(OUTPUT_STREAM,ph_type_data *phtd, intpaste_format, parse_node *inv) {intseq_from = 0, seq_to = phtd->no_words;
@@ -304,9 +304,9 @@ match is shown.
phrase *ph = Node::get_phrase_invoked(inv);if (ph) {ph_type_data *phtd = &(ph->type_data);
-if (Wordings::nonempty(ph->ph_documentation_symbol)) {
+if (Wordings::nonempty(ToPhraseFamily::doc_ref(ph->from))) {TEMPORARY_TEXT(pds)
-WRITE_TO(pds, "%+W", Wordings::one_word(Wordings::first_wn(ph->ph_documentation_symbol)));
+WRITE_TO(pds, "%+W", Wordings::one_word(Wordings::first_wn(ToPhraseFamily::doc_ref(ph->from))));Index::DocReferences::link_to(OUT, pds, -1);DISCARD_TEXT(pds) } else
@@ -329,7 +329,7 @@ match is shown.
voidPhrases::TypeData::Textual::write_index_representation(OUTPUT_STREAM, ph_type_data *phtd, phrase *ph) {if (phtd->manner_of_return == DECIDES_CONDITION_MOR)WRITE("<i>if</i> ");
-Phrases::write_HTML_representation(OUT, ph, INDEX_PHRASE_FORMAT);
+Phrases::write_HTML_representation(OUT, ph, INDEX_PHRASE_FORMAT);if (phtd->return_kind == NULL) {if (phtd->manner_of_return == DECIDES_CONDITION_MOR) WRITE("<i>:</i>"); } else {
@@ -368,7 +368,7 @@ This is the routine which prints those details.
-voidPhrases::TypeData::Textual::parse(ph_type_data *phtd, wordingXW, wording *OW) {
+voidPhrases::TypeData::Textual::parse(ph_type_data *phtd, wordingXW, wording *OW) {intsay_flag = FALSE; is this going to be a "say" phrase?if (Wordings::nonempty(XW)) XW = Phrases::TypeData::Textual::phtd_parse_return_data(phtd, XW); trim return data from the front
@@ -716,7 +716,7 @@ haven't yet been parsed, so that we don't yet know it will be meaningful.
intno_truth_state_returns = 0;
-wordingPhrases::TypeData::Textual::phtd_parse_return_data(ph_type_data *phtd, wordingXW) {
+wordingPhrases::TypeData::Textual::phtd_parse_return_data(ph_type_data *phtd, wordingXW) {phtd->return_kind = NULL;if (<to-return-data>(XW)) {XW = GET_RW(<to-return-data>, 1);
@@ -749,7 +749,7 @@ preamble word range backwards — it returns the current last word number.
-wordingPhrases::TypeData::Textual::phtd_parse_doodads(ph_type_data *phtd, wordingW, int *say_flag) {
+wordingPhrases::TypeData::Textual::phtd_parse_doodads(ph_type_data *phtd, wordingW, int *say_flag) {<<operation>> = -1; <<assignment>> = FALSE; <<deprecated>> = FALSE; <<run-on>> = FALSE;<phrase-preamble>(W); guaranteed to match any non-empty textif (<<r>> == SAY_ANN) W = GET_RW(<say-preamble>, 1);
@@ -979,7 +979,7 @@ form the word and token sequences:
-voidPhrases::TypeData::Textual::phtd_parse_word_sequence(ph_type_data *phtd) {
+voidPhrases::TypeData::Textual::phtd_parse_word_sequence(ph_type_data *phtd) {phtd->no_tokens = 0;phtd->no_words = 0;
@@ -1184,7 +1184,7 @@ such as "list of numbers", it returns 0.)
-intPhrases::TypeData::Textual::find_kind_variable_domains(kind *K, int *usages, kind **declarations) {
+intPhrases::TypeData::Textual::find_kind_variable_domains(kind *K, int *usages, kind **declarations) {intt = 0;if (K) {intN = Kinds::get_variable_number(K);
@@ -1236,7 +1236,7 @@ in exactly one place: for example,
To provide the names of phrases as first-class values.
-
-
§1. A few "To..." phrases have names, and can therefore be used as values in their
-own right, a functional-programming sort of device. For example:
-
-
-
-
To decide what number is double (N - a number) (this is doubling):
-
-
-
has the name "doubling". Such a name is recorded here:
-
-
-
-typedefstructconstant_phrase {
-structnoun *name;
-structphrase *phrase_meant; if known at this point
-structkind *cphr_kind; ditto
-structinter_name *cphr_iname;
-structwordingassociated_preamble_text;
-CLASS_DEFINITION
-} constant_phrase;
-
-
The structure constant_phrase is accessed in 2/rls, 2/fao, 2/act, 3/po, 4/sv, 6/cii, 6/cste and here.
-
§2. Here we create a new named phrase ("doubling", say):
-
-
-
-constant_phrase *Phrases::Constants::create(wordingNW, wordingRW) {
-constant_phrase *cphr = CREATE(constant_phrase);
-cphr->phrase_meant = NULL; we won't know until later
-cphr->cphr_kind = NULL; nor this
-cphr->associated_preamble_text = RW;
-cphr->name = Nouns::new_proper_noun(NW, NEUTER_GENDER, ADD_TO_LEXICON_NTOPT,
-PHRASE_CONSTANT_MC, Rvalues::from_constant_phrase(cphr), Task::language_of_syntax());
-cphr->cphr_iname = NULL;
-returncphr;
-}
-
§4. As often happens with Inform constants, the kind of a constant phrase can't
-be known when its name first comes up, and must be filled in later. (In
-particular, before the second traverse many kinds do not yet exist.) So
-the following takes a patch-it-later approach.
-
§6. So much for setting up constant phrases. Now we come to compilation, and
-a surprise. It might be expected that a constant phrase compiles simply to
-an I6 routine name, but no: it compiles to a small array called a "closure".
-
§7.1. The closure array consists of three words: the strong kind ID, the address
-of the routine, and the text of the name. (The latter enables us to print
-phrase values efficiently.) Note that we make a compilation request for the
-phrase in order to make sure somebody has actually compiled it: this is in
-case the phrase occurs as a constant but is never explicitly invoked.
-
-
-
Compile the closure array for this constant phrase7.1 =
-
§8. Now we come to something trickier. We want default values for kinds of phrases,
-because otherwise we can't have variables holding phrases unless they are
-always initialised explicitly, and so on. Clearly the default value for a
-phrase to nothing is one that does nothing, and for a phrase to some kind K
-is one that returns the default value of kind K. For example, the default
-value of
-
-
-
- phrase (text, time) -> number
-
-
is the function which takes any pair of a text and a time, does nothing with
-them, and always returns 0. But this means we need to actually compile such
-routines. Since there are in principle an infinite number of distinct phrase
-kinds, we will only compile them for the phrase kinds which arise during
-compilation.
-
§1. As noted in the introduction to this chapter, a phrase structure is
created for each "To..." definition and each rule in the source text. It is
@@ -111,7 +111,6 @@ code below.
structinter_schema *inter_tail_defn; inline definition translated to inter, if possibleintinter_defn_converted; has this been tried yet?intinline_mor; manner of return for inline I6 definition, or UNKNOWN_NT
-structwordingph_documentation_symbol; cross-reference with documentationstructcompilation_unit *owning_module;structpackage_request *requests_package;
@@ -132,7 +131,7 @@ code below.
CLASS_DEFINITION} phrase;
-
The structure phrase is accessed in 2/rls, 2/rb, 3/prcd, 3/ptd, 3/dptd, 3/po, 3/pav, 3/tph, 3/tp, 6/inv, 6/pi, 6/ci, 6/cii, 6/cp, 6/cste and here.
+
The structure phrase is accessed in 2/rls, 2/rb, 3/prcd, 3/ptd, 3/dptd, 3/po, 3/tph, 6/inv, 6/pi, 6/ci, 6/cii, 6/cp, 6/cste and here.
§4. "To..." phrases, though no others, are listed in logical precedence order:
§5.1.1. That just leaves two problem messages about inline definitions:
@@ -341,20 +329,30 @@ what number is...", for instance.
if (<inline-phrase-definition>(W)) { *wn = <<inlinecode>>; *mor = <<r>>; }}
-
§8. Miscellaneous. That completes the process of creation. Here's how we log them:
+
§11. Compilation. The following is called to give us an opportunity to compile a routine defining
+
§12. Compilation. The following is called to give us an opportunity to compile a routine defining
a phrase. As was mentioned in the introduction, "To..." phrases are sometimes
compiled multiple times, for different kinds of tokens, and are compiled in
response to "requests". All other phrases are compiled just once.
@@ -425,11 +423,11 @@ response to "requests". All other phrases are compiled just once.
if (ph->imported) return;if ((req) || (ph->at_least_one_compiled_form_needed)) {Routines::Compile::routine(ph, legible, req, R);
-Move along the progress bar if it's this phrase's first compilation11.1;
+Move along the progress bar if it's this phrase's first compilation12.1; }}
-
§11.1. Move along the progress bar if it's this phrase's first compilation11.1 =
+
§12.1. Move along the progress bar if it's this phrase's first compilation12.1 =
@@ -439,8 +437,8 @@ response to "requests". All other phrases are compiled just once.
ProgressBar::update(4, ((float) (*i))/((float) max_i)); }
voidPhrases::invoke_to_begin(void) {
@@ -458,7 +456,7 @@ response to "requests". All other phrases are compiled just once.
"and in Basic mode, Inform expects to see exactly one of ""these, specifying where execution should begin."); } else {
-if (Phrases::compiled_inline(ph)) {
+if (Phrases::compiled_inline(ph)) {StandardProblems::sentence_problem(Task::syntax_tree(), _p_(...),"the 'to begin' phrase seems to be defined inline","which in Basic mode is not allowed.");
@@ -485,7 +483,7 @@ response to "requests". All other phrases are compiled just once.
}
diff --git a/docs/imperative-module/3-po.html b/docs/imperative-module/3-po.html
index fa7288705..086c74368 100644
--- a/docs/imperative-module/3-po.html
+++ b/docs/imperative-module/3-po.html
@@ -108,12 +108,12 @@ valid as values, since a condition is not also a value in Inform 7.
structwordingname; text of name} phrase_option;
-
The structure phrase_option is accessed in 2/rls, 2/fao, 2/act, 3/pav, 4/sv, 6/cii, 6/cste and here.
+
The structure phrase_option is accessed in 2/rls, 2/fao, 2/act, 4/sv, 6/cii, 6/cste and here.
§3. Creation. By default, a phrase has no options.
-ph_options_dataPhrases::Options::new(wordingW) {
+ph_options_dataPhrases::Options::new(wordingW) {ph_options_dataphod;phod.no_options_permitted = 0;phod.multiple_options_permitted = FALSE;
@@ -121,7 +121,7 @@ valid as values, since a condition is not also a value in Inform 7.
returnphod;}
-intPhrases::Options::allows_options(ph_options_data *phod) {
+intPhrases::Options::allows_options(ph_options_data *phod) {if (phod->no_options_permitted > 0) returnTRUE;returnFALSE;}
@@ -169,14 +169,13 @@ these are relatively rare in Inform source text.
ph_options_data *phod_being_parsed = NULL;phrase *ph_being_parsed = NULL;
-ph_options_dataPhrases::Options::parse_declared_options(wordingW) {
-ph_options_dataphod = Phrases::Options::new(W);
+voidPhrases::Options::parse_declared_options(ph_options_data *phod, wordingW) {if (Wordings::nonempty(W)) {
-phod_being_parsed = &phod;
+phod->options_declaration = W;
+phod_being_parsed = phod;<phrase-option-declaration-list>(W);
-if (<<r>>) phod.multiple_options_permitted = TRUE;
+if (<<r>>) phod->multiple_options_permitted = TRUE; }
-returnphod;}
§7. I have to say that I regret the syntax for phrase options, which makes
@@ -242,7 +241,7 @@ For example, in:
typedefstructph_runtime_context_data {structwordingactivity_context; happens only while any activities go on?
-structparse_node *activity_where; and who says?structactivity_list *avl; #ifdefIF_MODULEstructparse_node *during_scene; ...happens only during a scene matching this?
@@ -123,7 +122,6 @@ rulebooks reach them.
intnever_test_actor; ...for instance, for a parametrised rather than action rulebookintmarked_for_anyone; any actor is allowed to perform this action #endif
-structrulebook **compile_for_rulebook; ...used for the default outcomeintpermit_all_outcomes; waive the usual restrictions on rule outcomes} ph_runtime_context_data;
@@ -185,7 +183,6 @@ the following only blanks out a PHRCD structure ready for that to happen.
ph_runtime_context_dataPhrases::Context::new(void) {ph_runtime_context_dataphrcd;phrcd.activity_context = EMPTY_WORDING;
-phrcd.activity_where = NULL;phrcd.avl = NULL; #ifdefIF_MODULEphrcd.during_scene = NULL;
@@ -195,7 +192,6 @@ the following only blanks out a PHRCD structure ready for that to happen.
phrcd.marked_for_anyone = FALSE; #endifphrcd.permit_all_outcomes = FALSE;
-phrcd.compile_for_rulebook = NULL;returnphrcd;}
voidPhrases::Context::compile_test_tail(phrase *ph, rule *R) {
-inter_name *identifier = Phrases::iname(ph);
+inter_name *identifier = Phrases::iname(ph);ph_runtime_context_data *phrcd = &(ph->runtime_context_data);
-
-if (phrcd->compile_for_rulebook) {
-rulebook *rb = *(phrcd->compile_for_rulebook);
-if (rb) RTRules::compile_default_outcome(Rulebooks::get_outcomes(rb));
- }
-
-if (Wordings::nonempty(phrcd->activity_context)) Compile an activity or explicit condition test tail9.1.1;
+rulebook *rb = RuleFamily::get_rulebook(ph->from);
+if (rb) RTRules::compile_default_outcome(Rulebooks::get_outcomes(rb));
+if (Wordings::nonempty(phrcd->activity_context))
+Compile an activity or explicit condition test tail9.1.1;if (PluginCalls::compile_test_tail(ph, R) == FALSE) {if (phrcd->ap) Compile an action test tail9.6; }
@@ -735,7 +728,7 @@ with the default outcome return (see above).
returnn;}
-
The structure activity_list is accessed in 2/rlb, 2/act, 3/phr, 3/tph, 3/tp, 4/lv, 4/sv, 4/sf, 5/dtd, 5/cdp, 6/inv, 6/pi, 6/cii, 6/cp, 6/cste and here.
+
The structure activity_list is accessed in 2/rlb, 2/act, 3/phr, 3/tph, 4/lv, 4/sv, 4/sf, 5/dtd, 5/cdp, 6/inv, 6/pi, 6/cii, 6/cp, 6/cste and here.
§11. Run-time contexts are seen in the "while" clauses at the end of rules.
For example:
@@ -902,7 +895,7 @@ values, of the kind to which the activity applies.
}
diff --git a/docs/imperative-module/3-ptd.html b/docs/imperative-module/3-ptd.html
index 2a046a9ef..3399fc0fb 100644
--- a/docs/imperative-module/3-ptd.html
+++ b/docs/imperative-module/3-ptd.html
@@ -296,7 +296,7 @@ whistles and doodads which regular phrases don't.
§9. Creation.
-ph_type_dataPhrases::TypeData::new(void) {
+ph_type_dataPhrases::TypeData::new(void) {ph_type_dataphtd;phtd.registration_text = EMPTY_WORDING;
@@ -403,7 +403,7 @@ logic, since one argument is in effect a kind rather than a value.)
-kind *Phrases::TypeData::kind(ph_type_data *phtd) {
+kind *Phrases::TypeData::kind(ph_type_data *phtd) {kind *argument_kinds[MAX_TOKENS_PER_PHRASE];inti, j = 0;for (i=0; i<phtd->no_tokens; i++)
@@ -528,7 +528,7 @@ variables "new entry" and "L" with those kinds.
-voidPhrases::TypeData::into_stack_frame(ph_stack_frame *phsf,
+voidPhrases::TypeData::into_stack_frame(ph_stack_frame *phsf,ph_type_data *phtd, kind *kind_in_this_compilation, intfirst) {if (Kinds::get_construct(kind_in_this_compilation) != CON_phrase)internal_error("no function kind");
@@ -914,7 +914,7 @@ by than name.
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. 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:
-
-
-
defineNOT_A_TIMED_EVENT -1 as for the vast majority of phrases
-defineNO_FIXED_TIME -2 for phrases like "When the clock strikes: ..."
-defineNOT_AN_EVENT -3 not even syntactically
-
-
§2. And here we record where events are used:
-
-
-
-typedefstructuse_as_event {
-structparse_node *where_triggered; sentence which specifies when this occurs
-structuse_as_event *next;
-CLASS_DEFINITION
-} use_as_event;
-
-
The structure use_as_event is accessed in 2/rlb, 2/act, 3/phr, 3/prcd, 3/tph, 4/lv, 4/sv, 4/sf, 5/dtd, 5/cdp, 6/inv, 6/pi, 6/cii, 6/cp, 6/cste and here.
-
§3. Timed events are stored in two simple arrays, processed by run-time code.
-
§5. An interesting case where the Problem is arguably only a warning and
-arguably shouldn't block compilation. Then again...
-
-
-
-voidPhrases::Timed::check_for_unused(void) {
-phrase *ph;
-LOOP_OVER(ph, phrase)
-if (RuleFamily::get_timing_of_event(ph->from) == NO_FIXED_TIME) {
-linked_list *L = RuleFamily::get_uses_as_event(ph->from);
-if (LinkedLists::len(L) == 0) {
-current_sentence = ph->from->at;
-StandardProblems::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.)");
- }
- }
-}
-
-
-
-
-
-
-
diff --git a/docs/imperative-module/3-tph.html b/docs/imperative-module/3-tph.html
index 9c191a831..4371e1a2e 100644
--- a/docs/imperative-module/3-tph.html
+++ b/docs/imperative-module/3-tph.html
@@ -124,7 +124,7 @@ variety of values:
if ((Log::aspect_switched_on(PHRASE_COMPARISONS_DA)) || (r == CONFLICTED_PH)) {LOG("Phrase comparison (");
-Phrases::write_HTML_representation(DL, ph1, PASTE_PHRASE_FORMAT);
+Phrases::write_HTML_representation(DL, ph1, PASTE_PHRASE_FORMAT);LOG(") ");switch(r) {caseINCOMPARABLE_PH:LOG("~~"); break;
@@ -136,13 +136,13 @@ variety of values:
caseCONFLICTED_PH:LOG("!!"); break; }LOG(" (");
-Phrases::write_HTML_representation(DL, ph2, PASTE_PHRASE_FORMAT);
+Phrases::write_HTML_representation(DL, ph2, PASTE_PHRASE_FORMAT);LOG(")\n"); }if (r == CONFLICTED_PH) {
-Problems::quote_source(1, Phrases::declaration_node(ph1));
-Problems::quote_source(2, Phrases::declaration_node(ph2));
+Problems::quote_source(1, Phrases::declaration_node(ph1));
+Problems::quote_source(2, Phrases::declaration_node(ph2));StandardProblems::handmade_problem(Task::syntax_tree(), _p_(PM_ConflictedReturnKinds));Problems::issue_problem_segment("The two phrase definitions %1 and %2 make the same wording "
@@ -202,7 +202,7 @@ reasons, that is, to make the compiled code more legible.
intRoutines::ToPhrases::sequence_count(phrase *ph) {if (ph == NULL) return0;if (ph->sequence_count == -1) {
-Phrases::log(ph);
+Phrases::log(ph);internal_error("Sequence count not ready"); }returnph->sequence_count;
@@ -234,7 +234,7 @@ values in force, so that there is no possible ambiguity in how we read K.
-to_phrase_request *Routines::ToPhrases::make_request(phrase *ph, kind *K,
+to_phrase_request *Routines::ToPhrases::make_request(phrase *ph, kind *K,kind_variable_declaration *kvd, wordingW) {if ((ph == NULL) || (K == NULL)) internal_error("bad request");
@@ -274,7 +274,7 @@ list is a list of. The result would be:
-inter_name *Routines::ToPhrases::make_iname(phrase *ph, kind *req_kind) {
+inter_name *Routines::ToPhrases::make_iname(phrase *ph, kind *req_kind) {if (Phrases::TypeData::invoked_inline(ph)) {TEMPORARY_TEXT(identifier)
-wchar_t *p = Phrases::get_inline_definition(ph);
+wchar_t *p = Phrases::get_inline_definition(ph);intfound = FALSE;for (inti=0; p[i]; i++)if (Characters::isalpha(p[i])) {
@@ -310,7 +310,7 @@ I6 routine.
break; }if (found == FALSE) {
-current_sentence = Phrases::declaration_node(ph);
+current_sentence = Phrases::declaration_node(ph);Problems::quote_source(1, current_sentence);Problems::quote_phrase(2, ph);StandardProblems::handmade_problem(Task::syntax_tree(), _p_(PM_PhraseNamedI6Failed));
@@ -347,7 +347,7 @@ since the last time it was called.
if (req == NULL) break;latest_request_granted = req;
-Phrases::compile(latest_request_granted->requested_phrase,
+Phrases::compile(latest_request_granted->requested_phrase,i, max_i, NULL, latest_request_granted, NULL);N++; }
@@ -403,7 +403,7 @@ is confined to the current Chapter.
}
diff --git a/docs/imperative-module/4-lv.html b/docs/imperative-module/4-lv.html
index cef35a093..04bb49426 100644
--- a/docs/imperative-module/4-lv.html
+++ b/docs/imperative-module/4-lv.html
@@ -148,7 +148,7 @@ marks it as deallocated.
CLASS_DEFINITION} local_variable;
-
The structure local_variable is accessed in 2/rlb, 2/act, 3/phr, 3/prcd, 3/tph, 3/tp, 4/sv, 4/sf, 5/dtd, 5/cdp, 6/inv, 6/pi, 6/cii, 6/cp, 6/cste and here.
+
The structure local_variable is accessed in 2/rlb, 2/act, 3/phr, 3/prcd, 3/tph, 4/sv, 4/sf, 5/dtd, 5/cdp, 6/inv, 6/pi, 6/cii, 6/cp, 6/cste and here.
§3. A local variable needs to be stored somewhere at run-time. The obvious
correspondence is to put these into I6 local variables, which are, in effect,
CPU registers. We won't need to do much in the way of register-allocation,
@@ -389,7 +389,7 @@ scratch work-space which can be used in the compiled code.
returnLocalVariables::declare_this(v, FALSE, 8);}
-local_variable *LocalVariables::add_named_call(text_stream *name) {
+local_variable *LocalVariables::add_named_call(text_stream *name) {ph_stack_frame *phsf = Frames::current_stack_frame();if (phsf)returnLocalVariables::add_internal(&(phsf->local_value_variables), name,
@@ -456,7 +456,7 @@ passed to its I6 routine, and this occupies a pseudo-call-parameter:
-voidLocalVariables::options_parameter_is_needed(ph_stack_frame *phsf) {
+voidLocalVariables::options_parameter_is_needed(ph_stack_frame *phsf) {LocalVariables::add_internal(&(phsf->local_value_variables),I"phrase_options", OTHER_CALL_PARAMETER_LV);}
@@ -1368,7 +1368,7 @@ need in the compilation of any given routine:
}
The structure stacked_variable is accessed in 2/rls, 2/fao, 2/act, 3/po, 3/pav, 6/cii, 6/cste and here.
The structure stacked_variable_list is accessed in 2/rlb, 2/act, 3/phr, 3/prcd, 3/tph, 3/tp, 4/lv, 4/sf, 5/dtd, 5/cdp, 6/inv, 6/pi, 6/cii, 6/cp, 6/cste and here.
The structure stacked_variable_owner is private to this section.
The structure stacked_variable_owner_list is accessed in 2/rlb, 2/act, 3/phr, 3/prcd, 3/tph, 3/tp, 4/lv, 4/sf, 5/dtd, 5/cdp, 6/inv, 6/pi, 6/cii, 6/cp, 6/cste and here.
+
The structure stacked_variable is accessed in 2/rls, 2/fao, 2/act, 3/po, 6/cii, 6/cste and here.
The structure stacked_variable_list is accessed in 2/rlb, 2/act, 3/phr, 3/prcd, 3/tph, 4/lv, 4/sf, 5/dtd, 5/cdp, 6/inv, 6/pi, 6/cii, 6/cp, 6/cste and here.
The structure stacked_variable_owner is private to this section.
The structure stacked_variable_owner_list is accessed in 2/rlb, 2/act, 3/phr, 3/prcd, 3/tph, 4/lv, 4/sf, 5/dtd, 5/cdp, 6/inv, 6/pi, 6/cii, 6/cp, 6/cste and here.
§2.
diff --git a/docs/imperative-module/6-cii.html b/docs/imperative-module/6-cii.html
index 7ace2e271..cd031be28 100644
--- a/docs/imperative-module/6-cii.html
+++ b/docs/imperative-module/6-cii.html
@@ -210,8 +210,8 @@ head goes to OUT
§1.4. Suppose there's a phrase with both head and tail. Then the tail won't appear
@@ -1220,43 +1220,14 @@ token, because that would be "property name". Instead:
return;
The annotation makes no difference to how R is compiled, except that it
-sneaks in a sanity check (R must be explicitly named and must be an event
-rule), and also makes a note for indexing purposes.
+
-if (Rvalues::is_CONSTANT_construction(supplied, CON_rule)) {
-rule *R = Rvalues::to_rule(supplied);
-imperative_defn *id = Rules::get_imperative_definition(R);
-if (id) Phrases::Timed::note_usage(id->body_of_defn, current_sentence);
- } else {
-Problems::quote_source(1, current_sentence);
-Problems::quote_wording(2, Node::get_text(supplied));
-StandardProblems::handmade_problem(Task::syntax_tree(), _p_(PM_NonconstantEvent));
-Problems::issue_problem_segment(
-"You wrote %1, but '%2' isn't the name of any timed event that "
-"I know of. (These need to be set up in a special way, like so - "
-"'At the time when stuff happens: ...' creates a timed event "
-"called 'stuff happens'.)");
-Problems::issue_problem_end();
- }
+PluginCalls::nonstandard_inline_annotation(sche->inline_command, supplied);valid_annotation = TRUE;
diff --git a/docs/imperative-module/6-cp.html b/docs/imperative-module/6-cp.html
index da7c1cc35..f500f1398 100644
--- a/docs/imperative-module/6-cp.html
+++ b/docs/imperative-module/6-cp.html
@@ -99,7 +99,7 @@ should always be supplied for "To..." phrases, but left null for rules.
-voidRoutines::Compile::routine(phrase *ph,
+voidRoutines::Compile::routine(phrase *ph,stacked_variable_owner_list *legible, to_phrase_request *req,rule *R) {parse_node *code_at = ph->from->at;
@@ -205,9 +205,9 @@ phrase to be different from the number version, and so on.
diff --git a/docs/imperative-module/6-inv.html b/docs/imperative-module/6-inv.html
index 66437ae82..2ec8337cb 100644
--- a/docs/imperative-module/6-inv.html
+++ b/docs/imperative-module/6-inv.html
@@ -268,7 +268,7 @@ for different invocations of, say, "+".
} elseif (Node::get_say_adjective(inv)) {LOG("adj:%d", Node::get_say_adjective(inv)->allocation_id); } else {
-Phrases::log_briefly(Node::get_phrase_invoked(inv));
+Phrases::log_briefly(Node::get_phrase_invoked(inv));for (i=0; i<Invocations::get_no_tokens(inv); i++) {LOG(" ($P", Invocations::get_token_as_parsed(inv, i));if (Invocations::get_token_check_to_do(inv, i))
diff --git a/docs/imperative-module/index.html b/docs/imperative-module/index.html
index 42e9e2117..1334ccbb9 100644
--- a/docs/imperative-module/index.html
+++ b/docs/imperative-module/index.html
@@ -156,21 +156,11 @@
Phrase Options -
To create and subsequently parse against the list of phrase options with which the user can choose to invoke a To phrase.
To Phrases -
To manage the sorting of To... phrases in logical precedence order, and keep track of which kinds they are being applied to.
-
-
- Timed Phrases -
- 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.
-
diff --git a/docs/index-module/2-ifs.html b/docs/index-module/2-ifs.html
index e863cea86..623b618b0 100644
--- a/docs/index-module/2-ifs.html
+++ b/docs/index-module/2-ifs.html
@@ -818,7 +818,7 @@ to show, hide and colour things:
return; }if (Str::eq_wide_string(elt, L"Ev")) {
-Phrases::Timed::index(OUT); rules which happen at set times of day
+IXRules::index_timed_rules(OUT); rules which happen at set times of dayreturn; }if (Str::eq_wide_string(elt, L"RS")) {
@@ -941,7 +941,7 @@ the source text in the application.
-voidIndex::link(OUTPUT_STREAM, intwn) {
+voidIndex::link(OUTPUT_STREAM, intwn) {Index::link_to_location(OUT, Lexer::word_location(wn), TRUE);}
diff --git a/docs/index-module/2-pi.html b/docs/index-module/2-pi.html
index a4338b57e..293972ba0 100644
--- a/docs/index-module/2-pi.html
+++ b/docs/index-module/2-pi.html
@@ -309,10 +309,10 @@ a single shared reveal-box:
diff --git a/docs/runtime-module/2-emt.html b/docs/runtime-module/2-emt.html
index f0509c5c6..9884f1588 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;}
@@ -399,7 +399,7 @@ insert them into the Inter stream close to the top.
returnsave;}
-packaging_stateEmit::named_table_array_begin(inter_name *name, kind *K) {
+packaging_stateEmit::named_table_array_begin(inter_name *name, kind *K) {packaging_statesave = Emit::named_array_begin(name, K);Produce::annotate_iname_i(name, TABLEARRAY_IANN, 1);returnsave;
@@ -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();
@@ -512,7 +512,7 @@ insert them into the Inter stream close to the top.
returnsave;}
-voidEmit::array_iname_entry(inter_name *iname) {
+voidEmit::array_iname_entry(inter_name *iname) {if (current_A == NULL) internal_error("entry outside of inter array");inter_symbol *alias;if (iname == NULL) alias = Site::veneer_symbol(Emit::tree(), NOTHING_VSYMB);
@@ -547,7 +547,7 @@ insert them into the Inter stream close to the top.
}#endif
-voidEmit::array_text_entry(text_stream *content) {
+voidEmit::array_text_entry(text_stream *content) {if (current_A == NULL) internal_error("entry outside of inter array");inter_tiv1 = 0, v2 = 0;Produce::text_value(Emit::tree(), &v1, &v2, content);
@@ -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());
diff --git a/docs/runtime-module/2-hrr.html b/docs/runtime-module/2-hrr.html
index 1a412a33a..7b7ba235e 100644
--- a/docs/runtime-module/2-hrr.html
+++ b/docs/runtime-module/2-hrr.html
@@ -1723,11 +1723,11 @@ function togglePopup(material_id) {
To provide the names of phrases as first-class values.
+
+
§1. So much for setting up constant phrases. Now we come to compilation, and
+a surprise. It might be expected that a constant phrase compiles simply to
+an I6 routine name, but no: it compiles to a small array called a "closure".
+
+voidPhrases::Constants::compile_closures(void) {
+constant_phrase *cphr;
+LOOP_OVER(cphr, constant_phrase) {
+phrase *ph = ToPhraseFamily::body_of_constant(cphr);
+if (ph == NULL) internal_error("cannot reconstruct phrase from cphr");
+ToPhraseFamily::kind(cphr);
+Compile the closure array for this constant phrase2.1;
+ }
+}
+
+
§2.1. The closure array consists of three words: the strong kind ID, the address
+of the routine, and the text of the name. (The latter enables us to print
+phrase values efficiently.) Note that we make a compilation request for the
+phrase in order to make sure somebody has actually compiled it: this is in
+case the phrase occurs as a constant but is never explicitly invoked.
+
+
+
Compile the closure array for this constant phrase2.1 =
+
§3. Now we come to something trickier. We want default values for kinds of phrases,
+because otherwise we can't have variables holding phrases unless they are
+always initialised explicitly, and so on. Clearly the default value for a
+phrase to nothing is one that does nothing, and for a phrase to some kind K
+is one that returns the default value of kind K. For example, the default
+value of
+
+
+
+ phrase (text, time) -> number
+
+
is the function which takes any pair of a text and a time, does nothing with
+them, and always returns 0. But this means we need to actually compile such
+routines. Since there are in principle an infinite number of distinct phrase
+kinds, we will only compile them for the phrase kinds which arise during
+compilation.
+
+
+
+
+
+
+
diff --git a/docs/runtime-module/4-ct.html b/docs/runtime-module/4-ct.html
index 4b473e4dd..5984fafb7 100644
--- a/docs/runtime-module/4-ct.html
+++ b/docs/runtime-module/4-ct.html
@@ -470,7 +470,7 @@ exceptional case.
}
diff --git a/docs/runtime-module/4-efart.html b/docs/runtime-module/4-efart.html
index f8effb87c..66c3c468d 100644
--- a/docs/runtime-module/4-efart.html
+++ b/docs/runtime-module/4-efart.html
@@ -178,7 +178,7 @@ and author.
}
diff --git a/docs/runtime-module/4-epv.html b/docs/runtime-module/4-epv.html
index c2587800c..bb581ba69 100644
--- a/docs/runtime-module/4-epv.html
+++ b/docs/runtime-module/4-epv.html
@@ -387,7 +387,7 @@ the property-permission symbol accordingly:
}
diff --git a/docs/runtime-module/4-es.html b/docs/runtime-module/4-es.html
index fa447cf87..b9acf1c39 100644
--- a/docs/runtime-module/4-es.html
+++ b/docs/runtime-module/4-es.html
@@ -89,7 +89,7 @@ they provide values different from each other and from all other functions.
}
diff --git a/docs/runtime-module/4-fc.html b/docs/runtime-module/4-fc.html
index 5c39aa3d8..20b26e0a7 100644
--- a/docs/runtime-module/4-fc.html
+++ b/docs/runtime-module/4-fc.html
@@ -216,7 +216,7 @@ Inform's own version number), but it belongs nowhere else either, so:
}
diff --git a/docs/runtime-module/4-i6i.html b/docs/runtime-module/4-i6i.html
index bf1d43b33..2ea881afc 100644
--- a/docs/runtime-module/4-i6i.html
+++ b/docs/runtime-module/4-i6i.html
@@ -315,7 +315,7 @@ requests, which, again, we do by instructing the Template code.
}
diff --git a/docs/runtime-module/4-ic.html b/docs/runtime-module/4-ic.html
index 4967799b4..d3bbebbed 100644
--- a/docs/runtime-module/4-ic.html
+++ b/docs/runtime-module/4-ic.html
@@ -502,7 +502,7 @@ constants, and use the Link constants to progress; we stop at }
diff --git a/docs/runtime-module/4-ins.html b/docs/runtime-module/4-ins.html
index bd989bf28..8295b4b44 100644
--- a/docs/runtime-module/4-ins.html
+++ b/docs/runtime-module/4-ins.html
@@ -158,7 +158,7 @@ declarations) and finally return }
diff --git a/docs/runtime-module/4-itc.html b/docs/runtime-module/4-itc.html
index c1dfa13df..dbaa3701c 100644
--- a/docs/runtime-module/4-itc.html
+++ b/docs/runtime-module/4-itc.html
@@ -648,7 +648,7 @@ only and may change at any time without notice.
The structure measurement_compilation_data is private to this section.
diff --git a/docs/runtime-module/4-ni.html b/docs/runtime-module/4-ni.html
index 6bc97386e..1e8e2bb1f 100644
--- a/docs/runtime-module/4-ni.html
+++ b/docs/runtime-module/4-ni.html
@@ -159,7 +159,7 @@ instance, the Standard Rules want the player-character object to be called
}
diff --git a/docs/runtime-module/4-prp.html b/docs/runtime-module/4-prp.html
index a1ad74d2c..e5e3b6811 100644
--- a/docs/runtime-module/4-prp.html
+++ b/docs/runtime-module/4-prp.html
@@ -597,7 +597,7 @@ answer now.
}
diff --git a/docs/runtime-module/4-rart.html b/docs/runtime-module/4-rart.html
index 66141727f..534990ac6 100644
--- a/docs/runtime-module/4-rart.html
+++ b/docs/runtime-module/4-rart.html
@@ -2174,7 +2174,7 @@ matches the specific necessary kind of object if there is one.
}
diff --git a/docs/runtime-module/4-rls.html b/docs/runtime-module/4-rls.html
index a202b927d..611af4a47 100644
--- a/docs/runtime-module/4-rls.html
+++ b/docs/runtime-module/4-rls.html
@@ -113,6 +113,14 @@ function togglePopup(material_id) {
return &(R->defn_as_I7_source->body_of_defn->stack_frame);}
+voidRTRules::prepare_rule(imperative_defn *id, rule *R) {
+rule_family_data *rfd = RETRIEVE_POINTER_rule_family_data(id->family_specific_data);
+package_request *P = RTRules::package(R);
+if (Wordings::empty(rfd->constant_name))
+Hierarchy::markup_wording(P, RULE_NAME_HMD, Node::get_text(id->at));
+id->body_of_defn->ph_iname = Hierarchy::make_localised_iname_in(RULE_FN_HL, P, id->body_of_defn->owning_module);
+}
+
package_request *RTRules::package(rule *R) {returnR->compilation_data.rule_package;}
@@ -1093,7 +1101,7 @@ code are the real outcome of the code in this section.
}
diff --git a/docs/runtime-module/4-rsfk.html b/docs/runtime-module/4-rsfk.html
index a8761e11a..ff86744b9 100644
--- a/docs/runtime-module/4-rsfk.html
+++ b/docs/runtime-module/4-rsfk.html
@@ -174,7 +174,7 @@ chosen), but no problem message has been issued about this, or
Emit::array_generic_entry(v1, v2);returnrv;}
-intRTKinds::emit_default_value_as_val(kind *K, wordingW, char *storage_name) {
+intRTKinds::emit_default_value_as_val(kind *K, wordingW, char *storage_name) {value_holsterVH = Holsters::new(INTER_DATA_VHMODE);intrv = RTKinds::compile_default_value_vh(&VH, K, W, storage_name);Holsters::to_val_mode(Emit::tree(), &VH);
@@ -677,7 +677,7 @@ turns up. This means remembering everything we've seen, using a new structure:
-voidRTKinds::emit_strong_id(kind *K) {
+voidRTKinds::emit_strong_id(kind *K) {runtime_kind_structure *rks = RTKinds::get_rks(K);if (rks) {Emit::array_iname_entry(rks->rks_iname);
@@ -686,7 +686,7 @@ turns up. This means remembering everything we've seen, using a new structure:
}}
-voidRTKinds::emit_strong_id_as_val(kind *K) {
+voidRTKinds::emit_strong_id_as_val(kind *K) {runtime_kind_structure *rks = RTKinds::get_rks(K);if (rks) {Produce::val_iname(Emit::tree(), K_value, rks->rks_iname);
@@ -920,7 +920,7 @@ recursively scanned through for us, so that if we have seen a construction
inter_name *identifier = rks->rks_dv_iname;current_sentence = rks->default_requested_here;if (Kinds::get_construct(K) == CON_phrase) {
-Phrases::Constants::compile_default_closure(identifier, K);
+Phrases::Constants::compile_default_closure(identifier, K); } elseif (Kinds::get_construct(K) == CON_relation) {RTRelations::compile_default_relation(identifier, K); } elseif (Kinds::get_construct(K) == CON_list_of) {
@@ -2285,7 +2285,7 @@ and it seems best to reject the extra complexity needed.
-voidRoutines::end(packaging_statesave) {
+voidRoutines::end(packaging_statesave) {kind *R_kind = LocalVariables::deduced_function_kind(currently_compiling_in_frame);inter_name *kernel_name = NULL, *public_name = currently_compiling_iname;
@@ -307,7 +307,7 @@ after the call parameters, and is used only as a scratch variable.
diff --git a/docs/runtime-module/4-tl.html b/docs/runtime-module/4-tl.html
index 6e269abe5..47d38357d 100644
--- a/docs/runtime-module/4-tl.html
+++ b/docs/runtime-module/4-tl.html
@@ -445,7 +445,7 @@ number -1).
}
diff --git a/docs/runtime-module/4-ts.html b/docs/runtime-module/4-ts.html
index f3ff18c42..f71e73b56 100644
--- a/docs/runtime-module/4-ts.html
+++ b/docs/runtime-module/4-ts.html
@@ -460,7 +460,7 @@ we aren't doing very much; most TSs will be passed quickly over.
}
diff --git a/docs/runtime-module/4-ts2.html b/docs/runtime-module/4-ts2.html
index 463041c1c..29d0a8a90 100644
--- a/docs/runtime-module/4-ts2.html
+++ b/docs/runtime-module/4-ts2.html
@@ -92,7 +92,7 @@ stipulations on place and possessions attached.
CLASS_DEFINITION} test_scenario;
-
The structure test_scenario is accessed in 4/rsp, 4/rls, 4/act, 4/uoart, 4/vrb, 4/prp, 5/sc, 5/gpr and here.
+
The structure test_scenario is accessed in 4/rsp, 4/rls, 4/act, 4/uoart, 4/vrb, 4/prp, 4/cls, 5/sc, 5/gpr and here.
§2.
@@ -297,7 +297,7 @@ stipulations on place and possessions attached.
}
diff --git a/docs/runtime-module/4-tv.html b/docs/runtime-module/4-tv.html
index 40e85c375..da59475a9 100644
--- a/docs/runtime-module/4-tv.html
+++ b/docs/runtime-module/4-tv.html
@@ -169,7 +169,7 @@ hacky constructs which only the SR should ever refer to.
}
diff --git a/docs/runtime-module/4-uoart.html b/docs/runtime-module/4-uoart.html
index 7a20edd75..43f2b8866 100644
--- a/docs/runtime-module/4-uoart.html
+++ b/docs/runtime-module/4-uoart.html
@@ -205,7 +205,7 @@ source code: see the DM4 for details.
}
diff --git a/docs/runtime-module/4-vart.html b/docs/runtime-module/4-vart.html
index a41d65693..122e5a3c1 100644
--- a/docs/runtime-module/4-vart.html
+++ b/docs/runtime-module/4-vart.html
@@ -649,7 +649,7 @@ usages to the debugging log.
}
diff --git a/docs/runtime-module/4-vrb.html b/docs/runtime-module/4-vrb.html
index d79f87e71..47adeba50 100644
--- a/docs/runtime-module/4-vrb.html
+++ b/docs/runtime-module/4-vrb.html
@@ -476,7 +476,7 @@ which makes its kind safe. Hence the error messages.
diff --git a/docs/runtime-module/5-act.html b/docs/runtime-module/5-act.html
index af838eb37..318a5ac17 100644
--- a/docs/runtime-module/5-act.html
+++ b/docs/runtime-module/5-act.html
@@ -502,7 +502,7 @@ infrastructure, and we access it with a single call.
}
diff --git a/docs/runtime-module/5-ap.html b/docs/runtime-module/5-ap.html
index 8b6521198..39dff3b30 100644
--- a/docs/runtime-module/5-ap.html
+++ b/docs/runtime-module/5-ap.html
@@ -911,7 +911,7 @@ and in this case we therefore ignore