diff --git a/README.md b/README.md index a07c9433d..aeeac5e26 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,6 @@ # Inform 7 -v10.1.0-alpha.1+6R29 'Krypton' (19 February 2021) +v10.1.0-alpha.1+6R30 'Krypton' (20 February 2021) ## About Inform 7 diff --git a/build.txt b/build.txt index a66385499..3639626fb 100644 --- a/build.txt +++ b/build.txt @@ -1,3 +1,3 @@ Prerelease: alpha.1 -Build Date: 19 February 2021 -Build Number: 6R29 +Build Date: 20 February 2021 +Build Number: 6R30 diff --git a/docs/BasicInformKit/S-fl.html b/docs/BasicInformKit/S-fl.html index fb5acfaf4..f2167b109 100644 --- a/docs/BasicInformKit/S-fl.html +++ b/docs/BasicInformKit/S-fl.html @@ -453,9 +453,9 @@ run-time problem when there is no alternative.

§17. Back To Core.

-#IFNOT; FILES_PCALL
+#IFNOT; FILES_PLUGIN
 [ FileIO_GetC extf; return -1; ];
-#ENDIF; FILES_PCALL
+#ENDIF; FILES_PLUGIN
 
- + -

Plugins are optional extras for the Inform compiler: additions which can be active or inactive on any given compilation run.

+ +

Creating, activating or deactivating plugins.

-

§1. Except for one not-really-a-plugin called "core", each plugin is a piece of +


+ +

§1. Plugins are optional extras for the Inform compiler: additions which can be +active or inactive on any given compilation run. +

+ +

Except for one not-really-a-plugin called "core", each plugin is a piece of functionality that can be "activated" or "deactivated". Plugins have an ability to tweak or extend what the compiler does, giving it, for example, an ability to reason about spatial relationships when the compiler is being used for interactive fiction; or not, when it isn't.

-
-void PluginManager::start(void) {
-    PluginCalls::initialise_calls();
-}
-
-

§2.

+

There is no harm in this hard-wired maximum, since plugins are not things an +author can create in source text; we know exactly how many there are. +

define MAX_PLUGINS 32
 
@@ -94,7 +97,7 @@ used for interactive fiction; or not, when it isn't. struct text_stream *textual_name; struct wording wording_name; struct plugin *parent_plugin; - void (*starter_routine)(void); + void (*activation_function)(void); int active; CLASS_DEFINITION } plugin; @@ -103,7 +106,7 @@ used for interactive fiction; or not, when it isn't. plugin *P = CREATE(plugin); P->textual_name = Str::duplicate(tname); P->wording_name = Feeds::feed_text(tname); - P->starter_routine = starter; + P->activation_function = starter; P->active = FALSE; P->parent_plugin = set; if (P->allocation_id >= MAX_PLUGINS) internal_error("Too many plugins"); @@ -111,7 +114,7 @@ used for interactive fiction; or not, when it isn't. } -

§3. An inactive plugin does nothing; it's as if that section of code were not in +

§2. An inactive plugin does nothing; it's as if that section of code were not in the compiler at all.

@@ -133,7 +136,7 @@ the compiler at all. WRITE(".\n"); } -

§4. In the code above, plugins are set up as inactive by default — even "core", +

§3. In the code above, plugins are set up as inactive by default — even "core", which the compiler absolutely cannot live without. See Project Services (in supervisor) for how the set of active plugins for a compilation is determined in practice; note, in particularly, that it wisely chooses to activate the core. @@ -163,13 +166,13 @@ or deactivates its children. LOOP_OVER(Q, plugin) if (Q->parent_plugin == P) { if (Q == core_plugin) - Issue problem for trying to remove the core4.1 + Issue problem for trying to remove the core3.1 else Q->active = FALSE; } } } -

§4.1. Issue problem for trying to remove the core4.1 = +

§3.1. Issue problem for trying to remove the core3.1 =

@@ -178,8 +181,8 @@ or deactivates its children.
         "because then what should we do? What should we ever do?");
     return;
 
- -

§5. Every active plugin gets to run its start function, if it provides one. +

+

§4. Every active plugin gets to run its start function, if it provides one.

It's kind of incredible that C's grammar for round brackets is unambiguous. @@ -190,12 +193,12 @@ or deactivates its children. plugin *P; LOOP_OVER(P, plugin) if (P->active) { - void (*start)() = (void (*)()) P->starter_routine; + void (*start)() = (void (*)()) P->activation_function; if (start) (*start)(); } } -

§6. The names of the great plugins are hard-wired into the compiler rather +

§5. The names of the great plugins are hard-wired into the compiler rather than being stored in Preform grammar, and they therefore cannot be translated out of English. But this is intentional, for now at least. Authors are not intended to be aware of plugins; it is really kits of Inter code which choose @@ -223,7 +226,7 @@ Preform nonterminal to parse them, and here it is. }

-

§7. It's convenient also to provide: +

§6. It's convenient also to provide:

@@ -235,8 +238,66 @@ Preform nonterminal to parse them, and here it is.
     return NULL;
 }
 
+

§7. Plugs. Plugins affect the running of the compiler by inserting functions called plugs +into the following "plugin rulebooks" — there's a mixed metaphor here, but +the idea is that they behave like Inform rulebooks. When a rulebook is called, +the compiler works through each plug until one of them returns something other +than FALSE. +

+ +

Plugins should add plugs in their activation functions, by calling +PluginManager::plug, which has an interestingly vague type. The next +screenful of code looks like something of a workout for the C typechecker, but +it compiles under clang without even the -Wpedantic warning, and honestly +you're barely living as a C programmer if you never generate that one. +

+ +
+linked_list *plugin_rulebooks[NO_DEFINED_PLUG_VALUES+1];  of void, reprehensibly
+
+void PluginManager::start(void) {
+    for (int i=0; i<=NO_DEFINED_PLUG_VALUES; i++)
+        plugin_rulebooks[i] = NEW_LINKED_LIST(void);
+}
+
+void PluginManager::plug(int code, int (*R)()) {
+    if (code > NO_DEFINED_PLUG_VALUES) internal_error("not a plugin call");
+    void *vR = (void *) R;
+    ADD_TO_LINKED_LIST(vR, void, plugin_rulebooks[code]);
+}
+
+

§8. The functions in Plugin Calls then make use of these macros, which are +the easiest way to persuade the C typechecker to allow variable arguments to +be passed in a portable way. Similarly, there are two macros not one because +C does not allow a void variable argument list. +

+ +

We must take care that the variables introduced in the macro body do not mask +existing variables used in the arguments; the only way to do this is to give +them implausible names. +

+ +
define PLUGINS_CALL(code, args...) {
+    void *R_plugin_pointer_XYZZY;  no argument can have this name
+    LOOP_OVER_LINKED_LIST(R_plugin_pointer_XYZZY, void, plugin_rulebooks[code]) {
+        int (*R_plugin_rule_ZOOGE)() = (int (*)()) R_plugin_pointer_XYZZY;  or this one
+        int Q_plugin_return_PLUGH = (*R_plugin_rule_ZOOGE)(args);  or this
+        if (Q_plugin_return_PLUGH) return Q_plugin_return_PLUGH;
+    }
+    return FALSE;
+}
+define PLUGINS_CALLV(code) {
+    void *R_plugin_pointer_XYZZY;
+    LOOP_OVER_LINKED_LIST(R_plugin_pointer_XYZZY, void, plugin_rulebooks[code]) {
+        int (*R_plugin_rule_ZOOGE)() = (int (*)()) R_plugin_pointer_XYZZY;
+        int Q_plugin_return_PLUGH = (*R_plugin_rule_ZOOGE)();
+        if (Q_plugin_return_PLUGH) return Q_plugin_return_PLUGH;
+    }
+    return FALSE;
+}
+
diff --git a/docs/core-module/P-wtmd.html b/docs/core-module/P-wtmd.html index d97812a51..23e4095ab 100644 --- a/docs/core-module/P-wtmd.html +++ b/docs/core-module/P-wtmd.html @@ -115,7 +115,7 @@ and for sound and images respectively.

diff --git a/docs/core-module/index.html b/docs/core-module/index.html index ae1a4dfa9..d1fd74975 100644 --- a/docs/core-module/index.html +++ b/docs/core-module/index.html @@ -118,16 +118,6 @@ Inform-Only Nodes and Annotations - How Inform extends and annotates the syntax tree.

-
  • -

    - Plugins - - Plugins are optional extras for the Inform compiler: additions which can be active or inactive on any given compilation run.

    -
  • -
  • -

    - Plugin Calls - - To place calls to the plugins.

    -
  • @@ -158,12 +148,29 @@
  • Calculus Problems - -

    + Errors with formulating logical statements are sometimes caught by the calculus module: this section collects and issues such errors as tidy Inform problems.

  • Kinds Problems - -

    + Errors in setting up kinds and how they multiply are sometimes caught by the kinds module: this section collects and issues such errors as tidy Inform problems.

    +
  • + + +
  • +

    + Chapter 3: Plugins

    +

    Extensions to the main compiler, which can be either active or inactive.

    +
  • diff --git a/docs/if-module/1-im.html b/docs/if-module/1-im.html index 283821bc8..d76df77bc 100644 --- a/docs/if-module/1-im.html +++ b/docs/if-module/1-im.html @@ -171,7 +171,7 @@ foundation module does that automatically.) COMPILE_WRITER(grammar_verb *, PL::Parsing::Verbs::log) COMPILE_WRITER(grammar_line *, PL::Parsing::Lines::log) COMPILE_WRITER(action_name_list *, PL::Actions::ConstantLists::log) -COMPILE_WRITER(action_name *, PL::Actions::log) +COMPILE_WRITER(action_name *, PL::Actions::log) void IFModule::start(void) { Create this module's plugins4.1; @@ -239,7 +239,7 @@ foundation module does that automatically.) REGISTER_WRITER('G', PL::Parsing::Verbs::log); REGISTER_WRITER('g', PL::Parsing::Lines::log); REGISTER_WRITER('L', PL::Actions::ConstantLists::log); - REGISTER_WRITER('l', PL::Actions::log); + REGISTER_WRITER('l', PL::Actions::log);

    §5. This module uses syntax, and adds two node types to the syntax tree: diff --git a/docs/if-module/1-ism.html b/docs/if-module/1-ism.html index 96ea56a55..0523c4f33 100644 --- a/docs/if-module/1-ism.html +++ b/docs/if-module/1-ism.html @@ -72,7 +72,7 @@ SpecialMeanings::declare(PL::Scenes::ends_when_SMF, I"scene-ends-when", 1); SpecialMeanings::declare(PL::Parsing::understand_as_SMF, I"understand-as", 1); - SpecialMeanings::declare(PL::Actions::new_action_SMF, I"new-action", 2); + SpecialMeanings::declare(PL::Actions::new_action_SMF, I"new-action", 2); SpecialMeanings::declare(PL::Bibliographic::episode_SMF, I"episode", 2); SpecialMeanings::declare(PL::Bibliographic::Release::release_along_with_SMF,I"release-along-with", 4); diff --git a/docs/if-module/2-bd.html b/docs/if-module/2-bd.html index 758930e5a..a350eba4c 100644 --- a/docs/if-module/2-bd.html +++ b/docs/if-module/2-bd.html @@ -104,7 +104,7 @@ effect is only to make a small number of variables special.

     void PL::Bibliographic::start(void) {
    -    REGISTER(NEW_VARIABLE_NOTIFY_PCALL, PL::Bibliographic::bibliographic_new_variable_notify);
    +    PluginManager::plug(NEW_VARIABLE_NOTIFY_PLUG, PL::Bibliographic::bibliographic_new_variable_notify);
     }
     

    §3. The following grammar contains the names of all of the bibliographic diff --git a/docs/if-module/3-bck.html b/docs/if-module/3-bck.html index eee6ec257..6e491af64 100644 --- a/docs/if-module/3-bck.html +++ b/docs/if-module/3-bck.html @@ -73,7 +73,7 @@ function togglePopup(material_id) {

    A plugin to provide support for backdrop objects, which are present as scenery in multiple rooms at once.

    -
    +

    §1. While we normally assume that nothing can be in more than one place at once, backdrops are an exception. These are intended to represent widely @@ -111,11 +111,10 @@ inferences to avoid piling up bogus inconsistencies. FOUND_EVERYWHERE_INF = Inferences::new_family(I"FOUND_EVERYWHERE_INF"); - REGISTER(NEW_BASE_KIND_NOTIFY_PCALL, PL::Backdrops::backdrops_new_base_kind_notify); - REGISTER(NEW_PROPERTY_NOTIFY_PCALL, PL::Backdrops::backdrops_new_property_notify); - REGISTER(COMPLETE_MODEL_PCALL, PL::Backdrops::backdrops_complete_model); - REGISTER(ESTIMATE_PROPERTY_USAGE_PCALL, PL::Backdrops::backdrops_estimate_property_usage); - REGISTER(INTERVENE_IN_ASSERTION_PCALL, PL::Backdrops::backdrops_intervene_in_assertion); + PluginManager::plug(NEW_BASE_KIND_NOTIFY_PLUG, PL::Backdrops::backdrops_new_base_kind_notify); + PluginManager::plug(NEW_PROPERTY_NOTIFY_PLUG, PL::Backdrops::backdrops_new_property_notify); + PluginManager::plug(COMPLETE_MODEL_PLUG, PL::Backdrops::backdrops_complete_model); + PluginManager::plug(INTERVENE_IN_ASSERTION_PLUG, PL::Backdrops::backdrops_intervene_in_assertion); } typedef struct found_in_inference_data { @@ -123,7 +122,7 @@ inferences to avoid piling up bogus inconsistencies. CLASS_DEFINITION } found_in_inference_data; -inference *PL::Backdrops::new_found_in_inference(inference_subject *loc, int certitude) { +inference *PL::Backdrops::new_found_in_inference(inference_subject *loc, int certitude) { PROTECTED_MODEL_PROCEDURE; found_in_inference_data *data = CREATE(found_in_inference_data); data->location = InferenceSubjects::divert(loc); @@ -149,7 +148,7 @@ inferences to avoid piling up bogus inconsistencies. return CI_IDENTICAL; } -instance *PL::Backdrops::get_inferred_location(inference *i) { +instance *PL::Backdrops::get_inferred_location(inference *i) { if ((i == NULL) || (i->family != FOUND_IN_INF)) internal_error("not a FOUND_IN_INF inf"); found_in_inference_data *data = RETRIEVE_POINTER_found_in_inference_data(i->data); @@ -180,7 +179,7 @@ there is no need to translate this to other languages.)

    §6.

    -int PL::Backdrops::object_is_a_backdrop(instance *I) {
    +int PL::Backdrops::object_is_a_backdrop(instance *I) {
         if ((PluginManager::active(regions_plugin)) && (K_backdrop) && (I) &&
             (Instances::of_kind(I, K_backdrop))) return TRUE;
         return FALSE;
    @@ -211,16 +210,7 @@ Standard Rules. (So there is no need to translate this to other languages.)
         return FALSE;
     }
     
    -

    §9. Every backdrop needs a single-word property (found_in at the I6 level): -

    - -
    -int PL::Backdrops::backdrops_estimate_property_usage(kind *k, int *words_used) {
    -    if (Kinds::eq(k, K_backdrop)) *words_used += 2;
    -    return FALSE;
    -}
    -
    -

    §10. Here we look at "in" and "part of" relationships to see if they concern +

    §9. Here we look at "in" and "part of" relationships to see if they concern backdrops; if they do, then they need to become FOUND_IN_INF inferences. Without this intervention, they'd be subject to the usual spatial rules and text like @@ -234,7 +224,7 @@ and text like

    -int PL::Backdrops::assert_relations(binary_predicate *relation,
    +int PL::Backdrops::assert_relations(binary_predicate *relation,
         instance *I0, instance *I1) {
     
         if ((Instances::of_kind(I1, K_backdrop)) &&
    @@ -253,7 +243,7 @@ and text like
         return FALSE;
     }
     
    -

    §11. For indexing purposes, the following loops are useful: +

    §10. For indexing purposes, the following loops are useful:

    define LOOP_OVER_BACKDROPS_IN(B, P, I)
    @@ -266,33 +256,33 @@ and text like
             if (PL::Backdrops::object_is_a_backdrop(B))
                 POSITIVE_KNOWLEDGE_LOOP(I, Instances::as_subject(B), FOUND_EVERYWHERE_INF)
     
    -

    §12. Since backdrops are contained using different mechanisms, the following +

    §11. Since backdrops are contained using different mechanisms, the following (which does nothing if Backdrops isn't plugged in) adds backdrop contents to a room called loc, or lists backdrops which are "everywhere" if loc is NULL.

    -void PL::Backdrops::index_object_further(OUTPUT_STREAM, instance *loc, int depth,
    +void PL::Backdrops::index_object_further(OUTPUT_STREAM, instance *loc, int depth,
         int details, int how) {
         int discoveries = 0;
         instance *bd;
         inference *inf;
         if (loc) {
             LOOP_OVER_BACKDROPS_IN(bd, loc, inf) {
    -            if (++discoveries == 1) Insert fore-matter12.1;
    +            if (++discoveries == 1) Insert fore-matter11.1;
                 Data::Objects::index(OUT, bd, NULL, depth+1, details);
             }
         } else {
             LOOP_OVER_BACKDROPS_EVERYWHERE(bd, inf) {
    -            if (++discoveries == 1) Insert fore-matter12.1;
    +            if (++discoveries == 1) Insert fore-matter11.1;
                 Data::Objects::index(OUT, bd, NULL, depth+1, details);
             }
         }
    -    if (discoveries > 0) Insert after-matter12.2;
    +    if (discoveries > 0) Insert after-matter11.2;
     }
     
    -

    §12.1. Insert fore-matter12.1 = +

    §11.1. Insert fore-matter11.1 =

    @@ -301,8 +291,8 @@ is NULL.
             case 2: HTML_TAG("br"); break;
         }
     
    - -

    §12.2. Insert after-matter12.2 = +

    +

    §11.2. Insert after-matter11.2 =

    @@ -311,8 +301,8 @@ is NULL.
             case 2: break;
         }
     
    - -

    §13. Everywhere. Here we defines a form of noun phrase special to Backdrops (because a backdrop +

    +

    §12. Everywhere. Here we defines a form of noun phrase special to Backdrops (because a backdrop can be said to be "everywhere", which nothing else can).

    @@ -321,10 +311,10 @@ can be said to be "everywhere", which nothing else can). everywhere -

    §14.

    +

    §13.

    -int PL::Backdrops::backdrops_intervene_in_assertion(parse_node *px, parse_node *py) {
    +int PL::Backdrops::backdrops_intervene_in_assertion(parse_node *px, parse_node *py) {
         if ((Node::get_type(py) == EVERY_NT) &&
             (<notable-backdrops-noun-phrases>(Node::get_text(py)))) {
             inference_subject *left_subject = Node::get_subject(px);
    @@ -347,12 +337,12 @@ can be said to be "everywhere", which nothing else can).
         return FALSE;
     }
     
    -

    §15. And this is where it makes the necessary inference after such a request has +

    §14. And this is where it makes the necessary inference after such a request has been asserted true:

    -void PL::Backdrops::infer_presence_everywhere(instance *I) {
    +void PL::Backdrops::infer_presence_everywhere(instance *I) {
         if ((I == NULL) || (Instances::of_kind(I, K_backdrop) == FALSE)) {
             StandardProblems::sentence_problem(Task::syntax_tree(), _p_(PM_EverywhereNonBackdrop),
                 "only a backdrop can be everywhere",
    @@ -364,33 +354,33 @@ been asserted true:
         Inferences::join_inference(Inferences::create_inference(FOUND_EVERYWHERE_INF, NULL_GENERAL_POINTER, prevailing_mood), Instances::as_subject(I));
     }
     
    -

    §16. Model completion. We intervene only at Stage II, the spatial modelling stage. +

    §15. Model completion. We intervene only at Stage II, the spatial modelling stage.

    -int PL::Backdrops::backdrops_complete_model(int stage) {
    +int PL::Backdrops::backdrops_complete_model(int stage) {
         if (stage == WORLD_STAGE_II) {
             P_absent = EitherOrProperties::new_nameless(L"absent");
             RTProperties::implement_as_attribute(P_absent, TRUE);
             instance *I;
             LOOP_OVER_INSTANCES(I, K_object) {
                 inter_name *FOUNDIN = NULL;
    -            If the object is found everywhere, make a found-in property accordingly16.1;
    +            If the object is found everywhere, make a found-in property accordingly15.1;
                 int room_count = 0, region_count = 0;
    -            Find how many rooms or regions the object is found inside16.2;
    +            Find how many rooms or regions the object is found inside15.2;
                 if ((FOUNDIN == NULL) && (room_count > 0) && (room_count < 16) && (region_count == 0))
    -                The object is found only in a few rooms, and no regions, so make it a list16.3;
    +                The object is found only in a few rooms, and no regions, so make it a list15.3;
                 if ((FOUNDIN == NULL) && (room_count + region_count > 0))
    -                The object is found in many rooms or in whole regions, so make it a routine16.4;
    +                The object is found in many rooms or in whole regions, so make it a routine15.4;
                 if ((FOUNDIN == NULL) && (Instances::of_kind(I, K_backdrop)))
    -                The object is found nowhere, so give it a stub found-in property and mark it absent16.5;
    +                The object is found nowhere, so give it a stub found-in property and mark it absent15.5;
                 if (FOUNDIN) PL::Map::set_found_in(I, FOUNDIN);
             }
         }
         return FALSE;
     }
     
    -

    §16.1. If the object is found everywhere, make a found-in property accordingly16.1 = +

    §15.1. If the object is found everywhere, make a found-in property accordingly15.1 =

    @@ -400,8 +390,8 @@ been asserted true:
             break;
         }
     
    - -

    §16.2. Find how many rooms or regions the object is found inside16.2 = +

    +

    §15.2. Find how many rooms or regions the object is found inside15.2 =

    @@ -412,8 +402,8 @@ been asserted true:
             else room_count++;
         }
     
    - -

    §16.3. The object is found only in a few rooms, and no regions, so make it a list16.3 = +

    +

    §15.3. The object is found only in a few rooms, and no regions, so make it a list15.3 =

    @@ -426,8 +416,8 @@ been asserted true:
         Emit::array_end(save);
         Produce::annotate_i(FOUNDIN, INLINE_ARRAY_IANN, 1);
     
    - -

    §16.4. The object is found in many rooms or in whole regions, so make it a routine16.4 = +

    +

    §15.4. The object is found in many rooms or in whole regions, so make it a routine15.4 =

    @@ -438,14 +428,14 @@ been asserted true:
         notice->many_places = TRUE;
         FOUNDIN = notice->found_in_routine_iname;
     
    - -

    §16.5. absent is an I6-only attribute which marks a backdrop has having been removed +

    +

    §15.5. absent is an I6-only attribute which marks a backdrop has having been removed from the world model. It's not sufficient for an object's found_in always to say no to the question "are you in the current location?"; the I6 template code, derived from the old I6 library, requires absent to be set. So:

    -

    The object is found nowhere, so give it a stub found-in property and mark it absent16.5 = +

    The object is found nowhere, so give it a stub found-in property and mark it absent15.5 =

    @@ -458,8 +448,8 @@ code, derived from the old I6 library, requires     EitherOrProperties::assert(
             P_absent, Instances::as_subject(I), TRUE, CERTAIN_CE);
     
    - -

    §17.

    + +

    §16.

     void PL::Backdrops::write_found_in_routines(void) {
    @@ -467,13 +457,13 @@ code, derived from the old I6 library, requires     LOOP_OVER(notice, backdrop_found_in_notice) {
             instance *I = notice->backdrop;
             if (notice->many_places)
    -            The object is found in many rooms or in whole regions17.1
    +            The object is found in many rooms or in whole regions16.1
             else
    -            The object is found nowhere17.2;
    +            The object is found nowhere16.2;
         }
     }
     
    -

    §17.1. The object is found in many rooms or in whole regions17.1 = +

    §16.1. The object is found in many rooms or in whole regions16.1 =

    @@ -506,8 +496,8 @@ code, derived from the old I6 library, requires     }
         Routines::end(save);
     
    - -

    §17.2. The object is found nowhere17.2 = +

    +

    §16.2. The object is found nowhere16.2 =

    @@ -515,7 +505,7 @@ code, derived from the old I6 library, requires     Produce::rfalse(Emit::tree());
         Routines::end(save);
     
    - + diff --git a/docs/if-module/3-dvc.html b/docs/if-module/3-dvc.html index 8faadb833..f859a3415 100644 --- a/docs/if-module/3-dvc.html +++ b/docs/if-module/3-dvc.html @@ -87,8 +87,8 @@ age of Inter we want to avoid that sort of tomfoolery.
     void PL::Devices::start(void) {
    -    REGISTER(NEW_BASE_KIND_NOTIFY_PCALL, PL::Devices::devices_new_base_kind_notify);
    -    REGISTER(COMPLETE_MODEL_PCALL, PL::Devices::IF_complete_model);
    +    PluginManager::plug(NEW_BASE_KIND_NOTIFY_PLUG, PL::Devices::devices_new_base_kind_notify);
    +    PluginManager::plug(COMPLETE_MODEL_PLUG, PL::Devices::IF_complete_model);
     }
     

    §3.

    diff --git a/docs/if-module/3-em.html b/docs/if-module/3-em.html index 4cc142fc3..6986a39cf 100644 --- a/docs/if-module/3-em.html +++ b/docs/if-module/3-em.html @@ -321,8 +321,8 @@ If all are null, then the global scope is used. int PL::EPSMap::obj_in_region(instance *I, instance *reg) { if ((I == NULL) || (reg == NULL)) return FALSE; - if (PL::Regions::enclosing(I) == reg) return TRUE; - return PL::EPSMap::obj_in_region(PL::Regions::enclosing(I), reg); + if (PL::Regions::enclosing(I) == reg) return TRUE; + return PL::EPSMap::obj_in_region(PL::Regions::enclosing(I), reg); }

    §11. String parameters. diff --git a/docs/if-module/3-enah.html b/docs/if-module/3-enah.html index 9c4134608..1b60d2f8e 100644 --- a/docs/if-module/3-enah.html +++ b/docs/if-module/3-enah.html @@ -227,7 +227,7 @@ we're dealing with a backdrop. So we play dumb. #ifdef IF_MODULE inference_subject *subj = Assert::subject_of_term(prop->terms[0]); instance *ox = InstanceSubjects::to_object_instance(subj); - PL::Backdrops::infer_presence_everywhere(ox); + PL::Backdrops::infer_presence_everywhere(ox); #endif } #endif diff --git a/docs/if-module/3-hm.html b/docs/if-module/3-hm.html index 9f2a70f26..3871e194e 100644 --- a/docs/if-module/3-hm.html +++ b/docs/if-module/3-hm.html @@ -607,7 +607,7 @@ from each other.) instance *R; LOOP_OVER_ROOMS(R) if (MAP_DATA(R)->world_index_colour == NULL) { - instance *reg = PL::Regions::enclosing(R); + instance *reg = PL::Regions::enclosing(R); if (reg) MAP_DATA(R)->world_index_colour = MAP_DATA(reg)->world_index_colour; else @@ -1284,7 +1284,7 @@ This is the chip shown on the "details" box for a room in the World Index.

    -void PL::HTMLMap::colour_chip(OUTPUT_STREAM, instance *I, instance *Reg, parse_node *at) {
    +void PL::HTMLMap::colour_chip(OUTPUT_STREAM, instance *I, instance *Reg, parse_node *at) {
         HTML_OPEN_WITH("table",
             "border=\"%d\" cellpadding=\"0\" cellspacing=\"0\" "
             "bordercolor=\"#%s\" height=\"%d\"",
    @@ -1319,7 +1319,7 @@ that nothing is shown if all of the rooms are outside of regions.
         int count = 0;
         instance *R;
         LOOP_OVER_ROOMS(R) {
    -        if (PL::Regions::enclosing(R) == reg) {
    +        if (PL::Regions::enclosing(R) == reg) {
                 if (count++ == 0) {
                     Start the region key table for this region13.1;
                 } else {
    diff --git a/docs/if-module/3-mcr.html b/docs/if-module/3-mcr.html
    index c93e7437f..756bf3ad0 100644
    --- a/docs/if-module/3-mcr.html
    +++ b/docs/if-module/3-mcr.html
    @@ -384,7 +384,7 @@ such.
     

    -binary_predicate *PL::MapDirections::get_mapping_relation(instance *dir) {
    +binary_predicate *PL::MapDirections::get_mapping_relation(instance *dir) {
         if (dir == NULL) return NULL;
         return MAP_DATA(dir)->direction_relation;
     }
    diff --git a/docs/if-module/3-prs.html b/docs/if-module/3-prs.html
    index 9f9d40d43..e2c424382 100644
    --- a/docs/if-module/3-prs.html
    +++ b/docs/if-module/3-prs.html
    @@ -87,7 +87,7 @@ sort of tomfoolery.
     
     
     void PL::Persons::start(void) {
    -    REGISTER(COMPLETE_MODEL_PCALL, PL::Persons::IF_complete_model);
    +    PluginManager::plug(COMPLETE_MODEL_PLUG, PL::Persons::IF_complete_model);
     }
     

    §3.

    diff --git a/docs/if-module/3-rgn.html b/docs/if-module/3-rgn.html index 17987cbc3..61eb7ebd3 100644 --- a/docs/if-module/3-rgn.html +++ b/docs/if-module/3-rgn.html @@ -73,7 +73,7 @@ function togglePopup(material_id) {

    A plugin providing support for grouping rooms together into named and nestable regions.

    -
    +

    §1. The relation "R in S" behaves so differently for regions that we need to define it separately, even though there's no difference in English syntax. So: @@ -112,21 +112,21 @@ following minimal structure, though it will only be relevant for instances of

     void PL::Regions::start(void) {
    -    REGISTER(CREATE_INFERENCES_PCALL, PL::Regions::create_inference_subjects);
    -    REGISTER(NEW_BASE_KIND_NOTIFY_PCALL, PL::Regions::regions_new_base_kind_notify);
    -    REGISTER(SET_SUBKIND_NOTIFY_PCALL, PL::Regions::regions_set_subkind_notify);
    -    REGISTER(NEW_SUBJECT_NOTIFY_PCALL, PL::Regions::regions_new_subject_notify);
    -    REGISTER(NEW_PROPERTY_NOTIFY_PCALL, PL::Regions::regions_new_property_notify);
    -    REGISTER(COMPLETE_MODEL_PCALL, PL::Regions::regions_complete_model);
    -    REGISTER(MORE_SPECIFIC_PCALL, PL::Regions::regions_more_specific);
    -    REGISTER(ESTIMATE_PROPERTY_USAGE_PCALL, PL::Regions::regions_estimate_property_usage);
    -    REGISTER(INTERVENE_IN_ASSERTION_PCALL, PL::Regions::regions_intervene_in_assertion);
    -    REGISTER(NAME_TO_EARLY_INFS_PCALL, PL::Regions::regions_name_to_early_infs);
    -    REGISTER(ADD_TO_WORLD_INDEX_PCALL, PL::Regions::regions_add_to_World_index);
    +    PluginManager::plug(CREATE_INFERENCE_SUBJECTS_PLUG, PL::Regions::create_inference_subjects);
    +    PluginManager::plug(NEW_BASE_KIND_NOTIFY_PLUG, PL::Regions::regions_new_base_kind_notify);
    +    PluginManager::plug(SET_SUBKIND_NOTIFY_PLUG, PL::Regions::regions_set_subkind_notify);
    +    PluginManager::plug(NEW_SUBJECT_NOTIFY_PLUG, PL::Regions::regions_new_subject_notify);
    +    PluginManager::plug(NEW_PROPERTY_NOTIFY_PLUG, PL::Regions::regions_new_property_notify);
    +    PluginManager::plug(COMPLETE_MODEL_PLUG, PL::Regions::regions_complete_model);
    +    PluginManager::plug(MORE_SPECIFIC_PLUG, PL::Regions::regions_more_specific);
    +    PluginManager::plug(INTERVENE_IN_ASSERTION_PLUG, PL::Regions::regions_intervene_in_assertion);
    +    PluginManager::plug(NAME_TO_EARLY_INFS_PLUG, PL::Regions::regions_name_to_early_infs);
    +    PluginManager::plug(ADD_TO_WORLD_INDEX_PLUG, PL::Regions::regions_add_to_World_index);
     }
     
    -void PL::Regions::create_inference_subjects(void) {
    +int PL::Regions::create_inference_subjects(void) {
         infs_region = InferenceSubjects::new_fundamental(global_constants, "region(early)");
    +    return FALSE;
     }
     
     regions_data *PL::Regions::new_data(inference_subject *subj) {
    @@ -137,7 +137,7 @@ following minimal structure, though it will only be relevant for instances of
         return rd;
     }
     
    -inter_name *PL::Regions::found_in_iname(instance *I) {
    +inter_name *PL::Regions::found_in_iname(instance *I) {
         if (REGIONS_DATA(I)->in_region_iname == NULL)
             REGIONS_DATA(I)->in_region_iname = Hierarchy::make_iname_in(REGION_FOUND_IN_FN_HL, RTInstances::package(I));
         return REGIONS_DATA(I)->in_region_iname;
    @@ -188,7 +188,7 @@ there is no need to translate this to other languages.)
     

    §8.

    -int PL::Regions::object_is_a_region(instance *I) {
    +int PL::Regions::object_is_a_region(instance *I) {
         if ((PluginManager::active(regions_plugin)) && (K_region) && (I) &&
             (Instances::of_kind(I, K_region))) return TRUE;
         return FALSE;
    @@ -234,20 +234,12 @@ Standard Rules. (So there is no need to translate this to other languages.)
         return FALSE;
     }
     
    -

    §12.

    - -
    -int PL::Regions::regions_estimate_property_usage(kind *k, int *words_used) {
    -    if (Kinds::eq(k, K_region)) *words_used += 2;
    -    return FALSE;
    -}
    -
    -

    §13. Assertions. The following doesn't really intervene at all: it simply produces two problem +

    §12. Assertions. The following doesn't really intervene at all: it simply produces two problem messages which would have been less helpful if core Inform had produced them.

    -int PL::Regions::regions_intervene_in_assertion(parse_node *px, parse_node *py) {
    +int PL::Regions::regions_intervene_in_assertion(parse_node *px, parse_node *py) {
         if ((Node::get_type(px) == PROPER_NOUN_NT) &&
             (Node::get_type(py) == COMMON_NOUN_NT)) {
             inference_subject *left_subject = Node::get_subject(px);
    @@ -285,18 +277,18 @@ messages which would have been less helpful if core Inform had produced them.
         return FALSE;
     }
     
    -

    §14. Relations.

    +

    §13. Relations.

    -int PL::Regions::regions_name_to_early_infs(wording W, inference_subject **infs) {
    +int PL::Regions::regions_name_to_early_infs(wording W, inference_subject **infs) {
         if ((<notable-regions-kinds>(W)) && (K_region == NULL)) *infs = infs_region;
         return FALSE;
     }
     
    -

    §15.

    +

    §14.

    -void PL::Regions::create_relations(void) {
    +void PL::Regions::create_relations(void) {
         R_regional_containment =
             BinaryPredicates::make_pair(spatial_bp_family,
                 BPTerms::new(infs_region),
    @@ -308,14 +300,14 @@ messages which would have been less helpful if core Inform had produced them.
         BinaryPredicates::set_index_details(R_regional_containment, NULL, "room/region");
     }
     
    -

    §16. We intervene only in limited cases: X contains Y, X regionally contains Y, +

    §15. We intervene only in limited cases: X contains Y, X regionally contains Y, or X incorporates Y; and only when X is a region. (This of course only applies to the built-in spatial relationships; regions are entirely free to participate in nonspatial relations.)

    -int PL::Regions::assert_relations(binary_predicate *relation,
    +int PL::Regions::assert_relations(binary_predicate *relation,
         instance *I0, instance *I1) {
         int I0_is_region = FALSE;
         if (Instances::of_kind(I0, K_region)) I0_is_region = TRUE;
    @@ -326,9 +318,9 @@ to participate in nonspatial relations.)
             if ((relation == R_incorporation) ||
                 (relation == R_containment) ||
                 (relation == R_regional_containment)) {
    -            You can only be declared as in one region16.1;
    -            if (I1_is_region) A region is being put inside a region16.2
    -            else A room is being put inside a region16.3;
    +            You can only be declared as in one region15.1;
    +            if (I1_is_region) A region is being put inside a region15.2
    +            else A room is being put inside a region15.3;
             } else {
                 StandardProblems::sentence_problem(Task::syntax_tree(), _p_(PM_RegionRelation),
                     "regions can only contain rooms",
    @@ -348,7 +340,7 @@ to participate in nonspatial relations.)
         return FALSE;
     }
     
    -

    §16.1. You can only be declared as in one region16.1 = +

    §15.1. You can only be declared as in one region15.1 =

    @@ -364,8 +356,8 @@ to participate in nonspatial relations.)
         REGIONS_DATA(I1)->in_region = I0;
         REGIONS_DATA(I1)->in_region_set_at = current_sentence;
     
    -
    • This code is used in §16.
    -

    §16.2. A region is being put inside a region16.2 = +

    • This code is used in §15.
    +

    §15.2. A region is being put inside a region15.2 =

    @@ -373,12 +365,12 @@ to participate in nonspatial relations.)
         inference_subject *outer = Instances::as_subject(I0);
         PL::Spatial::infer_parentage(inner, CERTAIN_CE, outer);
     
    -
    • This code is used in §16.
    -

    §16.3. Anything in or part of a region is necessarily a room, if it isn't known +

    • This code is used in §15.
    +

    §15.3. Anything in or part of a region is necessarily a room, if it isn't known to be a region already:

    -

    A room is being put inside a region16.3 = +

    A room is being put inside a region15.3 =

    @@ -387,14 +379,14 @@ to be a region already:
         Propositions::Abstract::assert_kind_of_instance(I1, K_room);
         PropertyInferences::draw(rm, P_map_region, spec);
     
    -
    • This code is used in §16.
    -

    §17. Note that because we use regular PARENTAGE_INF inferences to remember +

    • This code is used in §15.
    +

    §16. Note that because we use regular PARENTAGE_INF inferences to remember that one region is inside another, it follows that the progenitor of a region is either the next broadest region containing it, or else NULL.

    -instance *PL::Regions::enclosing(instance *reg) {
    +instance *PL::Regions::enclosing(instance *reg) {
         instance *P = NULL;
         if (PL::Spatial::object_is_a_room(reg)) P = REGIONS_DATA(reg)->in_region;
         if (PL::Regions::object_is_a_region(reg)) P = PL::Spatial::progenitor(reg);
    @@ -402,23 +394,23 @@ region is either the next broadest region containing it, or else     return P;
     }
     
    -

    §18. Model completion.

    +

    §17. Model completion.

    -int PL::Regions::regions_complete_model(int stage) {
    -    if (stage == WORLD_STAGE_II) Assert map-region properties of rooms and regions18.1;
    -    if (stage == WORLD_STAGE_III) Assert regional-found-in properties of regions18.2;
    +int PL::Regions::regions_complete_model(int stage) {
    +    if (stage == WORLD_STAGE_II) Assert map-region properties of rooms and regions17.1;
    +    if (stage == WORLD_STAGE_III) Assert regional-found-in properties of regions17.2;
         return FALSE;
     }
     
    -

    §18.1. The following is needed in case somebody does something like this: +

    §17.1. The following is needed in case somebody does something like this:

    A desert room is a kind of room. The map region of a desert room is usually Sahara.

    -

    Assert map-region properties of rooms and regions18.1 = +

    Assert map-region properties of rooms and regions17.1 =

    @@ -437,8 +429,8 @@ region is either the next broadest region containing it, or else             }
             }
     
    -
    • This code is used in §18.
    -

    §18.2. Assert regional-found-in properties of regions18.2 = +

    • This code is used in §17.
    +

    §17.2. Assert regional-found-in properties of regions17.2 =

    @@ -452,8 +444,8 @@ region is either the next broadest region containing it, or else                 Rvalues::from_iname(iname), CERTAIN_CE);
             }
     
    -
    • This code is used in §18.
    -

    §19.

    +
    • This code is used in §17.
    +

    §18.

     void PL::Regions::write_regional_found_in_routines(void) {
    @@ -479,12 +471,12 @@ region is either the next broadest region containing it, or else         }
     }
     
    -

    §20.

    +

    §19.

    -int PL::Regions::regions_add_to_World_index(OUTPUT_STREAM, instance *O) {
    +int PL::Regions::regions_add_to_World_index(OUTPUT_STREAM, instance *O) {
         if ((O) && (Instances::of_kind(O, K_room))) {
    -        instance *R = PL::Regions::enclosing(O);
    +        instance *R = PL::Regions::enclosing(O);
             if (R) PL::HTMLMap::colour_chip(OUT, O, R, REGIONS_DATA(O)->in_region_set_at);
         }
         return FALSE;
    diff --git a/docs/if-module/3-scn.html b/docs/if-module/3-scn.html
    index d1090942c..2141f0dc3 100644
    --- a/docs/if-module/3-scn.html
    +++ b/docs/if-module/3-scn.html
    @@ -171,9 +171,9 @@ including bit 1 which records whether the scene has started.
     
     
     void PL::Scenes::start(void) {
    -    REGISTER(NEW_PROPERTY_NOTIFY_PCALL, PL::Scenes::scenes_new_property_notify);
    -    REGISTER(NEW_INSTANCE_NOTIFY_PCALL, PL::Scenes::scenes_new_named_instance_notify);
    -    REGISTER(NEW_BASE_KIND_NOTIFY_PCALL, PL::Scenes::scenes_new_base_kind_notify);
    +    PluginManager::plug(NEW_PROPERTY_NOTIFY_PLUG, PL::Scenes::scenes_new_property_notify);
    +    PluginManager::plug(NEW_INSTANCE_NOTIFY_PLUG, PL::Scenes::scenes_new_named_instance_notify);
    +    PluginManager::plug(NEW_BASE_KIND_NOTIFY_PLUG, PL::Scenes::scenes_new_base_kind_notify);
     }
     

    §8. To detect "scene" and "recurring": diff --git a/docs/if-module/3-sm.html b/docs/if-module/3-sm.html index a36dcf2c9..936bf4b23 100644 --- a/docs/if-module/3-sm.html +++ b/docs/if-module/3-sm.html @@ -137,20 +137,20 @@ indications of spatial structure:

    §4.

    -void PL::Spatial::infer_is_room(inference_subject *R, int certitude) {
    +void PL::Spatial::infer_is_room(inference_subject *R, int certitude) {
         Inferences::join_inference(Inferences::create_inference(IS_ROOM_INF, NULL_GENERAL_POINTER, certitude), R);
     }
     void PL::Spatial::infer_is_nowhere(inference_subject *R, int certitude) {
         Inferences::join_inference(Inferences::create_inference(PARENTAGE_NOWHERE_INF, NULL_GENERAL_POINTER, certitude), R);
     }
    -void PL::Spatial::infer_part_of(inference_subject *inner, int certitude, inference_subject *outer) {
    +void PL::Spatial::infer_part_of(inference_subject *inner, int certitude, inference_subject *outer) {
         part_of_inference_data *data = CREATE(part_of_inference_data);
         data->parent = InferenceSubjects::divert(outer);
         inference *i = Inferences::create_inference(PART_OF_INF,
             STORE_POINTER_part_of_inference_data(data), certitude);
         Inferences::join_inference(i, inner);
     }
    -void PL::Spatial::infer_parentage(inference_subject *inner, int certitude, inference_subject *outer) {
    +void PL::Spatial::infer_parentage(inference_subject *inner, int certitude, inference_subject *outer) {
         parentage_inference_data *data = CREATE(parentage_inference_data);
         data->parent = InferenceSubjects::divert(outer);
         inference *i = Inferences::create_inference(PARENTAGE_INF,
    @@ -291,19 +291,19 @@ timing issue to get around (see below).
         METHOD_ADD(PART_OF_INF, LOG_DETAILS_INF_MTID, PL::Spatial::log_part_of_inference);
         METHOD_ADD(PART_OF_INF, COMPARE_INF_MTID, PL::Spatial::cmp_part_of_inference);
     
    -    REGISTER(CREATE_INFERENCES_PCALL, PL::Spatial::create_inference_subjects);
    -    REGISTER(NEW_BASE_KIND_NOTIFY_PCALL, PL::Spatial::spatial_new_base_kind_notify);
    -    REGISTER(ACT_ON_SPECIAL_NPS_PCALL, PL::Spatial::spatial_act_on_special_NPs);
    -    REGISTER(COMPLETE_MODEL_PCALL, PL::Spatial::IF_complete_model);
    -    REGISTER(DEFAULT_APPEARANCE_PCALL, PL::Spatial::spatial_default_appearance);
    -    REGISTER(NAME_TO_EARLY_INFS_PCALL, PL::Spatial::spatial_name_to_early_infs);
    -    REGISTER(NEW_SUBJECT_NOTIFY_PCALL, PL::Spatial::spatial_new_subject_notify);
    -    REGISTER(NEW_PROPERTY_NOTIFY_PCALL, PL::Spatial::spatial_new_property_notify);
    -    REGISTER(PARSE_COMPOSITE_NQS_PCALL, PL::Spatial::spatial_parse_composite_NQs);
    -    REGISTER(SET_KIND_NOTIFY_PCALL, PL::Spatial::spatial_set_kind_notify);
    -    REGISTER(SET_SUBKIND_NOTIFY_PCALL, PL::Spatial::spatial_set_subkind_notify);
    -    REGISTER(ADD_TO_WORLD_INDEX_PCALL, PL::Spatial::spatial_add_to_World_index);
    -    REGISTER(INTERVENE_IN_ASSERTION_PCALL, PL::Spatial::spatial_intervene_in_assertion);
    +    PluginManager::plug(CREATE_INFERENCE_SUBJECTS_PLUG, PL::Spatial::create_inference_subjects);
    +    PluginManager::plug(NEW_BASE_KIND_NOTIFY_PLUG, PL::Spatial::spatial_new_base_kind_notify);
    +    PluginManager::plug(ACT_ON_SPECIAL_NPS_PLUG, PL::Spatial::spatial_act_on_special_NPs);
    +    PluginManager::plug(COMPLETE_MODEL_PLUG, PL::Spatial::IF_complete_model);
    +    PluginManager::plug(DEFAULT_APPEARANCE_PLUG, PL::Spatial::spatial_default_appearance);
    +    PluginManager::plug(NAME_TO_EARLY_INFS_PLUG, PL::Spatial::spatial_name_to_early_infs);
    +    PluginManager::plug(NEW_SUBJECT_NOTIFY_PLUG, PL::Spatial::spatial_new_subject_notify);
    +    PluginManager::plug(NEW_PROPERTY_NOTIFY_PLUG, PL::Spatial::spatial_new_property_notify);
    +    PluginManager::plug(PARSE_COMPOSITE_NQS_PLUG, PL::Spatial::spatial_parse_composite_NQs);
    +    PluginManager::plug(SET_KIND_NOTIFY_PLUG, PL::Spatial::spatial_set_kind_notify);
    +    PluginManager::plug(SET_SUBKIND_NOTIFY_PLUG, PL::Spatial::spatial_set_subkind_notify);
    +    PluginManager::plug(ADD_TO_WORLD_INDEX_PLUG, PL::Spatial::spatial_add_to_World_index);
    +    PluginManager::plug(INTERVENE_IN_ASSERTION_PLUG, PL::Spatial::spatial_intervene_in_assertion);
     }
     
     int PL::Spatial::is_room_explain_contradiction(inference_family *f, inference *A,
    @@ -377,11 +377,12 @@ after stage (d) when they exist.
     

    -void PL::Spatial::create_inference_subjects(void) {
    +int PL::Spatial::create_inference_subjects(void) {
         infs_room =      InferenceSubjects::new_fundamental(global_constants, "room(early)");
         infs_thing =     InferenceSubjects::new_fundamental(global_constants, "thing(early)");
         infs_supporter = InferenceSubjects::new_fundamental(global_constants, "supporter(early)");
         infs_person =    InferenceSubjects::new_fundamental(global_constants, "person(early)");
    +    return FALSE;
     }
     

    §9. And this is where those IOUs are redeemed. What happens is that, ordinarily, @@ -512,7 +513,7 @@ of vehicle, and so on, but this would cause mayhem in the model world. So:

    -int PL::Spatial::object_is_a_room(instance *I) {
    +int PL::Spatial::object_is_a_room(instance *I) {
         if ((PluginManager::active(spatial_plugin)) && (K_room) && (I) &&
             (Instances::of_kind(I, K_room)))
             return TRUE;
    @@ -1002,13 +1003,13 @@ provide access routines to read and write:
     

    -instance *PL::Spatial::progenitor(instance *I) {
    +instance *PL::Spatial::progenitor(instance *I) {
         if (I == NULL) return NULL;
         if (PluginManager::active(spatial_plugin) == FALSE) return NULL;
         return SPATIAL_DATA(I)->progenitor;
     }
     
    -void PL::Spatial::set_progenitor(instance *of, instance *to, inference *reason) {
    +void PL::Spatial::set_progenitor(instance *of, instance *to, inference *reason) {
         if (PluginManager::active(spatial_plugin) == FALSE)
             internal_error("spatial plugin inactive");
         if (to == NULL) internal_error("set progenitor of nothing");
    @@ -1735,7 +1736,7 @@ it already turns up under its owner.
             }
         }
         PL::Player::index_object_further(OUT, I, depth, details);
    -    PL::Backdrops::index_object_further(OUT, I, depth, details, 0);
    +    PL::Backdrops::index_object_further(OUT, I, depth, details, 0);
     
         if (SPATIAL_DATA(I)->object_tree_sibling)
             Data::Objects::index(OUT, SPATIAL_DATA(I)->object_tree_sibling, NULL, depth, details);
    diff --git a/docs/if-module/3-sm2.html b/docs/if-module/3-sm2.html
    index d91396c86..67238d831 100644
    --- a/docs/if-module/3-sm2.html
    +++ b/docs/if-module/3-sm2.html
    @@ -2880,8 +2880,8 @@ contain.
             instance *R1 = mc1->first_room_in_submap;
             instance *R2 = mc2->first_room_in_submap;
             if ((R1) && (R2)) {  which should always happen, but just in case of an error
    -            instance *reg1 = PL::Regions::enclosing(R1);
    -            instance *reg2 = PL::Regions::enclosing(R2);
    +            instance *reg1 = PL::Regions::enclosing(R1);
    +            instance *reg2 = PL::Regions::enclosing(R2);
                 if ((reg1) && (reg2 == NULL)) return -1;
                 if ((reg1 == NULL) && (reg2)) return 1;
                 if (reg1) {
    @@ -3013,12 +3013,12 @@ running time in check.
         if (sub->bounds.population == 1) {
             instance *R = sub->first_room_in_submap;
             if (R) {  which should always happen, but just in case of an error
    -            instance *reg = PL::Regions::enclosing(R);
    +            instance *reg = PL::Regions::enclosing(R);
                 if (reg) {
                     instance *S, *closest_S = NULL;
                     int closest = 0;
                     LOOP_OVER_ROOMS(S)
    -                    if ((S != R) && (PL::Regions::enclosing(S) == reg))
    +                    if ((S != R) && (PL::Regions::enclosing(S) == reg))
                             if ((posnd == FALSE) || (MAP_DATA(S)->submap->positioned)) {
                                 int diff = 2*(R->allocation_id - S->allocation_id);
                                 if (diff < 0) diff = 1-diff;
    @@ -3167,7 +3167,7 @@ can make use of the following:
         if (Instances::of_kind(R, K_room)) {
             wording RW = Instances::get_name(R, FALSE);
             LOG("%+W is a room.\n", RW);
    -        instance *reg = PL::Regions::enclosing(R);
    +        instance *reg = PL::Regions::enclosing(R);
             if (reg) {
                 wording RGW = Instances::get_name(reg, FALSE);
                 if (MAP_DATA(reg)->zone == 1) {
    @@ -3239,7 +3239,7 @@ can make use of the following:
     

    -void PL::SpatialMap::index_room_connections(OUTPUT_STREAM, instance *R) {
    +void PL::SpatialMap::index_room_connections(OUTPUT_STREAM, instance *R) {
         wording RW = Instances::get_name(R, FALSE);  name of the origin room
         instance *dir;
         LOOP_OVER_INSTANCES(dir, K_direction) {
    diff --git a/docs/if-module/3-sr.html b/docs/if-module/3-sr.html
    index f9603c575..91121debc 100644
    --- a/docs/if-module/3-sr.html
    +++ b/docs/if-module/3-sr.html
    @@ -125,7 +125,7 @@ MathJax = {
             Make built-in spatial relationships2.1;
             Make built-in indirect spatial relationships2.2;
             PL::MapDirections::create_relations();
    -        PL::Regions::create_relations();
    +        PL::Regions::create_relations();
         }
     }
     
    @@ -302,9 +302,9 @@ way which isn't symmetrical between the two, and this way round is cleanest.

    -    if (PL::Backdrops::assert_relations(bp, I0, I1)) return TRUE;
    +    if (PL::Backdrops::assert_relations(bp, I0, I1)) return TRUE;
         if (PL::MapDirections::assert_relations(bp, I0, I1)) return TRUE;
    -    if (PL::Regions::assert_relations(bp, I0, I1)) return TRUE;
    +    if (PL::Regions::assert_relations(bp, I0, I1)) return TRUE;
     
    • This code is used in §4.

    §4.2. This is the point at which non-assertable relations are thrown out. diff --git a/docs/if-module/3-tm.html b/docs/if-module/3-tm.html index 2b3caa6a7..7f9cfdaae 100644 --- a/docs/if-module/3-tm.html +++ b/docs/if-module/3-tm.html @@ -87,7 +87,7 @@ MathJax = {

    A plugin to provide a geographical model, linking rooms and doors together in oppositely-paired directions.

    -
    +

    §1. The map is a complicated data structure, both because it amounts to a ternary relation (though being implemented by many binary ones) and because @@ -200,7 +200,7 @@ makes for more legible code if we use a special inference type of our own: Inferences::join_inference(i, infs_from); } -void PL::Map::get_map_references(inference *i, +void PL::Map::get_map_references(inference *i, inference_subject **infs1, inference_subject **infs2) { if ((i == NULL) || (i->family != DIRECTION_INF)) internal_error("not a direction inf"); @@ -263,20 +263,19 @@ makes for more legible code if we use a special inference type of our own: METHOD_ADD(DIRECTION_INF, LOG_DETAILS_INF_MTID, PL::Map::log_direction_inf); METHOD_ADD(DIRECTION_INF, COMPARE_INF_MTID, PL::Map::cmp_direction_inf); - REGISTER(NEW_BASE_KIND_NOTIFY_PCALL, PL::Map::map_new_base_kind_notify); - REGISTER(NEW_SUBJECT_NOTIFY_PCALL, PL::Map::map_new_subject_notify); - REGISTER(SET_KIND_NOTIFY_PCALL, PL::Map::map_set_kind_notify); - REGISTER(SET_SUBKIND_NOTIFY_PCALL, PL::Map::map_set_subkind_notify); - REGISTER(ACT_ON_SPECIAL_NPS_PCALL, PL::Map::map_act_on_special_NPs); - REGISTER(CHECK_GOING_PCALL, PL::Map::map_check_going); - REGISTER(COMPILE_MODEL_TABLES_PCALL, PL::Map::map_compile_model_tables); - REGISTER(ESTIMATE_PROPERTY_USAGE_PCALL, PL::Map::map_estimate_property_usage); - REGISTER(COMPLETE_MODEL_PCALL, PL::Map::map_complete_model); - REGISTER(NEW_PROPERTY_NOTIFY_PCALL, PL::Map::map_new_property_notify); - REGISTER(PROPERTY_VALUE_NOTIFY_PCALL, PL::Map::map_property_value_notify); - REGISTER(INTERVENE_IN_ASSERTION_PCALL, PL::Map::map_intervene_in_assertion); - REGISTER(ADD_TO_WORLD_INDEX_PCALL, PL::Map::map_add_to_World_index); - REGISTER(ANNOTATE_IN_WORLD_INDEX_PCALL, PL::Map::map_annotate_in_World_index); + PluginManager::plug(NEW_BASE_KIND_NOTIFY_PLUG, PL::Map::map_new_base_kind_notify); + PluginManager::plug(NEW_SUBJECT_NOTIFY_PLUG, PL::Map::map_new_subject_notify); + PluginManager::plug(SET_KIND_NOTIFY_PLUG, PL::Map::map_set_kind_notify); + PluginManager::plug(SET_SUBKIND_NOTIFY_PLUG, PL::Map::map_set_subkind_notify); + PluginManager::plug(ACT_ON_SPECIAL_NPS_PLUG, PL::Map::map_act_on_special_NPs); + PluginManager::plug(CHECK_GOING_PLUG, PL::Map::map_check_going); + PluginManager::plug(COMPILE_RUNTIME_DATA_PLUG, PL::Map::map_compile_model_tables); + PluginManager::plug(COMPLETE_MODEL_PLUG, PL::Map::map_complete_model); + PluginManager::plug(NEW_PROPERTY_NOTIFY_PLUG, PL::Map::map_new_property_notify); + PluginManager::plug(INFERENCE_DRAWN_NOTIFY_PLUG, PL::Map::map_inference_drawn); + PluginManager::plug(INTERVENE_IN_ASSERTION_PLUG, PL::Map::map_intervene_in_assertion); + PluginManager::plug(ADD_TO_WORLD_INDEX_PLUG, PL::Map::map_add_to_World_index); + PluginManager::plug(ANNOTATE_IN_WORLD_INDEX_PLUG, PL::Map::map_annotate_in_World_index); }

    §9.

    @@ -383,7 +382,7 @@ Rules. (So there is no need to translate this to other languages.)

    §15.

    -int PL::Map::object_is_a_door(instance *I) {
    +int PL::Map::object_is_a_door(instance *I) {
         if ((PluginManager::active(map_plugin)) && (K_door) && (I) &&
             (Instances::of_kind(I, K_door)))
             return TRUE;
    @@ -403,7 +402,7 @@ sheaf of binary relations, one for each direction. Anyway:
     

    -int PL::Map::is_a_direction(inference_subject *infs) {
    +int PL::Map::is_a_direction(inference_subject *infs) {
         if (K_direction == NULL) return FALSE;  in particular, if we aren't using the IF model
         return InferenceSubjects::is_within(infs, KindSubjects::from_kind(K_direction));
     }
    @@ -492,7 +491,7 @@ quite crunchy algorithms, has the fastest possible access to the layout.
     
    define MAP_EXIT(X, Y) MAP_DATA(X)->exits[Y]
     
    -void PL::Map::build_exits_array(void) {
    +void PL::Map::build_exits_array(void) {
         instance *I;
         int d = 0;
         LOOP_OVER_INSTANCES(I, K_object) {
    @@ -601,7 +600,7 @@ object has four pieces of data attached:
     

    -void PL::Map::get_door_data(instance *door, instance **c1, instance **c2) {
    +void PL::Map::get_door_data(instance *door, instance **c1, instance **c2) {
         if (c1) *c1 = MAP_DATA(door)->map_connection_a;
         if (c2) *c2 = MAP_DATA(door)->map_connection_b;
     }
    @@ -643,8 +642,10 @@ deduction is made:
     

    -int PL::Map::map_property_value_notify(property *prn, parse_node *val) {
    -    if (prn == P_other_side) {
    +int PL::Map::map_inference_drawn(inference *I, inference_subject *subj) {
    +    property *prn = PropertyInferences::get_property(I);
    +    if ((prn) && (prn == P_other_side)) {
    +        parse_node *val = PropertyInferences::get_value(I);
             instance *I = Rvalues::to_object_instance(val);
             if (I) PL::Spatial::infer_is_room(Instances::as_subject(I), CERTAIN_CE);
         }
    @@ -659,7 +660,7 @@ one and Backdrops), and this is where they set it.
     

    -void PL::Map::set_found_in(instance *I, inter_name *S) {
    +void PL::Map::set_found_in(instance *I, inter_name *S) {
         if (P_found_in == NULL)
             P_found_in = ValueProperties::new_nameless(I"found_in",
                 K_value);
    @@ -677,24 +678,14 @@ and there seems little point in writing this any better.
     

    -instance *PL::Map::get_value_of_opposite_property(instance *I) {
    +instance *PL::Map::get_value_of_opposite_property(instance *I) {
         parse_node *val = PropertyInferences::value_of(
             Instances::as_subject(I), P_opposite);
         if (val) return Rvalues::to_object_instance(val);
         return NULL;
     }
     
    -

    §28. This really is very approximate, but: -

    - -
    -int PL::Map::map_estimate_property_usage(kind *k, int *words_used) {
    -    if (Kinds::eq(k, K_door)) *words_used += 14;
    -    if (Kinds::eq(k, K_room)) *words_used += 2;
    -    return FALSE;
    -}
    -
    -

    §29. Linguistic extras. These NPs allow us to refer to the special directions "up" and "down": +

    §28. Linguistic extras. These NPs allow us to refer to the special directions "up" and "down":

    @@ -703,10 +694,10 @@ and there seems little point in writing this any better.
         above
     
    -

    §30.

    +

    §29.

    -int PL::Map::map_act_on_special_NPs(parse_node *p) {
    +int PL::Map::map_act_on_special_NPs(parse_node *p) {
         if (<notable-map-noun-phrases>(Node::get_text(p))) {
             switch (<<r>>) {
                 case 0:
    @@ -726,11 +717,11 @@ and there seems little point in writing this any better.
         return FALSE;
     }
     
    -

    §31. We also add some optional clauses to the "going" action: +

    §30. We also add some optional clauses to the "going" action:

    -int PL::Map::map_check_going(parse_node *from, parse_node *to,
    +int PL::Map::map_check_going(parse_node *from, parse_node *to,
         parse_node *by, parse_node *through, parse_node *pushing) {
         if (PL::Actions::Patterns::check_going(from, "from",
             K_room, K_region) == FALSE) return FALSE;
    @@ -745,7 +736,7 @@ and there seems little point in writing this any better.
         return TRUE;
     }
     
    -

    §32. Consider the sentences: +

    §31. Consider the sentences:

    @@ -772,7 +763,7 @@ because, of course, that does set its kind.

    -int PL::Map::map_intervene_in_assertion(parse_node *px, parse_node *py) {
    +int PL::Map::map_intervene_in_assertion(parse_node *px, parse_node *py) {
         if ((Node::get_type(px) == PROPER_NOUN_NT) &&
             (Node::get_type(py) == COMMON_NOUN_NT)) {
             inference_subject *left_object = Node::get_subject(px);
    @@ -792,7 +783,7 @@ because, of course, that does set its kind.
         return FALSE;
     }
     
    -

    §33. The map-connector. Now we come to the code which creates map connections. This needs special +

    §32. The map-connector. Now we come to the code which creates map connections. This needs special treatment only so that asserting \(M(X, Y)\) also asserts \(M'(Y, X)\), where \(M'\) is the predicate for the opposite direction to \(M\); but since this is only a guess, it drops from CERTAIN_CE to merely LIKELY_CE. @@ -807,7 +798,7 @@ make this guess; so we begin with switching in and out. void PL::Map::enter_one_way_mode(void) { oneway_map_connections_only = TRUE; } void PL::Map::exit_one_way_mode(void) { oneway_map_connections_only = FALSE; }

    -

    §34. Note that, in order to make the conjectural reverse map direction, we need +

    §33. Note that, in order to make the conjectural reverse map direction, we need to look up the "opposite" property of the forward one. This relies on all directions having their opposites defined before any map is built, and is the reason for Inform's insistence that directions are always created in matched @@ -835,7 +826,7 @@ pairs. return; } - PL::Map::oneway_map_connection(go_from, go_to, forwards_dir, CERTAIN_CE); + PL::Map::oneway_map_connection(go_from, go_to, forwards_dir, CERTAIN_CE); if ((reverse_dir) && (go_to) && (oneway_map_connections_only == FALSE)) { if (Instances::of_kind(reverse_dir, K_direction) == FALSE) { Problems::quote_object(1, forwards_dir); @@ -848,7 +839,7 @@ pairs. "which doesn't make sense since %2 isn't a direction. (Maybe " "you forgot to say that it was?)"); Problems::issue_problem_end(); - } else PL::Map::oneway_map_connection(go_to, go_from, reverse_dir, LIKELY_CE); + } else PL::Map::oneway_map_connection(go_to, go_from, reverse_dir, LIKELY_CE); } } @@ -864,41 +855,41 @@ pairs. prevailing_mood = x; }

    -

    §35. Model completion. And here begins the fun. It's not as easy to write down the requirements for +

    §34. Model completion. And here begins the fun. It's not as easy to write down the requirements for the map as might be thought.

    -int PL::Map::map_complete_model(int stage) {
    +int PL::Map::map_complete_model(int stage) {
         switch (stage) {
             case 2:
    -            Give each room a room-index property as workspace for route finding35.1;
    -            Ensure that map connections are room-to-room, room-to-door or door-to-room35.2;
    +            Give each room a room-index property as workspace for route finding34.1;
    +            Ensure that map connections are room-to-room, room-to-door or door-to-room34.2;
                 if (problem_count > 0) break;
    -            Ensure that every door has either one or two connections from it35.3;
    +            Ensure that every door has either one or two connections from it34.3;
                 if (problem_count > 0) break;
    -            Ensure that no door has spurious other connections to it35.4;
    +            Ensure that no door has spurious other connections to it34.4;
                 if (problem_count > 0) break;
    -            Ensure that no door uses both map connections and other side35.5;
    +            Ensure that no door uses both map connections and other side34.5;
                 if (problem_count > 0) break;
    -            Ensure that no door is present in a room to which it does not connect35.6;
    +            Ensure that no door is present in a room to which it does not connect34.6;
                 if (problem_count > 0) break;
    -            Place any one-sided door inside the room which connects to it35.7;
    -            Assert found-in, door-to and door-dir properties for doors35.8;
    +            Place any one-sided door inside the room which connects to it34.7;
    +            Assert found-in, door-to and door-dir properties for doors34.8;
                 break;
             case 4: PL::Map::build_exits_array(); break;
         }
         return FALSE;
     }
     
    -

    §35.1. Every room has a room_index property. It has no meaningful contents at +

    §34.1. Every room has a room_index property. It has no meaningful contents at the start of play, and we initialise to \(-1\) since this marks the route-finding cache as being broken. (Route-finding is one of the few really time-critical tasks at run-time, which is why we keep complicating the I7 code to accommodate it.)

    -

    Give each room a room-index property as workspace for route finding35.1 = +

    Give each room a room-index property as workspace for route finding34.1 =

    @@ -911,12 +902,12 @@ accommodate it.)
                 ValueProperties::assert(P_room_index,
                     Instances::as_subject(I), minus_one, CERTAIN_CE);
     
    -
    • This code is used in §35.
    -

    §35.2. The following code does little if the source is correct: it mostly +

    • This code is used in §34.
    +

    §34.2. The following code does little if the source is correct: it mostly checks that various mapping impossibilities do not occur.

    -

    Ensure that map connections are room-to-room, room-to-door or door-to-room35.2 = +

    Ensure that map connections are room-to-room, room-to-door or door-to-room34.2 =

    @@ -946,8 +937,8 @@ checks that various mapping impossibilities do not occur.
             }
         }
     
    -
    • This code is used in §35.
    -

    §35.3. Ensure that every door has either one or two connections from it35.3 = +

    • This code is used in §34.
    +

    §34.3. Ensure that every door has either one or two connections from it34.3 =

    @@ -994,12 +985,12 @@ checks that various mapping impossibilities do not occur.
                         parse_node *PX = where[0]; where[0] = where[1]; where[1] = PX;
                     }
                 }
    -            if (connections_in == 0) Issue a problem message for a stranded door35.3.1;
    -            if (connections_in > 2) Issue a problem message for an overactive door35.3.2;
    +            if (connections_in == 0) Issue a problem message for a stranded door34.3.1;
    +            if (connections_in > 2) Issue a problem message for an overactive door34.3.2;
             }
     
    -
    • This code is used in §35.
    -

    §35.3.1. Issue a problem message for a stranded door35.3.1 = +

    • This code is used in §34.
    +

    §34.3.1. Issue a problem message for a stranded door34.3.1 =

    @@ -1010,8 +1001,8 @@ checks that various mapping impossibilities do not occur.
             "on each side. You could do this by writing something like 'The blue door is "
             "east of the Library and west of the Conservatory'.");
     
    - -

    §35.3.2. Issue a problem message for an overactive door35.3.2 = +

    +

    §34.3.2. Issue a problem message for an overactive door34.3.2 =

    @@ -1028,15 +1019,15 @@ checks that various mapping impossibilities do not occur.
             "you really need a three-sided cavity, best to make it a room in its own right.");
         Problems::issue_problem_end();
     
    - -

    §35.4. Since map connections are not always reversible (only most of the time), we +

    +

    §34.4. Since map connections are not always reversible (only most of the time), we can't assume that having at most two ways out means there are at most two ways in. So we check here that any way in to a door corresponds to one of its ways out. (The reverse need not be true: it's possible for a door to lead to a room from which there's no way back.)

    -

    Ensure that no door has spurious other connections to it35.4 = +

    Ensure that no door has spurious other connections to it34.4 =

    @@ -1079,8 +1070,8 @@ from which there's no way back.)
                 }
             }
     
    -
    • This code is used in §35.
    -

    §35.5. Ensure that no door uses both map connections and other side35.5 = +

    • This code is used in §34.
    +

    §34.5. Ensure that no door uses both map connections and other side34.5 =

    @@ -1099,8 +1090,8 @@ from which there's no way back.)
                         "way to set up a one-sided door). As a door can't be both one- and "
                         "two-sided at once, I'm going to object to this.");
     
    -
    • This code is used in §35.
    -

    §35.6. The Spatial model requires that rooms are free-standing, that is, not in, on +

    • This code is used in §34.
    +

    §34.6. The Spatial model requires that rooms are free-standing, that is, not in, on or part of anything else; but it knows nothing of doors. So if we are not careful, the source text could put a door on a shelf, or make it part of a robot, or something like that. (Testing showed, in fact, that some authors @@ -1108,7 +1099,7 @@ actually wanted to do this, though the result was a horribly inconsistent model at run-time.) This is where we apply the kill-joy rule in question:

    -

    Ensure that no door is present in a room to which it does not connect35.6 = +

    Ensure that no door is present in a room to which it does not connect34.6 =

    @@ -1123,13 +1114,13 @@ model at run-time.) This is where we apply the kill-joy rule in question:
                     "but this is not allowed. A door must be in one or both of the rooms it is "
                     "between, but not in a third place altogether.");
     
    -
    • This code is used in §35.
    -

    §35.7. We don't need to do the following for two-sided doors since they will bypass +

    • This code is used in §34.
    +

    §34.7. We don't need to do the following for two-sided doors since they will bypass the object tree and use I6's found_in to be present in both rooms connecting to them.

    -

    Place any one-sided door inside the room which connects to it35.7 = +

    Place any one-sided door inside the room which connects to it34.7 =

    @@ -1140,14 +1131,14 @@ to them.
                 (PL::Spatial::progenitor(I) == NULL))
                 PL::Spatial::set_progenitor(I, MAP_DATA(I)->map_connection_a, NULL);
     
    -
    • This code is used in §35.
    -

    §35.8. At this point we know that the doors are correctly plumbed in, and all we +

    • This code is used in §34.
    +

    §34.8. At this point we know that the doors are correctly plumbed in, and all we need to do is compile properties to implement them. See the DM4 for details of how to compile one and two-sided doors in I6. Alternatively, take it on trust that there is nothing surprising here.

    -

    Assert found-in, door-to and door-dir properties for doors35.8 = +

    Assert found-in, door-to and door-dir properties for doors34.8 =

    @@ -1166,19 +1157,19 @@ trust that there is nothing surprising here.
                 instance *D1 = MAP_DATA(I)->map_direction_a;
                 instance *D2 = MAP_DATA(I)->map_direction_b;
                 if (R1 && R2) {
    -                Assert found-in for a two-sided door35.8.1;
    -                Assert door-dir for a two-sided door35.8.2;
    -                Assert door-to for a two-sided door35.8.3;
    +                Assert found-in for a two-sided door34.8.1;
    +                Assert door-dir for a two-sided door34.8.2;
    +                Assert door-to for a two-sided door34.8.3;
                 } else if (R1) {
    -                Assert door-dir for a one-sided door35.8.4;
    +                Assert door-dir for a one-sided door34.8.4;
                 }
             }
     
    -
    • This code is used in §35.
    -

    §35.8.1. Here found_in is a two-entry list. +

    • This code is used in §34.
    +

    §34.8.1. Here found_in is a two-entry list.

    -

    Assert found-in for a two-sided door35.8.1 = +

    Assert found-in for a two-sided door34.8.1 =

    @@ -1191,12 +1182,12 @@ trust that there is nothing surprising here.
         Produce::annotate_i(S, INLINE_ARRAY_IANN, 1);
         PL::Map::set_found_in(I, S);
     
    - -

    §35.8.2. Here door_dir is a routine looking at the current location and returning +

    +

    §34.8.2. Here door_dir is a routine looking at the current location and returning always the way to the other room — the one we are not in.

    -

    Assert door-dir for a two-sided door35.8.2 = +

    Assert door-dir for a two-sided door34.8.2 =

    @@ -1209,12 +1200,12 @@ always the way to the other room — the one we are not in.
         ValueProperties::assert(P_door_dir, Instances::as_subject(I),
             Rvalues::from_iname(notice->ddn_iname), CERTAIN_CE);
     
    - -

    §35.8.3. Here door_to is a routine looking at the current location and returning +

    +

    §34.8.3. Here door_to is a routine looking at the current location and returning always the other room — the one we are not in.

    -

    Assert door-to for a two-sided door35.8.3 = +

    Assert door-to for a two-sided door34.8.3 =

    @@ -1226,8 +1217,8 @@ always the other room — the one we are not in.
         ValueProperties::assert(P_door_to, Instances::as_subject(I),
             Rvalues::from_iname(notice->dtn_iname), CERTAIN_CE);
     
    - -

    §35.8.4. The reversal of direction here looks peculiar, but is correct. Suppose +

    +

    §34.8.4. The reversal of direction here looks peculiar, but is correct. Suppose the Drainage Room contains a one-sided door called the iron grating, and the iron grating is east of the Drainage Room. To get through, the player will type EAST. But that means the iron grating has one exit, west to the @@ -1240,7 +1231,7 @@ property for the door; "other side" is an alias for door_to here.

    -

    Assert door-dir for a one-sided door35.8.4 = +

    Assert door-dir for a one-sided door34.8.4 =

    @@ -1249,8 +1240,8 @@ why we don't need to compile 
             ValueProperties::assert(P_door_dir, Instances::as_subject(I),
                 Rvalues::from_iname(RTInstances::emitted_iname(backwards)), CERTAIN_CE);
     
    - -

    §36. Redeeming those notices.

    + +

    §35. Redeeming those notices.

     void PL::Map::write_door_dir_routines(void) {
    @@ -1363,17 +1354,17 @@ why we don't need to compile 
         }
     }
     
    -

    §37. Indexing.

    +

    §36. Indexing.

    -int PL::Map::map_add_to_World_index(OUTPUT_STREAM, instance *O) {
    +int PL::Map::map_add_to_World_index(OUTPUT_STREAM, instance *O) {
         if ((O) && (Instances::of_kind(O, K_room))) {
             PL::SpatialMap::index_room_connections(OUT, O);
         }
         return FALSE;
     }
     
    -int PL::Map::map_annotate_in_World_index(OUTPUT_STREAM, instance *O) {
    +int PL::Map::map_annotate_in_World_index(OUTPUT_STREAM, instance *O) {
         if ((O) && (Instances::of_kind(O, K_door))) {
             instance *A = NULL, *B = NULL;
             PL::Map::get_door_data(O, &A, &B);
    diff --git a/docs/if-module/3-tnt.html b/docs/if-module/3-tnt.html
    index d17d7e30f..809ac5866 100644
    --- a/docs/if-module/3-tnt.html
    +++ b/docs/if-module/3-tnt.html
    @@ -111,8 +111,8 @@ stream, though there aren't very many of them.
     
     
     void PL::Naming::start(void) {
    -    REGISTER(NEW_PROPERTY_NOTIFY_PCALL, PL::Naming::naming_new_property_notify);
    -    REGISTER(COMPLETE_MODEL_PCALL, PL::Naming::naming_complete_model);
    +    PluginManager::plug(NEW_PROPERTY_NOTIFY_PLUG, PL::Naming::naming_new_property_notify);
    +    PluginManager::plug(COMPLETE_MODEL_PLUG, PL::Naming::naming_complete_model);
     }
     

    §4. Recognising significant properties. These are property names to do with naming which Inform provides special @@ -223,7 +223,7 @@ we do here is provide its state on request.

    -int PL::Naming::object_is_privately_named(instance *I) {
    +int PL::Naming::object_is_privately_named(instance *I) {
         int certainty = PropertyInferences::either_or_state(Instances::as_subject(I), P_privately_named);
         if (certainty > 0) return TRUE;
         if (certainty < 0) return FALSE;
    diff --git a/docs/if-module/3-tp.html b/docs/if-module/3-tp.html
    index 1fabdceae..b225555f3 100644
    --- a/docs/if-module/3-tp.html
    +++ b/docs/if-module/3-tp.html
    @@ -102,14 +102,14 @@ to this plugin, but the idea is to position the player in both space and time.
     
     
     void PL::Player::start(void) {
    -    REGISTER(NEW_VARIABLE_NOTIFY_PCALL, PL::Player::player_new_quantity_notify);
    -    REGISTER(VARIABLE_SET_WARNING_PCALL, PL::Player::player_variable_set_warning);
    -    REGISTER(NEW_INSTANCE_NOTIFY_PCALL, PL::Player::player_new_instance_notify);
    -    REGISTER(IRREGULAR_GENITIVE_PCALL, PL::Player::player_irregular_genitive);
    -    REGISTER(COMPLETE_MODEL_PCALL, PL::Player::player_complete_model);
    -    REGISTER(REFINE_IMPLICIT_NOUN_PCALL, PL::Player::player_refine_implicit_noun);
    -    REGISTER(DETECT_BODYSNATCHING_PCALL, PL::Player::player_detect_bodysnatching);
    -    REGISTER(ANNOTATE_IN_WORLD_INDEX_PCALL, PL::Player::player_annotate_in_World_index);
    +    PluginManager::plug(NEW_VARIABLE_NOTIFY_PLUG, PL::Player::player_new_quantity_notify);
    +    PluginManager::plug(VARIABLE_VALUE_NOTIFY_PLUG, PL::Player::player_variable_set_warning);
    +    PluginManager::plug(NEW_INSTANCE_NOTIFY_PLUG, PL::Player::player_new_instance_notify);
    +    PluginManager::plug(IRREGULAR_GENITIVE_IN_ASSEMBLY_PLUG, PL::Player::player_irregular_genitive);
    +    PluginManager::plug(COMPLETE_MODEL_PLUG, PL::Player::player_complete_model);
    +    PluginManager::plug(REFINE_IMPLICIT_NOUN_PLUG, PL::Player::player_refine_implicit_noun);
    +    PluginManager::plug(DETECT_BODYSNATCHING_PLUG, PL::Player::player_detect_bodysnatching);
    +    PluginManager::plug(ANNOTATE_IN_WORLD_INDEX_PLUG, PL::Player::player_annotate_in_World_index);
     }
     

    §4. Special objects. The "yourself" object is special in being tied, or "aliased", to the diff --git a/docs/if-module/4-act.html b/docs/if-module/4-act.html index ba6fb6ceb..15caa4cef 100644 --- a/docs/if-module/4-act.html +++ b/docs/if-module/4-act.html @@ -73,7 +73,7 @@ function togglePopup(material_id) {

    To define, map to I6 and index individual actions.

    -
    +

    §1. An action is an impulse to do something within the model world, and which may not be possible. Much of the work of designing an interactive fiction @@ -181,12 +181,11 @@ tried later. This is a pointer value; see "StoredAction.i6t".

     void PL::Actions::start(void) {
    -    REGISTER(NEW_BASE_KIND_NOTIFY_PCALL, PL::Actions::actions_new_base_kind_notify);
    -    REGISTER(COMPILE_CONSTANT_PCALL, PL::Actions::actions_compile_constant);
    -    REGISTER(OFFERED_PROPERTY_PCALL, PL::Actions::actions_offered_property);
    -    REGISTER(OFFERED_SPECIFICATION_PCALL, PL::Actions::actions_offered_specification);
    -    REGISTER(TYPECHECK_EQUALITY_PCALL, PL::Actions::actions_typecheck_equality);
    -    REGISTER(FORBID_SETTING_PCALL, PL::Actions::actions_forbid_setting);
    +    PluginManager::plug(NEW_BASE_KIND_NOTIFY_PLUG, PL::Actions::actions_new_base_kind_notify);
    +    PluginManager::plug(COMPILE_CONSTANT_PLUG, PL::Actions::actions_compile_constant);
    +    PluginManager::plug(OFFERED_PROPERTY_PLUG, PL::Actions::actions_offered_property);
    +    PluginManager::plug(OFFERED_SPECIFICATION_PLUG, PL::Actions::actions_offered_specification);
    +    PluginManager::plug(TYPECHECK_EQUALITY_PLUG, PL::Actions::actions_typecheck_equality);
     
         Vocabulary::set_flags(Vocabulary::entry_for_text(L"doing"), ACTION_PARTICIPLE_MC);
         Vocabulary::set_flags(Vocabulary::entry_for_text(L"asking"), ACTION_PARTICIPLE_MC);
    @@ -217,7 +216,7 @@ tried later. This is a pointer value; see "StoredAction.i6t".
         if (Kinds::eq(K, K_action_name)) {
             action_name *an = Rvalues::to_action_name(spec);
             if (Holsters::data_acceptable(VH)) {
    -            inter_name *N = PL::Actions::iname(an);
    +            inter_name *N = PL::Actions::iname(an);
                 if (N) Emit::holster(VH, N);
             }
             return TRUE;
    @@ -243,7 +242,7 @@ tried later. This is a pointer value; see "StoredAction.i6t".
         if (Kinds::eq(K, K_action_name)) {
             action_name *an = Rvalues::to_action_name(owner);
             if (an == NULL) internal_error("failed to extract action-name structure");
    -        if (global_pass_state.pass == 1) PL::Actions::an_add_variable(an, what);
    +        if (global_pass_state.pass == 1) PL::Actions::an_add_variable(an, what);
             return TRUE;
         }
         return FALSE;
    @@ -251,7 +250,8 @@ tried later. This is a pointer value; see "StoredAction.i6t".
     
     int PL::Actions::actions_offered_specification(parse_node *owner, wording W) {
         if (Rvalues::is_CONSTANT_of_kind(owner, K_action_name)) {
    -        PL::Actions::actions_set_specification_text(Rvalues::to_action_name(owner), Wordings::first_wn(W));
    +        PL::Actions::actions_set_specification_text(
    +            Rvalues::to_action_name(owner), Wordings::first_wn(W));
             return TRUE;
         }
         return FALSE;
    @@ -272,26 +272,14 @@ tried later. This is a pointer value; see "StoredAction.i6t".
         return FALSE;
     }
     
    -

    §11. It could be argued that this ought to be a typechecking rule, but it applies -only to setting true, so is here instead. The distinction is there because we -can check whether an action is "taking a container" (say) but can't set a -stored action equal to it, because it's too vague: what is the container to be -taken? -

    - -
    -int PL::Actions::actions_forbid_setting(kind *K) {
    -    return FALSE;
    -}
    -
    -

    §12. The constructor function for action names divides them into two according +

    §11. The constructor function for action names divides them into two according to their implementation. Some actions are fully implemented in I6, and do not have the standard check/carry out/report rulebooks: others are full I7 actions. (As I7 has matured, more and more actions have moved from the first category to the second.)

    -

    §13. This is an action name which Inform provides special support for; it +

    §12. This is an action name which Inform provides special support for; it recognises the English name when defined by the Standard Rules. (So there is no need to translate this to other languages.)

    @@ -302,7 +290,7 @@ need to translate this to other languages.) going
    -

    §14. When we want to refer to an action name as a noun, we can use this to +

    §13. When we want to refer to an action name as a noun, we can use this to make that explicit: for instance, "taking" becomes "the taking action".

    @@ -311,10 +299,10 @@ make that explicit: for instance, "taking" becomes "the taking action". ... action
    -

    §15.

    +

    §14.

    -action_name *PL::Actions::act_new(wording W, int implemented_by_I7) {
    +action_name *PL::Actions::act_new(wording W, int implemented_by_I7) {
         int make_ds = FALSE;
         action_name *an = CREATE(action_name);
         if (<notable-actions>(W)) {
    @@ -403,7 +391,7 @@ make that explicit: for instance, "taking" becomes "the taking action".
         action_name *an2;
         LOOP_OVER(an2, action_name)
             if (an != an2)
    -            if (PL::Actions::action_names_overlap(an, an2)) {
    +            if (PL::Actions::action_names_overlap(an, an2)) {
                     an->it_optional = FALSE;
                     an2->it_optional = FALSE;
                 }
    @@ -413,7 +401,7 @@ make that explicit: for instance, "taking" becomes "the taking action".
     
      pointing at, pointing it at
     
    -

    §16. The "action pronoun" use of "it" is to be a placeholder in an action +

    §15. The "action pronoun" use of "it" is to be a placeholder in an action name to indicate where a noun phrase should appear. Some actions apply to only one noun: for instance, in

    @@ -440,10 +428,10 @@ will do: it doesn't have to be "it".) <object-pronoun>
    -

    §17.

    +

    §16.

    -int PL::Actions::action_names_overlap(action_name *an1, action_name *an2) {
    +int PL::Actions::action_names_overlap(action_name *an1, action_name *an2) {
         wording W = an1->present_name;
         wording XW = an2->present_name;
         for (int i = Wordings::first_wn(W), j = Wordings::first_wn(XW);
    @@ -456,12 +444,12 @@ will do: it doesn't have to be "it".)
         return FALSE;
     }
     
    -void PL::Actions::log(action_name *an) {
    +void PL::Actions::log(action_name *an) {
         if (an == NULL) LOG("<null-action-name>");
         else LOG("%W", an->present_name);
     }
     
    -

    §18. And the following matches an action name (with no substitution of noun +

    §17. And the following matches an action name (with no substitution of noun phrases: "unlocking the door with" won't match the unlocking action; only "unlocking it with" will do that).

    @@ -486,7 +474,7 @@ phrases: "unlocking the door with" won't match the unlocking action; only }
    -

    §19. However, <action-name> can also be made to match an action name without +

    §18. However, <action-name> can also be made to match an action name without a final preposition, if that preposition is on the following list. For example, it allows "listening" to match the listening to action; this is needed because of the almost unique status of "listening" in having an @@ -500,10 +488,10 @@ then that's what "listening" will match.) ... to

    -

    §20.

    +

    §19.

    -action_name *PL::Actions::longest_null(wording W, int tense, int *excess) {
    +action_name *PL::Actions::longest_null(wording W, int tense, int *excess) {
         action_name *an;
         LOOP_OVER(an, action_name)
             if (an->max_parameters == 0) {
    @@ -516,16 +504,16 @@ then that's what "listening" will match.)
         return NULL;
     }
     
    -int PL::Actions::it_optional(action_name *an) {
    +int PL::Actions::it_optional(action_name *an) {
         return an->it_optional;
     }
     
    -int PL::Actions::abbreviable(action_name *an) {
    +int PL::Actions::abbreviable(action_name *an) {
         return an->abbreviable;
     }
     
    -text_stream *PL::Actions::identifier(action_name *an) {
    -    return Emit::to_text(PL::Actions::base_iname(an));
    +text_stream *PL::Actions::identifier(action_name *an) {
    +    return Emit::to_text(PL::Actions::base_iname(an));
     }
     
     action_name *PL::Actions::Wait(void) {
    @@ -533,7 +521,7 @@ then that's what "listening" will match.)
         return waiting_action;
     }
     
    -inter_name *PL::Actions::base_iname(action_name *an) {
    +inter_name *PL::Actions::base_iname(action_name *an) {
         if (an->an_base_iname == NULL) {
             if (waiting_action == an)
                 an->an_base_iname = Hierarchy::make_iname_in(WAIT_HL, an->an_package);
    @@ -545,9 +533,9 @@ then that's what "listening" will match.)
         return an->an_base_iname;
     }
     
    -inter_name *PL::Actions::double_sharp(action_name *an) {
    +inter_name *PL::Actions::double_sharp(action_name *an) {
         if (an->an_iname == NULL) {
    -        an->an_iname = Hierarchy::derive_iname_in(DOUBLE_SHARP_NAME_HL, PL::Actions::base_iname(an), an->an_package);
    +        an->an_iname = Hierarchy::derive_iname_in(DOUBLE_SHARP_NAME_HL, PL::Actions::base_iname(an), an->an_package);
             Emit::ds_named_pseudo_numeric_constant(an->an_iname, K_value, (inter_ti) an->allocation_id);
             Hierarchy::make_available(Emit::tree(), an->an_iname);
             Produce::annotate_i(an->an_iname, ACTION_IANN, 1);
    @@ -555,16 +543,16 @@ then that's what "listening" will match.)
         return an->an_iname;
     }
     
    -inter_name *PL::Actions::Sub(action_name *an) {
    +inter_name *PL::Actions::Sub(action_name *an) {
         if (an->an_routine_iname == NULL) {
    -        an->an_routine_iname = Hierarchy::derive_iname_in(PERFORM_FN_HL, PL::Actions::base_iname(an), an->an_package);
    +        an->an_routine_iname = Hierarchy::derive_iname_in(PERFORM_FN_HL, PL::Actions::base_iname(an), an->an_package);
             Hierarchy::make_available(Emit::tree(), an->an_routine_iname);
         }
         return an->an_routine_iname;
     }
     
    -inter_name *PL::Actions::iname(action_name *an) {
    -    return PL::Actions::double_sharp(an);
    +inter_name *PL::Actions::iname(action_name *an) {
    +    return PL::Actions::double_sharp(an);
     }
     
     rulebook *PL::Actions::get_fragmented_rulebook(action_name *an, rulebook *rb) {
    @@ -585,14 +573,14 @@ then that's what "listening" will match.)
         return orig;
     }
     
    -void PL::Actions::actions_set_specification_text(action_name *an, int wn) {
    +void PL::Actions::actions_set_specification_text(action_name *an, int wn) {
         an->an_specification_text_word = wn;
     }
    -int PL::Actions::an_get_specification_text(action_name *an) {
    +int PL::Actions::an_get_specification_text(action_name *an) {
         return an->an_specification_text_word;
     }
     
    -

    §21. Most actions are given automatically generated Inform 6 names in the +

    §20. Most actions are given automatically generated Inform 6 names in the compiled code: Q4_green, for instance. A few must however correspond to names of significance in the I6 library.

    @@ -612,7 +600,7 @@ names of significance in the I6 library. return; } if (an->translated) { - LOG("Tried action name %W = %n\n", W, PL::Actions::base_iname(an)); + LOG("Tried action name %W = %n\n", W, PL::Actions::base_iname(an)); StandardProblems::sentence_problem(Task::syntax_tree(), _p_(PM_TranslatesActionAlready), "this action has already been translated", "so there must be some duplication somewhere."); @@ -623,10 +611,10 @@ names of significance in the I6 library. an->translated = TRUE; an->translated_name = Str::new(); WRITE_TO(an->translated_name, "%N", Wordings::first_wn(Node::get_text(p2))); - LOGIF(ACTION_CREATIONS, "Translated action: $l as %n\n", an, PL::Actions::base_iname(an)); + LOGIF(ACTION_CREATIONS, "Translated action: $l as %n\n", an, PL::Actions::base_iname(an)); } -int PL::Actions::get_stem_length(action_name *an) { +int PL::Actions::get_stem_length(action_name *an) { if (Wordings::empty(an->present_name)) return 0; should never happen int s = 0; LOOP_THROUGH_WORDING(k, an->present_name) @@ -635,7 +623,7 @@ names of significance in the I6 library. return s; }
    -

    §22. Action variables. Action variables can optionally be marked as able to extend the grammar of +

    §21. Action variables. Action variables can optionally be marked as able to extend the grammar of action patterns. For example, the Standard Rules define:

    @@ -649,20 +637,20 @@ action patterns. For example, the Standard Rules define:
     <action-variable> ::=
         <action-variable-name> ( matched as {<quoted-text-without-subs>} ) |    ==> { TRUE, - }
    -    <action-variable-name> ( ... ) |    ==> Issue PM_BadMatchingSyntax problem22.2
    +    <action-variable-name> ( ... ) |    ==> Issue PM_BadMatchingSyntax problem21.2
         <action-variable-name>                                  ==> { FALSE, - }
     
    -

    §22.1. And the new action variable name is vetted by being run through this: +

    §21.1. And the new action variable name is vetted by being run through this:

     <action-variable-name> ::=
    -    <unfortunate-name> |    ==> Issue PM_ActionVarAnd problem22.1.1
    +    <unfortunate-name> |    ==> Issue PM_ActionVarAnd problem21.1.1
         ...                                                     ==> { TRUE, - }
     
    -

    §22.2. Issue PM_BadMatchingSyntax problem22.2 = +

    §21.2. Issue PM_BadMatchingSyntax problem21.2 =

    @@ -678,8 +666,8 @@ action patterns. For example, the Standard Rules define:
         Problems::issue_problem_end();
         ==> { NOT_APPLICABLE, - };
     
    -
    • This code is used in §22.
    -

    §22.1.1. Issue PM_ActionVarAnd problem22.1.1 = +

    • This code is used in §21.
    +

    §21.1.1. Issue PM_ActionVarAnd problem21.1.1 =

    @@ -694,11 +682,11 @@ action patterns. For example, the Standard Rules define:
             "avoid 'and', 'or', 'with', or 'having' in such names, please.");
         Problems::issue_problem_end();
     
    - -

    §23.

    + +

    §22.

    -void PL::Actions::an_add_variable(action_name *an, parse_node *cnode) {
    +void PL::Actions::an_add_variable(action_name *an, parse_node *cnode) {
         wording MW = EMPTY_WORDING, NW = EMPTY_WORDING;
         stacked_variable *stv = NULL;
     
    @@ -819,11 +807,11 @@ action patterns. For example, the Standard Rules define:
         }
     }
     
    -stacked_variable *PL::Actions::parse_match_clause(action_name *an, wording W) {
    +stacked_variable *PL::Actions::parse_match_clause(action_name *an, wording W) {
         return StackedVariables::parse_match_clause(an->owned_by_an, W);
     }
     
    -void PL::Actions::compile_action_name_var_creators(void) {
    +void PL::Actions::compile_action_name_var_creators(void) {
         action_name *an;
         LOOP_OVER(an, action_name) {
             if ((an->owned_by_an) &&
    @@ -834,7 +822,7 @@ action patterns. For example, the Standard Rules define:
         }
     }
     
    -

    §24. This handles the special meaning "X is an action...". +

    §23. This handles the special meaning "X is an action...". <nounphrase-actionable> is an awkward necessity, designed to prevent the regular sentence

    @@ -854,7 +842,7 @@ new action. <new-action-sentence-object-unarticled> ::= action <nounphrase-actionable> | ==> { TRUE, RP[1] } - action ==> Issue PM_BadActionDeclaration problem24.1 + action ==> Issue PM_BadActionDeclaration problem23.1 <nounphrase-actionable> ::= ^<variable-creation-tail> ==> { 0, Diagrams::new_UNPARSED_NOUN(W) } @@ -864,7 +852,7 @@ new action. *** variable
    -

    §24.1. Issue PM_BadActionDeclaration problem24.1 = +

    §23.1. Issue PM_BadActionDeclaration problem23.1 =

    @@ -874,11 +862,11 @@ new action.
             "is an action applying to one thing.'");
         ==> { FALSE, NULL };
     
    -
    • This code is used in §24.
    -

    §25.

    +
    • This code is used in §23.
    +

    §24.

    -int PL::Actions::new_action_SMF(int task, parse_node *V, wording *NPs) {
    +int PL::Actions::new_action_SMF(int task, parse_node *V, wording *NPs) {
         wording SW = (NPs)?(NPs[0]):EMPTY_WORDING;
         wording OW = (NPs)?(NPs[1]):EMPTY_WORDING;
         switch (task) {  "Taking something is an action."
    @@ -893,13 +881,13 @@ new action.
                 }
                 break;
             case PASS_1_SMFT:
    -            PL::Actions::act_parse_definition(V);
    +            PL::Actions::act_parse_definition(V);
                 break;
         }
         return FALSE;
     }
     
    -

    §26.

    +

    §25.

    define OOW_ACT_CLAUSE 1
     define PP_ACT_CLAUSE 2
    @@ -910,7 +898,7 @@ new action.
     
     action_name *an_being_parsed = NULL;
     
    -

    §27. We now come to a quite difficult sentence to parse: the declaration of a +

    §26. We now come to a quite difficult sentence to parse: the declaration of a new action.

    @@ -928,11 +916,11 @@ action to be created.
     <action-sentence-subject> ::=
    -    <action-name> |  ==> Issue PM_ActionAlreadyExists problem27.1
    +    <action-name> |  ==> Issue PM_ActionAlreadyExists problem26.1
         ...              ==> { 0, PL::Actions::act_new(W, TRUE) }
     
    -

    §27.1. Issue PM_ActionAlreadyExists problem27.1 = +

    §26.1. Issue PM_ActionAlreadyExists problem26.1 =

    @@ -946,8 +934,8 @@ action to be created.
             "('Understand \"unlock [something]\" as keyless unlocking.').");
         ==> { -, K_object };
     
    -
    • This code is used in §27.
    -

    §28. The object NP is trickier, because it is a sequence +

    • This code is used in §26.
    +

    §27. The object NP is trickier, because it is a sequence of "action clauses" which can occur in any order, which are allowed but not required to be delimited as a list, and which can inconveniently contain the word "and"; not only that, but note that in @@ -979,10 +967,10 @@ It's convenient to define a single action clause first: one <act-req> | ==> { 1, -, <<kind:op1>> = RP[1], <<ac1>> = R[1] } two <act-req> | ==> { 2, -, <<kind:op1>> = RP[1], <<ac1>> = R[1], <<kind:op2>> = RP[1], <<ac2>> = R[1] } <act-req> | ==> { 1, -, <<kind:op1>> = RP[1], <<ac1>> = R[1] } - ... ==> Issue PM_ActionMisapplied problem28.2; + ... ==> Issue PM_ActionMisapplied problem27.2; <act-req> ::= - <act-req-inner> ==> Check action kind28.1; + <act-req-inner> ==> Check action kind27.1; <act-req-inner> ::= <action-access> <k-kind> | ==> { R[1], RP[2] } @@ -994,13 +982,13 @@ It's convenient to define a single action clause first: carried ==> { REQUIRES_POSSESSION, - }

    -

    §29. We are now able to define this peculiar form of list of action clauses: +

    §28. We are now able to define this peculiar form of list of action clauses:

     <action-sentence-object> ::=
         <action-clauses> |                   ==> { 0, - }
    -    ...                                  ==> Issue PM_ActionClauseUnknown problem29.1
    +    ...                                  ==> Issue PM_ActionClauseUnknown problem28.1
     
     <action-clauses> ::=
         ... |                                         ==> { lookahead }
    @@ -1014,7 +1002,7 @@ It's convenient to define a single action clause first:
         <action-clause>                      ==> { pass 1 }
     
    -

    §29.1. Issue PM_ActionClauseUnknown problem29.1 = +

    §28.1. Issue PM_ActionClauseUnknown problem28.1 =

    @@ -1022,8 +1010,8 @@ It's convenient to define a single action clause first:
             "the action definition contained text I couldn't follow",
             "and may be too complicated.");
     
    -
    • This code is used in §29.
    -

    §28.1. Check action kind28.1 = +

    • This code is used in §28.
    +

    §27.1. Check action kind27.1 =

    @@ -1032,15 +1020,15 @@ It's convenient to define a single action clause first:
             if (A == UNRESTRICTED_ACCESS) A = REQUIRES_ACCESS;
             ==> { A, K_object };
         } else if (Kinds::Behaviour::is_subkind_of_object(K)) {
    -        Issue PM_ActionMisapplied problem28.2;
    +        Issue PM_ActionMisapplied problem27.2;
         } else if (A != UNRESTRICTED_ACCESS) {
    -        Issue PM_ActionMisapplied problem28.2;
    +        Issue PM_ActionMisapplied problem27.2;
         } else {
             ==> { A, K };
         }
     
    -
    • This code is used in §28.
    -

    §28.2. Issue PM_ActionMisapplied problem28.2 = +

    • This code is used in §27.
    +

    §27.2. Issue PM_ActionMisapplied problem27.2 =

    @@ -1050,11 +1038,11 @@ It's convenient to define a single action clause first:
             "one visible thing'.");
         ==> { REQUIRES_ACCESS, K_thing };
     
    - -

    §30.

    + +

    §29.

    -void PL::Actions::act_on_clause(int N) {
    +void PL::Actions::act_on_clause(int N) {
         switch (N) {
             case OOW_ACT_CLAUSE:
                 an_being_parsed->out_of_world = TRUE; break;
    @@ -1069,7 +1057,7 @@ It's convenient to define a single action clause first:
                         "should have past participle given just as 'hung'; I "
                         "can already deduce the rest.)");
                 an_being_parsed->past_name =
    -                PL::Actions::set_past_participle(an_being_parsed->past_name,
    +                PL::Actions::set_past_participle(an_being_parsed->past_name,
                         Wordings::last_wn(C));
                 break;
             }
    @@ -1092,10 +1080,10 @@ It's convenient to define a single action clause first:
         }
     }
     
    -

    §31.

    +

    §30.

    -wording PL::Actions::set_past_participle(wording W, int irregular_pp) {
    +wording PL::Actions::set_past_participle(wording W, int irregular_pp) {
         feed_t id = Feeds::begin();
         Feeds::feed_wording(Wordings::one_word(irregular_pp));
         if (Wordings::length(W) > 1)
    @@ -1103,10 +1091,10 @@ It's convenient to define a single action clause first:
         return Feeds::end(id);
     }
     
    -

    §32.

    +

    §31.

    -void PL::Actions::act_parse_definition(parse_node *p) {
    +void PL::Actions::act_parse_definition(parse_node *p) {
         <action-sentence-subject>(Node::get_text(p->next));
         action_name *an = <<rp>>;
         if (an == NULL) return;
    @@ -1138,38 +1126,38 @@ It's convenient to define a single action clause first:
         }
     }
     
    -int PL::Actions::is_out_of_world(action_name *an) {
    +int PL::Actions::is_out_of_world(action_name *an) {
         if (an->out_of_world) return TRUE;
         return FALSE;
     }
     
    -kind *PL::Actions::get_data_type_of_noun(action_name *an) {
    +kind *PL::Actions::get_data_type_of_noun(action_name *an) {
         return an->noun_kind;
     }
     
    -kind *PL::Actions::get_data_type_of_second_noun(action_name *an) {
    +kind *PL::Actions::get_data_type_of_second_noun(action_name *an) {
         return an->second_kind;
     }
     
    -wording PL::Actions::set_text_to_name_tensed(action_name *an, int tense) {
    +wording PL::Actions::set_text_to_name_tensed(action_name *an, int tense) {
         if (tense == HASBEEN_TENSE) return an->past_name;
         return an->present_name;
     }
     
    -int PL::Actions::can_have_parameters(action_name *an) {
    +int PL::Actions::can_have_parameters(action_name *an) {
         if (an->max_parameters > 0) return TRUE;
         return FALSE;
     }
     
    -int PL::Actions::get_max_parameters(action_name *an) {
    +int PL::Actions::get_max_parameters(action_name *an) {
         return an->max_parameters;
     }
     
    -int PL::Actions::get_min_parameters(action_name *an) {
    +int PL::Actions::get_min_parameters(action_name *an) {
         return an->min_parameters;
     }
     
    -

    §33. Past tense. Simpler actions — those with no parameter, or a single parameter which is +

    §32. Past tense. Simpler actions — those with no parameter, or a single parameter which is a thing — can be tested in the past tense. The run-time support for this is a general bitmap revealing which actions have ever happened, plus a bitmap for each object revealing which have ever been applied to the object @@ -1177,7 +1165,7 @@ in question. This is where we compile the bitmaps in their fresh, empty form.

    -int PL::Actions::can_be_compiled_in_past_tense(action_name *an) {
    +int PL::Actions::can_be_compiled_in_past_tense(action_name *an) {
         if (an->min_parameters > 1) return FALSE;
         if (an->max_parameters > 1) return FALSE;
         if ((an->max_parameters == 1) &&
    @@ -1186,7 +1174,7 @@ in question. This is where we compile the bitmaps in their fresh, empty form.
         return TRUE;
     }
     
    -inter_name *PL::Actions::compile_action_bitmap_property(instance *I) {
    +inter_name *PL::Actions::compile_action_bitmap_property(instance *I) {
         package_request *R = NULL;
         inter_name *N = NULL;
         if (I) {
    @@ -1214,22 +1202,22 @@ in question. This is where we compile the bitmaps in their fresh, empty form.
         Hierarchy::make_available(Emit::tree(), iname);
     }
     
    -

    §34. The grammar list.

    +

    §33. The grammar list.

    -void PL::Actions::add_gl(action_name *an, grammar_line *gl) {
    +void PL::Actions::add_gl(action_name *an, grammar_line *gl) {
         if (an->list_with_action == NULL) an->list_with_action = gl;
         else PL::Parsing::Lines::list_with_action_add(an->list_with_action, gl);
     }
     
    -void PL::Actions::remove_gl(action_name *an) {
    +void PL::Actions::remove_gl(action_name *an) {
         an->list_with_action = NULL;
     }
     
    -

    §35. Typechecking grammar for an action.

    +

    §34. Typechecking grammar for an action.

    -void PL::Actions::check_types_for_grammar(action_name *an, int tok_values,
    +void PL::Actions::check_types_for_grammar(action_name *an, int tok_values,
         kind **tok_value_kinds) {
         int required = 0; char *failed_on = "<internal error>";
     
    @@ -1335,7 +1323,7 @@ in question. This is where we compile the bitmaps in their fresh, empty form.
             Problems::issue_problem_end();
     }
     
    -

    §36. Compiling data about actions. In I6, there was no common infrastructure for the implementation of +

    §35. Compiling data about actions. In I6, there was no common infrastructure for the implementation of actions: each defined its own -Sub routine. Here, we do have a common infrastructure, and we access it with a single call.

    @@ -1345,7 +1333,7 @@ infrastructure, and we access it with a single call. action_name *an; LOOP_OVER(an, action_name) { if (an->use_verb_routine_in_I6_library) continue; - inter_name *iname = PL::Actions::Sub(an); + inter_name *iname = PL::Actions::Sub(an); packaging_state save = Routines::begin(iname); Produce::inv_primitive(Emit::tree(), RETURN_BIP); Produce::down(Emit::tree()); @@ -1361,12 +1349,12 @@ infrastructure, and we access it with a single call. } }
    -

    §37. Compiling data about actions. There are also collective tables of data about actions. +

    §36. Compiling data about actions. There are also collective tables of data about actions.

     void PL::Actions::ActionData(void) {
    -    PL::Actions::compile_action_name_var_creators();
    +    PL::Actions::compile_action_name_var_creators();
         action_name *an;
         int mn, ms, ml, mnp, msp, hn, hs, record_count = 0;
     
    @@ -1418,7 +1406,7 @@ infrastructure, and we access it with a single call.
             if (an->use_verb_routine_in_I6_library) continue;
                 Produce::inv_primitive(Emit::tree(), CASE_BIP);
                 Produce::down(Emit::tree());
    -                Produce::val_iname(Emit::tree(), K_value, PL::Actions::double_sharp(an));
    +                Produce::val_iname(Emit::tree(), K_value, PL::Actions::double_sharp(an));
                     Produce::code(Emit::tree());
                     Produce::down(Emit::tree());
     
    @@ -1426,10 +1414,10 @@ infrastructure, and we access it with a single call.
                     while (j <= Wordings::last_wn(an->present_name)) {
                         if (<action-pronoun>(Wordings::one_word(j))) {
                             if (j0 >= 0) {
    -                            Insert a space here if needed to break up the action name37.1;
    +                            Insert a space here if needed to break up the action name36.1;
     
                                 TEMPORARY_TEXT(AT)
    -                            PL::Actions::print_action_text_to(Wordings::new(j0, j-1), Wordings::first_wn(an->present_name), AT);
    +                            PL::Actions::print_action_text_to(Wordings::new(j0, j-1), Wordings::first_wn(an->present_name), AT);
                                 Produce::inv_primitive(Emit::tree(), PRINT_BIP);
                                 Produce::down(Emit::tree());
                                     Produce::val_text(Emit::tree(), AT);
    @@ -1438,7 +1426,7 @@ infrastructure, and we access it with a single call.
     
                                 j0 = -1;
                             }
    -                        Insert a space here if needed to break up the action name37.1;
    +                        Insert a space here if needed to break up the action name36.1;
                             Produce::inv_primitive(Emit::tree(), IFELSE_BIP);
                             Produce::down(Emit::tree());
                                 Produce::inv_primitive(Emit::tree(), EQ_BIP);
    @@ -1455,7 +1443,7 @@ infrastructure, and we access it with a single call.
                                 Produce::up(Emit::tree());
                                 Produce::code(Emit::tree());
                                 Produce::down(Emit::tree());
    -                                PL::Actions::cat_something2(an, somethings++, n_s, s_s);
    +                                PL::Actions::cat_something2(an, somethings++, n_s, s_s);
                                 Produce::up(Emit::tree());
                             Produce::up(Emit::tree());
                         } else {
    @@ -1464,9 +1452,9 @@ infrastructure, and we access it with a single call.
                         j++;
                     }
                     if (j0 >= 0) {
    -                    Insert a space here if needed to break up the action name37.1;
    +                    Insert a space here if needed to break up the action name36.1;
                         TEMPORARY_TEXT(AT)
    -                    PL::Actions::print_action_text_to(Wordings::new(j0, j-1), Wordings::first_wn(an->present_name), AT);
    +                    PL::Actions::print_action_text_to(Wordings::new(j0, j-1), Wordings::first_wn(an->present_name), AT);
                         Produce::inv_primitive(Emit::tree(), PRINT_BIP);
                         Produce::down(Emit::tree());
                             Produce::val_text(Emit::tree(), AT);
    @@ -1483,8 +1471,8 @@ infrastructure, and we access it with a single call.
                             Produce::up(Emit::tree());
                             Produce::code(Emit::tree());
                             Produce::down(Emit::tree());
    -                            Insert a space here if needed to break up the action name37.1;
    -                            PL::Actions::cat_something2(an, somethings++, n_s, s_s);
    +                            Insert a space here if needed to break up the action name36.1;
    +                            PL::Actions::cat_something2(an, somethings++, n_s, s_s);
                             Produce::up(Emit::tree());
                         Produce::up(Emit::tree());
                     }
    @@ -1499,7 +1487,7 @@ infrastructure, and we access it with a single call.
         Hierarchy::make_available(Emit::tree(), DB_Action_Details_iname);
     }
     
    -

    §37.1. Insert a space here if needed to break up the action name37.1 = +

    §36.1. Insert a space here if needed to break up the action name36.1 =

    @@ -1510,11 +1498,11 @@ infrastructure, and we access it with a single call.
             Produce::up(Emit::tree());
         }
     
    -
    • This code is used in §37 (four times).
    -

    §38.

    +
    • This code is used in §36 (four times).
    +

    §37.

    -void PL::Actions::cat_something2(action_name *an, int n, inter_symbol *n_s, inter_symbol *s_s) {
    +void PL::Actions::cat_something2(action_name *an, int n, inter_symbol *n_s, inter_symbol *s_s) {
         kind *K = an->noun_kind;
         inter_symbol *var = n_s;
         if (n > 0) {
    @@ -1541,7 +1529,7 @@ infrastructure, and we access it with a single call.
         Produce::up(Emit::tree());
     }
     
    -void PL::Actions::print_action_text_to(wording W, int start, OUTPUT_STREAM) {
    +void PL::Actions::print_action_text_to(wording W, int start, OUTPUT_STREAM) {
         if (Wordings::first_wn(W) == start) {
             WRITE("%W", Wordings::first_word(W));
             W = Wordings::trim_first_word(W);
    @@ -1556,17 +1544,17 @@ infrastructure, and we access it with a single call.
         packaging_state save = Emit::named_array_begin(iname, K_value);
         action_name *an;
         LOOP_OVER(an, action_name) {
    -        if (Str::get_first_char(PL::Actions::identifier(an)) == '_') Emit::array_numeric_entry(0);
    +        if (Str::get_first_char(PL::Actions::identifier(an)) == '_') Emit::array_numeric_entry(0);
             else Emit::array_action_entry(an);
         }
         Emit::array_end(save);
         Hierarchy::make_available(Emit::tree(), iname);
     }
     
    -

    §39. Indexing.

    +

    §38. Indexing.

    -int PL::Actions::index(OUTPUT_STREAM, action_name *an, int pass,
    +int PL::Actions::index(OUTPUT_STREAM, action_name *an, int pass,
         inform_extension **ext, heading **current_area, int f, int *new_par, int bold,
         int on_details_page) {
         if (an->use_verb_routine_in_I6_library) return f;
    @@ -1638,21 +1626,21 @@ infrastructure, and we access it with a single call.
             int somethings = 0;
             while (j <= Wordings::last_wn(an->present_name)) {
                 if (<action-pronoun>(Wordings::one_word(j))) {
    -                PL::Actions::act_index_something(OUT, an, somethings++);
    +                PL::Actions::act_index_something(OUT, an, somethings++);
                 } else {
                     WRITE("%+W ", Wordings::one_word(j));
                 }
                 j++;
             }
             if (somethings < an->max_parameters)
    -            PL::Actions::act_index_something(OUT, an, somethings++);
    +            PL::Actions::act_index_something(OUT, an, somethings++);
         }
         if (an->out_of_world) HTML::end_colour(OUT);
         if (pass == 2) {
    -        int swn = PL::Actions::an_get_specification_text(an);
    +        int swn = PL::Actions::an_get_specification_text(an);
             WRITE("</b>");
             Index::link(OUT, Wordings::first_wn(Node::get_text(an->designers_specification)));
    -        Index::anchor(OUT, PL::Actions::identifier(an));
    +        Index::anchor(OUT, PL::Actions::identifier(an));
             if (an->requires_light) WRITE(" (requires light)");
             WRITE(" (<i>past tense</i> %+W)", an->past_name);
             HTML_CLOSE("p");
    diff --git a/docs/if-module/4-ai.html b/docs/if-module/4-ai.html
    index a067c99a9..f85f551f2 100644
    --- a/docs/if-module/4-ai.html
    +++ b/docs/if-module/4-ai.html
    @@ -308,7 +308,7 @@ we divide these headwords into five "natures":
         inform_extension *ext = NULL;
         LOOP_OVER(an, action_name) {
             int new_par = FALSE;
    -        f = PL::Actions::index(OUT, an, 1, &ext, &current_area, f, &new_par, FALSE, FALSE);
    +        f = PL::Actions::index(OUT, an, 1, &ext, &current_area, f, &new_par, FALSE, FALSE);
             if (new_par) par_count++;
             an->an_index_group = par_count;
         }
    @@ -330,11 +330,11 @@ we divide these headwords into five "natures":
             ext = NULL;
             LOOP_OVER(an2, action_name) {
                 if (an2->an_index_group == an->an_index_group)
    -                f = PL::Actions::index(OUT, an2, 1, &ext, &current_area, f, &new_par, (an2 == an)?TRUE:FALSE, TRUE);
    +                f = PL::Actions::index(OUT, an2, 1, &ext, &current_area, f, &new_par, (an2 == an)?TRUE:FALSE, TRUE);
             }
             if (f) HTML_CLOSE("p");
             HTML_TAG("hr");
    -        PL::Actions::index(OUT, an, 2, &ext, &current_area, FALSE, &new_par, FALSE, FALSE);
    +        PL::Actions::index(OUT, an, 2, &ext, &current_area, FALSE, &new_par, FALSE, FALSE);
         }
     }
     
    diff --git a/docs/if-module/4-anl.html b/docs/if-module/4-anl.html
    index 37785f999..1cdd1d934 100644
    --- a/docs/if-module/4-anl.html
    +++ b/docs/if-module/4-anl.html
    @@ -352,7 +352,7 @@ end, but it's syntactically valid.)
     
         action_name_list *anl = PL::Actions::ConstantLists::flip_anl_parity(RP[1], TRUE);
         if ((anl == NULL) ||
    -        (PL::Actions::can_have_parameters(anl->action_listed) == FALSE)) {
    +        (PL::Actions::can_have_parameters(anl->action_listed) == FALSE)) {
             ==> { fail production };
         }
         anl->parameter[anl->parc] = GET_RW(<anl-excluded>, 1);
    @@ -423,9 +423,9 @@ end, but it's syntactically valid.)
         LOOP_OVER(an, action_name) {
             int x_ended = FALSE;
             int fc = 0;
    -        int it_optional = PL::Actions::it_optional(an);
    -        int abbreviable = PL::Actions::abbreviable(an);
    -        wording XW = PL::Actions::set_text_to_name_tensed(an, tense);
    +        int it_optional = PL::Actions::it_optional(an);
    +        int abbreviable = PL::Actions::abbreviable(an);
    +        wording XW = PL::Actions::set_text_to_name_tensed(an, tense);
             new_anl->action_listed = an;
             new_anl->parc = 0;
             new_anl->word_position = Wordings::first_wn(W);
    @@ -466,7 +466,7 @@ end, but it's syntactically valid.)
             else if (<anl-in-tail>(Wordings::from(W, w_m))) {
                 new_anl->in_clause = GET_RW(<anl-in-tail>, 1);
                 inc = TRUE;
    -        } else if (PL::Actions::can_have_parameters(an)) {
    +        } else if (PL::Actions::can_have_parameters(an)) {
                 anl_being_parsed = new_anl;
                 if (<anl-to-tail>(Wordings::from(W, w_m))) {
                     inc = TRUE;
    @@ -518,7 +518,7 @@ end, but it's syntactically valid.)
             if (anl->parity == -1) return NULL;
             if (anl->negate_pattern) return NULL;
             if (anl->action_listed) {
    -            int k = PL::Actions::get_stem_length(anl->action_listed) - anl->abbreviation_level;
    +            int k = PL::Actions::get_stem_length(anl->action_listed) - anl->abbreviation_level;
                 if (anl->word_position != posn) {
                     if (posn >= 0) return NULL;
                     posn = anl->word_position;
    @@ -561,7 +561,7 @@ end, but it's syntactically valid.)
         if (optimise) {
             WRITE("action %s", (anl->parity==1)?"==":"~=");
             for (action_name_list *L = anl; L; L = L->next) {
    -            WRITE("%n", PL::Actions::double_sharp(L->action_listed));
    +            WRITE("%n", PL::Actions::double_sharp(L->action_listed));
                 if (L->next) WRITE(" or ");
             }
         } else {
    @@ -570,7 +570,7 @@ end, but it's syntactically valid.)
                 if (L->nap_listed)
                     WRITE("(%n())", PL::Actions::Patterns::Named::identifier(L->nap_listed));
                 else
    -                WRITE("action == %n", PL::Actions::double_sharp(L->action_listed));
    +                WRITE("action == %n", PL::Actions::double_sharp(L->action_listed));
                 if (L->parity == -1) WRITE(")");
                 if (L->next) WRITE(" || ");
             }
    @@ -602,7 +602,7 @@ end, but it's syntactically valid.)
                 Produce::inv_primitive(Emit::tree(), EQ_BIP);
                 Produce::down(Emit::tree());
                     Produce::val_iname(Emit::tree(), K_value, Hierarchy::find(ACTION_HL));
    -                Produce::val_iname(Emit::tree(), K_value, PL::Actions::double_sharp(L->action_listed));
    +                Produce::val_iname(Emit::tree(), K_value, PL::Actions::double_sharp(L->action_listed));
                 Produce::up(Emit::tree());
             }
         }
    diff --git a/docs/if-module/4-ap.html b/docs/if-module/4-ap.html
    index 7677c9e0a..4d3d379e1 100644
    --- a/docs/if-module/4-ap.html
    +++ b/docs/if-module/4-ap.html
    @@ -406,10 +406,10 @@ STV clauses; (2) get this right:
     int PL::Actions::Patterns::is_unspecific(action_pattern *ap) {
         action_name *an = PL::Actions::Patterns::required_action(ap);
         if (an == NULL) return TRUE;
    -    int N = PL::Actions::get_min_parameters(an);
    +    int N = PL::Actions::get_min_parameters(an);
         if ((N > 0) && (ap->noun_spec == NULL)) return TRUE;
         if ((N > 1) && (ap->second_spec == NULL)) return TRUE;
    -    N = PL::Actions::get_max_parameters(an);
    +    N = PL::Actions::get_max_parameters(an);
         if ((N > 0) && (PL::Actions::Patterns::ap_clause_is_unspecific(ap->noun_spec))) return TRUE;
         if ((N > 1) && (PL::Actions::Patterns::ap_clause_is_unspecific(ap->second_spec))) return TRUE;
         if (PL::Actions::Patterns::ap_clause_is_unspecific(ap->actor_spec)) return TRUE;
    @@ -469,7 +469,7 @@ an action.
         return spec;
     }
     
    -int PL::Actions::Patterns::check_going(parse_node *spec, char *keyword,
    +int PL::Actions::Patterns::check_going(parse_node *spec, char *keyword,
         kind *ka, kind *kb) {
         if (spec == NULL) return TRUE;
         if (Specifications::is_description_like(spec)) {
    @@ -1075,7 +1075,7 @@ away as they are recorded.
             PL::Actions::ConstantLists::get_single_action(preliminary_anl);
         if (chief_an == NULL) {
             int x;
    -        chief_an = PL::Actions::longest_null(W, tense, &x);
    +        chief_an = PL::Actions::longest_null(W, tense, &x);
         }
         if (chief_an) {
             stacked_variable *last_stv_specified = NULL;
    @@ -1084,7 +1084,7 @@ away as they are recorded.
             while (i < Wordings::last_wn(W)) {
                 stacked_variable *stv = NULL;
                 if (Word::unexpectedly_upper_case(i) == FALSE)
    -                stv = PL::Actions::parse_match_clause(chief_an, Wordings::new(i, Wordings::last_wn(W)));
    +                stv = PL::Actions::parse_match_clause(chief_an, Wordings::new(i, Wordings::last_wn(W)));
                 if (stv != NULL) {
                     LOGIF(ACTION_PATTERN_PARSING,
                         "Special clauses found on <%W>\n", Wordings::from(W, i));
    @@ -1258,7 +1258,7 @@ description.
             if (Wordings::nonempty(entry->parameter[1])) {
                 if ((entry->action_listed != NULL)
                     && (K_understanding)
    -                && (Kinds::eq(PL::Actions::get_data_type_of_second_noun(entry->action_listed), K_understanding))
    +                && (Kinds::eq(PL::Actions::get_data_type_of_second_noun(entry->action_listed), K_understanding))
                     && (<understanding-action-irregular-operand>(entry->parameter[1]))) {
                     trial_ap.second_spec = Rvalues::from_grammar_verb(NULL);  Why no GV here?
                     Node::set_text(trial_ap.second_spec, entry->parameter[1]);
    @@ -1279,8 +1279,8 @@ description.
         kind *check_n = K_object;
         kind *check_s = K_object;
         if (entry->action_listed != NULL) {
    -        check_n = PL::Actions::get_data_type_of_noun(entry->action_listed);
    -        check_s = PL::Actions::get_data_type_of_second_noun(entry->action_listed);
    +        check_n = PL::Actions::get_data_type_of_noun(entry->action_listed);
    +        check_s = PL::Actions::get_data_type_of_second_noun(entry->action_listed);
         }
         trial_ap.valid = TRUE;
         if ((trial_ap.noun_any == FALSE) &&
    @@ -1305,10 +1305,10 @@ description.
             if ((entry->delete_this_link == FALSE) && (entry->action_listed)) {
                 if ((prev == NULL) || (prev->word_position != entry->word_position)) {
                     if ((entry->next == NULL) || (entry->next->word_position != entry->word_position)) {
    -                    if ((K[0] == NULL) && (PL::Actions::get_max_parameters(entry->action_listed) >= 1))
    -                        K[0] = PL::Actions::get_data_type_of_noun(entry->action_listed);
    -                    if ((K[1] == NULL) && (PL::Actions::get_max_parameters(entry->action_listed) >= 2))
    -                        K[1] = PL::Actions::get_data_type_of_second_noun(entry->action_listed);
    +                    if ((K[0] == NULL) && (PL::Actions::get_max_parameters(entry->action_listed) >= 1))
    +                        K[0] = PL::Actions::get_data_type_of_noun(entry->action_listed);
    +                    if ((K[1] == NULL) && (PL::Actions::get_max_parameters(entry->action_listed) >= 2))
    +                        K[1] = PL::Actions::get_data_type_of_second_noun(entry->action_listed);
                     }
                 }
             }
    @@ -1317,12 +1317,12 @@ description.
         for (entry = anl; entry; prev = entry, entry = entry->next) {
             if ((entry->delete_this_link == FALSE) && (entry->action_listed)) {
                 int poor_choice = FALSE;
    -            if ((K[0]) && (PL::Actions::get_max_parameters(entry->action_listed) >= 1)) {
    -                kind *L = PL::Actions::get_data_type_of_noun(entry->action_listed);
    +            if ((K[0]) && (PL::Actions::get_max_parameters(entry->action_listed) >= 1)) {
    +                kind *L = PL::Actions::get_data_type_of_noun(entry->action_listed);
                     if (Kinds::compatible(L, K[0]) == FALSE) poor_choice = TRUE;
                 }
    -            if ((K[1]) && (PL::Actions::get_max_parameters(entry->action_listed) >= 2)) {
    -                kind *L = PL::Actions::get_data_type_of_second_noun(entry->action_listed);
    +            if ((K[1]) && (PL::Actions::get_max_parameters(entry->action_listed) >= 2)) {
    +                kind *L = PL::Actions::get_data_type_of_second_noun(entry->action_listed);
                     if (Kinds::compatible(L, K[1]) == FALSE) poor_choice = TRUE;
                 }
                 if (poor_choice) {
    @@ -1382,17 +1382,17 @@ the case when the first action name in the list is             }
                 action_name *this = entry->action_listed;
                 if (this) {
    -                if (PL::Actions::is_out_of_world(this)) no_oow++; else no_iw++;
    +                if (PL::Actions::is_out_of_world(this)) no_oow++; else no_iw++;
     
                     if (entry->parc >= 1) {
    -                    kind *K = PL::Actions::get_data_type_of_noun(this);
    +                    kind *K = PL::Actions::get_data_type_of_noun(this);
                         kind *A = kinds_observed_in_list[0];
                         if ((A) && (K) && (Kinds::eq(A, K) == FALSE))
                             immiscible = TRUE;
                         kinds_observed_in_list[0] = K;
                     }
                     if (entry->parc >= 2) {
    -                    kind *K = PL::Actions::get_data_type_of_second_noun(this);
    +                    kind *K = PL::Actions::get_data_type_of_second_noun(this);
                         kind *A = kinds_observed_in_list[1];
                         if ((A) && (K) && (Kinds::eq(A, K) == FALSE))
                             immiscible = TRUE;
    @@ -1404,7 +1404,7 @@ the case when the first action name in the list is     for (action_name_list *entry = anl; entry; entry = entry->next)
             if (entry->action_listed)
    -            if (no_of_pars > PL::Actions::get_max_parameters(entry->action_listed))
    +            if (no_of_pars > PL::Actions::get_max_parameters(entry->action_listed))
                     immiscible = TRUE;
     
         if (immiscible) {
    @@ -1632,10 +1632,10 @@ into action patterns in the noun or second noun position.
             Produce::val(Emit::tree(), K_number, LITERAL_IVAL, (inter_ti) flag_bits);
             if (spec2) PL::Actions::Patterns::emit_try_action_parameter(spec2, K_object);
             else Produce::val_iname(Emit::tree(), K_object, Hierarchy::find(PLAYER_HL));
    -        Produce::val_iname(Emit::tree(), K_action_name, PL::Actions::double_sharp(an));
    -        if (spec0) PL::Actions::Patterns::emit_try_action_parameter(spec0, PL::Actions::get_data_type_of_noun(an));
    +        Produce::val_iname(Emit::tree(), K_action_name, PL::Actions::double_sharp(an));
    +        if (spec0) PL::Actions::Patterns::emit_try_action_parameter(spec0, PL::Actions::get_data_type_of_noun(an));
             else Produce::val(Emit::tree(), K_number, LITERAL_IVAL, 0);
    -        if (spec1) PL::Actions::Patterns::emit_try_action_parameter(spec1, PL::Actions::get_data_type_of_second_noun(an));
    +        if (spec1) PL::Actions::Patterns::emit_try_action_parameter(spec1, PL::Actions::get_data_type_of_second_noun(an));
             else Produce::val(Emit::tree(), K_number, LITERAL_IVAL, 0);
             if (store_instead) {
                 Produce::inv_call_iname(Emit::tree(), Hierarchy::find(STORED_ACTION_TY_CURRENT_HL));
    @@ -2015,7 +2015,7 @@ and in this case we therefore ignore             CPMC_NEEDED(SECOND_IS_INP1_CPMC, NULL);
             }
             if ((ap.action) && (ap.action->action_listed)) {
    -            kind_of_noun = PL::Actions::get_data_type_of_noun(ap.action->action_listed);
    +            kind_of_noun = PL::Actions::get_data_type_of_noun(ap.action->action_listed);
                 if (kind_of_noun == NULL) kind_of_noun = K_object;
             }
     
    @@ -2029,7 +2029,7 @@ and in this case we therefore ignore             }
             }
             if ((ap.action) && (ap.action->action_listed)) {
    -            kind_of_second = PL::Actions::get_data_type_of_second_noun(ap.action->action_listed);
    +            kind_of_second = PL::Actions::get_data_type_of_second_noun(ap.action->action_listed);
                 if (kind_of_second == NULL) kind_of_second = K_object;
             }
             if (Kinds::Behaviour::is_object(kind_of_second)) {
    @@ -2501,9 +2501,9 @@ and in this case we therefore ignore         Produce::val(Emit::tree(), K_number, LITERAL_IVAL, (inter_ti) -1);
         else {
             if (ap->action->next) bad_form = TRUE;
    -        if (PL::Actions::can_be_compiled_in_past_tense(ap->action->action_listed) == FALSE)
    +        if (PL::Actions::can_be_compiled_in_past_tense(ap->action->action_listed) == FALSE)
                 bad_form = TRUE;
    -        Produce::val_iname(Emit::tree(), K_value, PL::Actions::double_sharp(ap->action->action_listed));
    +        Produce::val_iname(Emit::tree(), K_value, PL::Actions::double_sharp(ap->action->action_listed));
         }
         Produce::up(Emit::tree());
     
    diff --git a/docs/if-module/5-gl.html b/docs/if-module/5-gl.html
    index ebe416b27..a819fe5bc 100644
    --- a/docs/if-module/5-gl.html
    +++ b/docs/if-module/5-gl.html
    @@ -169,7 +169,7 @@ to calculate, and useful when sorting grammar lines into applicability order.
         gl->resulting_action = ac;
         gl->belongs_to_gv = NULL;
     
    -    if (ac != NULL) PL::Actions::add_gl(ac, gl);
    +    if (ac != NULL) PL::Actions::add_gl(ac, gl);
     
         gl->mistaken = FALSE;
         gl->mistake_response_text = EMPTY_WORDING;
    @@ -1219,7 +1219,7 @@ command GVs) have not yet been type-checked, whereas all others have.
                     Emit::array_iname_entry(VERB_DIRECTIVE_REVERSE_iname);
                 }
     
    -            PL::Actions::check_types_for_grammar(gl->resulting_action, token_values,
    +            PL::Actions::check_types_for_grammar(gl->resulting_action, token_values,
                     token_value_kinds);
                 break;
             case GV_IS_PROPERTY_NAME:
    @@ -1500,7 +1500,7 @@ order of parsing — this is what the reader of the index is interested in.
         action_name *an = gl->resulting_action;
         if (an == NULL) return;
         Index::anchor(OUT, headword);
    -    if (PL::Actions::is_out_of_world(an))
    +    if (PL::Actions::is_out_of_world(an))
             HTML::begin_colour(OUT, I"800000");
         WRITE("&quot;");
         PL::Actions::Index::verb_definition(OUT, Lexer::word_text(gl->original_text),
    @@ -1511,7 +1511,7 @@ order of parsing — this is what the reader of the index is interested in.
         Index::detail_link(OUT, "A", an->allocation_id, TRUE);
         if (gl->reversed) WRITE(" (reversed)");
         WRITE("</i>");
    -    if (PL::Actions::is_out_of_world(an))
    +    if (PL::Actions::is_out_of_world(an))
             HTML::end_colour(OUT);
         HTML_TAG("br");
     }
    @@ -1541,7 +1541,7 @@ this for a whole list of GLs:
     

    -void PL::Parsing::Lines::list_with_action_add(grammar_line *list_head, grammar_line *gl) {
    +void PL::Parsing::Lines::list_with_action_add(grammar_line *list_head, grammar_line *gl) {
         if (list_head == NULL) internal_error("tried to add to null action list");
         while (list_head->next_with_action)
             list_head = list_head->next_with_action;
    @@ -1553,7 +1553,7 @@ the HTML index.
     

    -int PL::Parsing::Lines::index_list_with_action(OUTPUT_STREAM, grammar_line *gl) {
    +int PL::Parsing::Lines::index_list_with_action(OUTPUT_STREAM, grammar_line *gl) {
         int said_something = FALSE;
         while (gl != NULL) {
             if (gl->belongs_to_gv) {
    diff --git a/docs/if-module/5-gp.html b/docs/if-module/5-gp.html
    index 2b55e557c..f4beca962 100644
    --- a/docs/if-module/5-gp.html
    +++ b/docs/if-module/5-gp.html
    @@ -73,7 +73,7 @@ function togglePopup(material_id) {
         
     

    A plugin for the I6 run-time properties needed to support parsing.

    -
    +

    §1. Definitions.

    @@ -138,11 +138,10 @@ contains a pointer to its own unique copy of the following structure:
     void PL::Parsing::Visibility::start(void) {
    -    REGISTER(NEW_VARIABLE_NOTIFY_PCALL, PL::Parsing::Visibility::parsing_new_variable_notify);
    -    REGISTER(NEW_SUBJECT_NOTIFY_PCALL, PL::Parsing::Visibility::parsing_new_subject_notify);
    -    REGISTER(NEW_PERMISSION_NOTIFY_PCALL, PL::Parsing::Visibility::parsing_new_permission_notify);
    -    REGISTER(COMPLETE_MODEL_PCALL, PL::Parsing::Visibility::parsing_complete_model);
    -    REGISTER(ESTIMATE_PROPERTY_USAGE_PCALL, PL::Parsing::Visibility::parsing_estimate_property_usage);
    +    PluginManager::plug(NEW_VARIABLE_NOTIFY_PLUG, PL::Parsing::Visibility::parsing_new_variable_notify);
    +    PluginManager::plug(NEW_SUBJECT_NOTIFY_PLUG, PL::Parsing::Visibility::parsing_new_subject_notify);
    +    PluginManager::plug(NEW_PERMISSION_NOTIFY_PLUG, PL::Parsing::Visibility::parsing_new_permission_notify);
    +    PluginManager::plug(COMPLETE_MODEL_PLUG, PL::Parsing::Visibility::parsing_complete_model);
     }
     
     int PL::Parsing::Visibility::parsing_new_subject_notify(inference_subject *subj) {
    @@ -199,57 +198,45 @@ the Standard Rules or, in the case of "the X understood", by Inform itself.
         return FALSE;
     }
     
    -

    §9. This is for name and plural. -

    - -
    -int PL::Parsing::Visibility::parsing_estimate_property_usage(kind *k, int *words_used) {
    -    wording W = Kinds::Behaviour::get_name(k, FALSE);
    -    *words_used += Wordings::length(W);
    -    wording PW = Kinds::Behaviour::get_name(k, TRUE);
    -    *words_used += Wordings::length(PW);
    -    return FALSE;
    -}
    -
    -

    §10. Once the traverse is done, we can infer values for the two key I6 properties +

    §9. Once the traverse is done, we can infer values for the two key I6 properties for parsing:

    -int PL::Parsing::Visibility::parsing_complete_model(int stage) {
    +int PL::Parsing::Visibility::parsing_complete_model(int stage) {
         if (stage == WORLD_STAGE_V) {
             instance *I;
             P_name = ValueProperties::new_nameless(I"name", K_text);
    -        Hierarchy::make_available(Emit::tree(), PL::Parsing::Visibility::name_name());
    +        Hierarchy::make_available(Emit::tree(), PL::Parsing::Visibility::name_name());
             P_parse_name = ValueProperties::new_nameless(I"parse_name", K_value);
             P_action_bitmap = ValueProperties::new_nameless(I"action_bitmap", K_value);
             Hierarchy::make_available(Emit::tree(), RTProperties::iname(P_action_bitmap));
     
             LOOP_OVER_INSTANCES(I, K_object) {
                 inference_subject *subj = Instances::as_subject(I);
    -            Assert the I6 name property10.1;
    -            Assert the I6 parse-name property10.2;
    -            Assert the I6 action-bitmap property10.3;
    +            Assert the I6 name property9.1;
    +            Assert the I6 parse-name property9.2;
    +            Assert the I6 action-bitmap property9.3;
             }
     
             kind *K;
             LOOP_OVER_BASE_KINDS(K)
                 if (Kinds::Behaviour::is_subkind_of_object(K)) {
                     inference_subject *subj = KindSubjects::from_kind(K);
    -                Assert the I6 parse-name property10.2;
    +                Assert the I6 parse-name property9.2;
                 }
     
             inference_subject *subj = KindSubjects::from_kind(K_thing);
    -        Assert the I6 action-bitmap property10.3;
    +        Assert the I6 action-bitmap property9.3;
         }
         return FALSE;
     }
     
    -inter_name *PL::Parsing::Visibility::name_name(void) {
    +inter_name *PL::Parsing::Visibility::name_name(void) {
         return RTProperties::iname(P_name);
     }
     
    -

    §10.1. The name property requires special care, partly over I6 eccentricities +

    §9.1. The name property requires special care, partly over I6 eccentricities such as the way that single-letter dictionary words can be misinterpreted as characters (hence the double slash below), but also because something called "your ..." in the source text — "your nose", say — needs to @@ -268,7 +255,7 @@ it into the name -

    Assert the I6 name property10.1 = +

    Assert the I6 name property9.1 =

    @@ -330,12 +317,12 @@ for the kinds we inherit from.
                 Rvalues::from_iname(name_array), CERTAIN_CE);
         }
     
    -
    • This code is used in §10.
    -

    §10.2. We attach numbered parse name routines as properties for any object +

    • This code is used in §9.
    +

    §9.2. We attach numbered parse name routines as properties for any object where grammar has specified a need. (By default, this will not happen.)

    -

    Assert the I6 parse-name property10.2 = +

    Assert the I6 parse-name property9.2 =

    @@ -344,8 +331,8 @@ where grammar has specified a need. (By default, this will not happen.)
             ValueProperties::assert(P_parse_name, subj,
                 Rvalues::from_iname(S), CERTAIN_CE);
     
    -
    • This code is used in §10 (twice).
    -

    §10.3. The action bitmap is an array of bits attached to each object, one +

    • This code is used in §9 (twice).
    +

    §9.3. The action bitmap is an array of bits attached to each object, one for each action, which records whether that action has yet applied successfully to that object. This is used at run-time to handle past tense conditions such as "the jewels have been taken". Note that @@ -354,19 +341,19 @@ to ensure that it will be inherited by all I6 objects of this class, i.e., all I6 objects corresponding to I7 things.

    -

    Assert the I6 action-bitmap property10.3 = +

    Assert the I6 action-bitmap property9.3 =

         if (InferenceSubjects::is_within(subj, KindSubjects::from_kind(K_room)) == FALSE) {
             instance *I = InstanceSubjects::to_instance(subj);
    -        inter_name *S = PL::Actions::compile_action_bitmap_property(I);
    +        inter_name *S = PL::Actions::compile_action_bitmap_property(I);
             ValueProperties::assert(P_action_bitmap, subj,
                 Rvalues::from_iname(S), CERTAIN_CE);
         }
     
    -
    • This code is used in §10 (twice).
    -

    §11. Visible properties. A visible property is one which can be used to describe an object: for +

    • This code is used in §9 (twice).
    +

    §10. Visible properties. A visible property is one which can be used to describe an object: for instance, if colour is a visible property of a car, then it can be called "green car" if and only if the current value of the colour of the car is "green". @@ -378,7 +365,7 @@ depends on a property permission and not a mere property.

    -int PL::Parsing::Visibility::seek(property *pr, inference_subject *subj,
    +int PL::Parsing::Visibility::seek(property *pr, inference_subject *subj,
         int level, wording WHENW) {
         int parity, upto = 1;
         if (Properties::is_either_or(pr) == FALSE) upto = 0;
    @@ -395,7 +382,7 @@ depends on a property permission and not a mere property.
         return FALSE;
     }
     
    -int PL::Parsing::Visibility::any_property_visible_to_subject(inference_subject *subj, int allow_inheritance) {
    +int PL::Parsing::Visibility::any_property_visible_to_subject(inference_subject *subj, int allow_inheritance) {
         property *pr;
         LOOP_OVER(pr, property) {
             property_permission *pp =
    @@ -406,11 +393,11 @@ depends on a property permission and not a mere property.
         return FALSE;
     }
     
    -int PL::Parsing::Visibility::get_level(property_permission *pp) {
    +int PL::Parsing::Visibility::get_level(property_permission *pp) {
         return PP_PLUGIN_DATA(parsing, pp)->visibility_level_in_parser;
     }
     
    -parse_node *PL::Parsing::Visibility::get_condition(property_permission *pp) {
    +parse_node *PL::Parsing::Visibility::get_condition(property_permission *pp) {
         parse_node *spec;
         if (Wordings::empty(PP_PLUGIN_DATA(parsing, pp)->visibility_condition)) return NULL;
         spec = NULL;
    @@ -439,7 +426,7 @@ depends on a property permission and not a mere property.
                 PP_PLUGIN_DATA(parsing, pp)->visibility_condition);
         }
         if (InferenceSubjects::narrowest_broader_subject(infs))
    -        PL::Parsing::Visibility::log_parsing_visibility(InferenceSubjects::narrowest_broader_subject(infs));
    +        PL::Parsing::Visibility::log_parsing_visibility(InferenceSubjects::narrowest_broader_subject(infs));
     }