§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.
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.
+
defineMAX_PLUGINS32
@@ -94,7 +97,7 @@ used for interactive fiction; or not, when it isn't.
structtext_stream *textual_name;structwordingwording_name;structplugin *parent_plugin;
-void (*starter_routine)(void);
+void (*activation_function)(void);intactive;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.
}
The structure plugin is private to this section.
-
§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.1elseQ->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;
§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.
}
@@ -235,8 +238,66 @@ Preform nonterminal to parse them, and here it is.
returnNULL;}
+
§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.
+
§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.
+
+
+
definePLUGINS_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
+intQ_plugin_return_PLUGH = (*R_plugin_rule_ZOOGE)(args); or this
+if (Q_plugin_return_PLUGH) returnQ_plugin_return_PLUGH;
+ }
+returnFALSE;
+}
+definePLUGINS_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;
+intQ_plugin_return_PLUGH = (*R_plugin_rule_ZOOGE)();
+if (Q_plugin_return_PLUGH) returnQ_plugin_return_PLUGH;
+ }
+returnFALSE;
+}
+
+ Errors with formulating logical statements are sometimes caught by the calculus module: this section collects and issues such errors as tidy Inform 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.
§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.
§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) {
§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);}typedefstructfound_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, intcertitude) {
+inference *PL::Backdrops::new_found_in_inference(inference_subject *loc, intcertitude) {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.
returnCI_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.
-intPL::Backdrops::object_is_a_backdrop(instance *I) {
+intPL::Backdrops::object_is_a_backdrop(instance *I) {if ((PluginManager::active(regions_plugin)) && (K_backdrop) && (I) && (Instances::of_kind(I, K_backdrop))) returnTRUE;returnFALSE;
@@ -211,16 +210,7 @@ Standard Rules. (So there is no need to translate this to other languages.)
returnFALSE;}
-
§9. Every backdrop needs a single-word property (found_in at the I6 level):
-
§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
-intPL::Backdrops::assert_relations(binary_predicate *relation,
+intPL::Backdrops::assert_relations(binary_predicate *relation,instance *I0, instance *I1) {if ((Instances::of_kind(I1, K_backdrop)) &&
@@ -253,7 +243,7 @@ and text like
returnFALSE;}
-
§11. For indexing purposes, the following loops are useful:
+
§10. For indexing purposes, the following loops are useful:
defineLOOP_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.
§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
§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);
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.
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.
intPL::EPSMap::obj_in_region(instance *I, instance *reg) {if ((I == NULL) || (reg == NULL)) returnFALSE;
-if (PL::Regions::enclosing(I) == reg) returnTRUE;
-returnPL::EPSMap::obj_in_region(PL::Regions::enclosing(I), reg);
+if (PL::Regions::enclosing(I) == reg) returnTRUE;
+returnPL::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.
#ifdefIF_MODULEinference_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.
-voidPL::HTMLMap::colour_chip(OUTPUT_STREAM, instance *I, instance *Reg, parse_node *at) {
+voidPL::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.
intcount = 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.
§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
-intPL::Regions::object_is_a_region(instance *I) {
+intPL::Regions::object_is_a_region(instance *I) {if ((PluginManager::active(regions_plugin)) && (K_region) && (I) && (Instances::of_kind(I, K_region))) returnTRUE;returnFALSE;
@@ -234,20 +234,12 @@ Standard Rules. (So there is no need to translate this to other languages.)
returnFALSE;}
§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.
-intPL::Regions::regions_intervene_in_assertion(parse_node *px, parse_node *py) {
+intPL::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.
returnFALSE;}
-voidPL::Regions::create_relations(void) {
+voidPL::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.)
§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);
§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 returnP;}
§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:
-intPL::Spatial::object_is_a_room(instance *I) {
+intPL::Spatial::object_is_a_room(instance *I) {if ((PluginManager::active(spatial_plugin)) && (K_room) && (I) && (Instances::of_kind(I, K_room)))returnTRUE;
@@ -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) returnNULL;if (PluginManager::active(spatial_plugin) == FALSE) returnNULL;returnSPATIAL_DATA(I)->progenitor;}
-voidPL::Spatial::set_progenitor(instance *of, instance *to, inference *reason) {
+voidPL::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)) return1;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;intclosest = 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)) {intdiff = 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)) {wordingRW = 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) {wordingRGW = Instances::get_name(reg, FALSE);if (MAP_DATA(reg)->zone == 1) {
@@ -3239,7 +3239,7 @@ can make use of the following:
§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 = {
@@ -383,7 +382,7 @@ Rules. (So there is no need to translate this to other languages.)
§15.
-intPL::Map::object_is_a_door(instance *I) {
+intPL::Map::object_is_a_door(instance *I) {if ((PluginManager::active(map_plugin)) && (K_door) && (I) && (Instances::of_kind(I, K_door)))returnTRUE;
@@ -403,7 +402,7 @@ sheaf of binary relations, one for each direction. Anyway:
-intPL::Map::is_a_direction(inference_subject *infs) {
+intPL::Map::is_a_direction(inference_subject *infs) {if (K_direction == NULL) returnFALSE; in particular, if we aren't using the IF modelreturnInferenceSubjects::is_within(infs, KindSubjects::from_kind(K_direction));}
@@ -492,7 +491,7 @@ quite crunchy algorithms, has the fastest possible access to the layout.
defineMAP_EXIT(X, Y) MAP_DATA(X)->exits[Y]
-voidPL::Map::build_exits_array(void) {
+voidPL::Map::build_exits_array(void) {instance *I;intd = 0;LOOP_OVER_INSTANCES(I, K_object) {
@@ -601,7 +600,7 @@ object has four pieces of data attached:
-intPL::Map::map_property_value_notify(property *prn, parse_node *val) {
-if (prn == P_other_side) {
+intPL::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.
-voidPL::Map::set_found_in(instance *I, inter_name *S) {
+voidPL::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.
-intPL::Map::map_act_on_special_NPs(parse_node *p) {
+intPL::Map::map_act_on_special_NPs(parse_node *p) {if (<notable-map-noun-phrases>(Node::get_text(p))) {switch (<<r>>) {case0:
@@ -726,11 +717,11 @@ and there seems little point in writing this any better.
returnFALSE;}
-
§31. We also add some optional clauses to the "going" action:
+
§30. We also add some optional clauses to the "going" action:
-intPL::Map::map_check_going(parse_node *from, parse_node *to,
+intPL::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) returnFALSE;
@@ -745,7 +736,7 @@ and there seems little point in writing this any better.
returnTRUE;}
-
§32. Consider the sentences:
+
§31. Consider the sentences:
@@ -772,7 +763,7 @@ because, of course, that does set its kind.
-intPL::Map::map_intervene_in_assertion(parse_node *px, parse_node *py) {
+intPL::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.
returnFALSE;}
-
§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.
voidPL::Map::enter_one_way_mode(void) { oneway_map_connections_only = TRUE; }voidPL::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();
- } elsePL::Map::oneway_map_connection(go_to, go_from, reverse_dir, LIKELY_CE);
+ } elsePL::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.
§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 =
§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'.");
§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();
§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.)
} }
§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.");
§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.");
§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 =
§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 =
§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);
§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);
§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);
§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.
-intPL::Naming::object_is_privately_named(instance *I) {
+intPL::Naming::object_is_privately_named(instance *I) {intcertainty = PropertyInferences::either_or_state(Instances::as_subject(I), P_privately_named);if (certainty > 0) returnTRUE;if (certainty < 0) returnFALSE;
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.
§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) {
§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".
§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?
-
§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
-action_name *PL::Actions::act_new(wordingW, intimplemented_by_I7) {
+action_name *PL::Actions::act_new(wordingW, intimplemented_by_I7) {intmake_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>
-intPL::Actions::action_names_overlap(action_name *an1, action_name *an2) {
+intPL::Actions::action_names_overlap(action_name *an1, action_name *an2) {wordingW = an1->present_name;wordingXW = an2->present_name;for (inti = Wordings::first_wn(W), j = Wordings::first_wn(XW);
@@ -456,12 +444,12 @@ will do: it doesn't have to be "it".)
returnFALSE;}
-voidPL::Actions::log(action_name *an) {
+voidPL::Actions::log(action_name *an) {if (an == NULL) LOG("<null-action-name>");elseLOG("%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
§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));}
-intPL::Actions::get_stem_length(action_name *an) {
+intPL::Actions::get_stem_length(action_name *an) {if (Wordings::empty(an->present_name)) return0; should never happenints = 0;LOOP_THROUGH_WORDING(k, an->present_name)
@@ -635,7 +623,7 @@ names of significance in the I6 library.
returns;}
-
§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:
@@ -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();
§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, - }
@@ -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.");
-voidPL::Actions::act_on_clause(intN) {
+voidPL::Actions::act_on_clause(intN) {switch (N) {caseOOW_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.
-wordingPL::Actions::set_past_participle(wordingW, intirregular_pp) {
+wordingPL::Actions::set_past_participle(wordingW, intirregular_pp) {feed_tid = 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:
returnFeeds::end(id);}
§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.
-intPL::Actions::can_be_compiled_in_past_tense(action_name *an) {
+intPL::Actions::can_be_compiled_in_past_tense(action_name *an) {if (an->min_parameters > 1) returnFALSE;if (an->max_parameters > 1) returnFALSE;if ((an->max_parameters == 1) &&
@@ -1186,7 +1174,7 @@ in question. This is where we compile the bitmaps in their fresh, empty form.
returnTRUE;}
-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);}
-voidPL::Actions::check_types_for_grammar(action_name *an, inttok_values,
+voidPL::Actions::check_types_for_grammar(action_name *an, inttok_values,kind **tok_value_kinds) {intrequired = 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_statesave = 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.
§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); }
§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);
§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.
§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.
-intPL::Parsing::Visibility::seek(property *pr, inference_subject *subj,
+intPL::Parsing::Visibility::seek(property *pr, inference_subject *subj,intlevel, wordingWHENW) {intparity, 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.
returnFALSE;}
-intPL::Parsing::Visibility::any_property_visible_to_subject(inference_subject *subj, intallow_inheritance) {
+intPL::Parsing::Visibility::any_property_visible_to_subject(inference_subject *subj, intallow_inheritance) {property *pr;LOOP_OVER(pr, property) {property_permission *pp =
@@ -406,11 +393,11 @@ depends on a property permission and not a mere property.
returnFALSE;}
-intPL::Parsing::Visibility::get_level(property_permission *pp) {
+intPL::Parsing::Visibility::get_level(property_permission *pp) {returnPP_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)) returnNULL;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));}
diff --git a/docs/if-module/5-gpr.html b/docs/if-module/5-gpr.html
index a43b782de..eb53830e0 100644
--- a/docs/if-module/5-gpr.html
+++ b/docs/if-module/5-gpr.html
@@ -169,13 +169,13 @@ will simply compile a parse_n
returngv->gv_parse_name_iname;}
-inter_name *PL::Parsing::Tokens::General::compile_parse_name_property(inference_subject *subj) {
+inter_name *PL::Parsing::Tokens::General::compile_parse_name_property(inference_subject *subj) {inter_name *symb = NULL;grammar_verb *gv = PARSING_DATA_FOR_SUBJ(subj)->understand_as_this_object;if (PL::Parsing::Verbs::is_empty(gv) == FALSE) {symb = PL::Parsing::Tokens::General::get_gv_parse_name(gv); } else {
-if (PL::Parsing::Visibility::any_property_visible_to_subject(subj, FALSE)) {
+if (PL::Parsing::Visibility::any_property_visible_to_subject(subj, FALSE)) {parse_name_notice *notice = CREATE(parse_name_notice);compilation_unit *C = CompilationUnits::find(subj->infs_created_at);package_request *PR = Hierarchy::package(C, PARSE_NAMES_HAP);
@@ -261,10 +261,10 @@ will be the correct decision.
if (gv) {sometimes_has_visible_properties =
-PL::Parsing::Visibility::any_property_visible_to_subject(subj, TRUE);
+PL::Parsing::Visibility::any_property_visible_to_subject(subj, TRUE);N = PL::Parsing::Tokens::General::get_gv_parse_name(gv); } else {
-if (PL::Parsing::Visibility::any_property_visible_to_subject(subj, FALSE)
+if (PL::Parsing::Visibility::any_property_visible_to_subject(subj, FALSE) == FALSE) returnFALSE; }
@@ -409,7 +409,7 @@ more complex). I suspect we will return to this.
Produce::down(Emit::tree());Produce::inv_call_iname(Emit::tree(), Hierarchy::find(NEXTWORDSTOPPED_HL));Produce::val_iname(Emit::tree(), K_value, Hierarchy::find(SELF_HL));
-Produce::val_iname(Emit::tree(), K_value, PL::Parsing::Visibility::name_name());
+Produce::val_iname(Emit::tree(), K_value, PL::Parsing::Visibility::name_name());Produce::up(Emit::tree());Produce::code(Emit::tree());Produce::down(Emit::tree());
@@ -477,7 +477,7 @@ more complex). I suspect we will return to this.
Produce::down(Emit::tree());Produce::inv_call_iname(Emit::tree(), Hierarchy::find(NEXTWORDSTOPPED_HL));Produce::val_iname(Emit::tree(), K_value, Hierarchy::find(SELF_HL));
-Produce::val_iname(Emit::tree(), K_value, PL::Parsing::Visibility::name_name());
+Produce::val_iname(Emit::tree(), K_value, PL::Parsing::Visibility::name_name());Produce::up(Emit::tree());Produce::code(Emit::tree());Produce::down(Emit::tree());
@@ -577,7 +577,7 @@ in which case it would need to be followed by a semi-colon.
Produce::down(Emit::tree());Produce::inv_call_iname(Emit::tree(), Hierarchy::find(NEXTWORDSTOPPED_HL));Produce::val_iname(Emit::tree(), K_value, Hierarchy::find(SELF_HL));
-Produce::val_iname(Emit::tree(), K_value, PL::Parsing::Visibility::name_name());
+Produce::val_iname(Emit::tree(), K_value, PL::Parsing::Visibility::name_name());Produce::up(Emit::tree());Produce::code(Emit::tree());Produce::down(Emit::tree());
@@ -789,7 +789,7 @@ specific object.
if ((Properties::is_either_or(pr)) && (RTProperties::stored_in_negation(pr))) continue;property_permission *pp =PropertyPermissions::find(subj, pr, TRUE);
-if ((pp) && (PL::Parsing::Visibility::get_level(pp) > 0))
+if ((pp) && (PL::Parsing::Visibility::get_level(pp) > 0))PL::Parsing::Tokens::General::consider_visible_property(gprk, subj, pr, pp, phase); }PL::Parsing::Tokens::General::finish_considering_visible_properties(gprk, phase);
@@ -823,7 +823,7 @@ level, and to compile nothing to the file.
PL::Parsing::Tokens::General::begin_parsing_visible_properties(gprk); }
-spec = PL::Parsing::Visibility::get_condition(pp);
+spec = PL::Parsing::Visibility::get_condition(pp);if (spec) {conditional_vis = TRUE;
@@ -836,7 +836,7 @@ level, and to compile nothing to the file.
if (phase == 1)PL::Parsing::Tokens::General::distinguish_visible_property(gprk, pr);else
-PL::Parsing::Tokens::General::parse_visible_property(gprk, subj, pr, PL::Parsing::Visibility::get_level(pp));
+PL::Parsing::Tokens::General::parse_visible_property(gprk, subj, pr, PL::Parsing::Visibility::get_level(pp));if (conditional_vis) { Produce::up(Emit::tree()); Produce::up(Emit::tree()); }}
diff --git a/docs/if-module/5-gv.html b/docs/if-module/5-gv.html
index bc2a533e9..7d7400f81 100644
--- a/docs/if-module/5-gv.html
+++ b/docs/if-module/5-gv.html
@@ -562,7 +562,7 @@ or creates such.
returngv;}
-voidPL::Parsing::Verbs::take_out_one_word_grammar(grammar_verb *gv) {
+voidPL::Parsing::Verbs::take_out_one_word_grammar(grammar_verb *gv) {if (gv->gv_is != GV_IS_OBJECT)internal_error("One-word optimisation applies only to objects");gv->first_line = PL::Parsing::Lines::list_take_out_one_word_grammar(gv->first_line);
diff --git a/docs/if-module/5-tfg.html b/docs/if-module/5-tfg.html
index d430568dc..1abce257b 100644
--- a/docs/if-module/5-tfg.html
+++ b/docs/if-module/5-tfg.html
@@ -768,7 +768,7 @@ problem message for this case is now commented out.
"of day, or units; but certain built-into-Inform kinds of value ""(like snippet or rulebook, for instance) I can't use."); }
-if (PL::Parsing::Visibility::seek(pr, subj, level, WHENW) == FALSE) {
+if (PL::Parsing::Visibility::seek(pr, subj, level, WHENW) == FALSE) {StandardProblems::sentence_problem(Task::syntax_tree(), _p_(PM_UnknownUnpermittedProperty),"that property is not allowed for the thing or kind in question","just as (ordinarily) 'understand the open property as describing a "
@@ -792,7 +792,7 @@ problem message for this case is now commented out.
} else {action_name *an = ur->an_reference;LOGIF(GRAMMAR_CONSTRUCTION, "Understand nothing as: $l\n", an);
-PL::Actions::remove_gl(an);
+PL::Actions::remove_gl(an);grammar_verb *gv;LOOP_OVER(gv, grammar_verb) PL::Parsing::Verbs::remove_action(gv, an); }
diff --git a/docs/knowledge-module/2-ins.html b/docs/knowledge-module/2-ins.html
index a073fe668..a6da485ad 100644
--- a/docs/knowledge-module/2-ins.html
+++ b/docs/knowledge-module/2-ins.html
@@ -278,7 +278,7 @@ and the property "colour", whose names coincide:
-voidKindSubjects::new_permission_granted(inference_subject_family *f,
+voidKindSubjects::new_permission_granted(inference_subject_family *f,inference_subject *from, general_pointer *G) { *G = STORE_POINTER_property_of_value_storage(RTPropertyValues::get_storage());
@@ -205,7 +205,7 @@ We simply pass the request along to the appropriate code.
-voidKindSubjects::make_adj_const_domain(inference_subject_family *family,
+voidKindSubjects::make_adj_const_domain(inference_subject_family *family,inference_subject *infs, instance *I, property *prn) {kind *K = KindSubjects::to_kind(infs);InstanceAdjectives::make_adjectival(I, prn, K, NULL);
@@ -214,7 +214,7 @@ We simply pass the request along to the appropriate code.
§8.
-voidKindSubjects::get_name_text(inference_subject_family *family,
+voidKindSubjects::get_name_text(inference_subject_family *family,inference_subject *from, wording *W) {kind *K = KindSubjects::to_kind(from); *W = Kinds::Behaviour::get_name(K, FALSE);
@@ -225,7 +225,7 @@ of that kind, not certain:
@@ -265,6 +265,36 @@ to know if one base kind contains another.
returnFALSE;}
+
§11. Lastly, a bridge to the kinds module: the main compiler has to provide
+callbacks for it, as follows. When the kinds module creates a new base kind,
+it calls this:
+
@@ -307,6 +307,7 @@ the same basic fact, i.e., what the carrying capacity of the jar is.
} elseif (existing_sureness < inf_sureness) {LinkedLists::set_entry(insertion_point, SL, inf);Inferences::report_inference(inf, infs, "replaced existing less certain one");
+PluginCalls::inference_drawn(inf, infs); } else {intcontradiction_flag = FALSE;Determine whether or not they contradict each other8.2.1;
@@ -388,7 +389,7 @@ choice of what to be part of has more than two possible outcomes.
§13. This is called when Inferences::cmp is comparing two inferences which both
+
§12. This is called when Inferences::cmp is comparing two inferences which both
belong to this family. It should return one of the values described in the
documentation for that function; if it isn't provided, then the inferences will
automatically be considered as either duplicative or contradictory.
@@ -500,13 +489,13 @@ automatically be considered as either duplicative or contradictory.
§14. When a contradiction arises that requires a problem message, this method is
+
§13. When a contradiction arises that requires a problem message, this method is
called to give it the chance to issue a better-phrased one. If it does, it
should return TRUE. If it does not exist, or returns FALSE, a generic
contradiction problem is generated as usual.
@@ -518,7 +507,7 @@ contradiction problem is generated as usual.
INT_METHOD_TYPE(EXPLAIN_CONTRADICTION_INF_MTID, inference_family *f,inference *A, inference *B, intsimilarity, inference_subject *subj)
-intInferences::explain_contradiction(inference *A, inference *B,
+intInferences::explain_contradiction(inference *A, inference *B,intsimilarity, inference_subject *subj) {intrv = 0;INT_METHOD_CALL(rv, A->family, EXPLAIN_CONTRADICTION_INF_MTID, A, B, similarity, subj);
diff --git a/docs/knowledge-module/5-pi.html b/docs/knowledge-module/5-pi.html
index 620653995..101484f8b 100644
--- a/docs/knowledge-module/5-pi.html
+++ b/docs/knowledge-module/5-pi.html
@@ -81,10 +81,9 @@ either-or or valued.
voidPropertyInferences::start(void) {property_inf = Inferences::new_family(I"property_inf");METHOD_ADD(property_inf, LOG_DETAILS_INF_MTID, PropertyInferences::log_details);
-METHOD_ADD(property_inf, COMPARE_INF_MTID, PropertyInferences::cmp);
-METHOD_ADD(property_inf, JOIN_INF_MTID, PropertyInferences::join);
+METHOD_ADD(property_inf, COMPARE_INF_MTID, PropertyInferences::cmp);METHOD_ADD(property_inf, EXPLAIN_CONTRADICTION_INF_MTID,
-PropertyInferences::explain_contradiction);
+PropertyInferences::explain_contradiction);}
§2. Creation:
@@ -136,23 +135,13 @@ either-or or valued.
if (data->inferred_property_value) LOG(":=$P", data->inferred_property_value);}
-
§5. Plugins are allowed to react to the earliest news of a new property value, so:
-
§6. By convention, a pair of attached either/or properties which are negations of
+
§5. By convention, a pair of attached either/or properties which are negations of
each other — say "open" and "closed" — are treated as if they were the
same property but with different values.
-intPropertyInferences::cmp(inference_family *f, inference *i1, inference *i2) {
+intPropertyInferences::cmp(inference_family *f, inference *i1, inference *i2) {property_inference_data *data1 = RETRIEVE_POINTER_property_inference_data(i1->data);property_inference_data *data2 = RETRIEVE_POINTER_property_inference_data(i2->data);property *pr1 = data1->inferred_property;
@@ -180,12 +169,12 @@ same property but with different values.
returnCI_IDENTICAL;}
-
§7. A few properties get custom problem messages: initial value for a variable,
+
§6. A few properties get custom problem messages: initial value for a variable,
and properties which store the state of certain relations.
-intPropertyInferences::explain_contradiction(inference_family *f, inference *A,
+intPropertyInferences::explain_contradiction(inference_family *f, inference *A,inference *B, intsimilarity, inference_subject *subj) {property_inference_data *A_data = RETRIEVE_POINTER_property_inference_data(A->data);property_inference_data *B_data = RETRIEVE_POINTER_property_inference_data(B->data);
@@ -245,32 +234,34 @@ and properties which store the state of certain relations.
returnTRUE;}
§9. The ability to set the kind looks very odd here, and it is used only to force
+
§8. The ability to set the kind looks very odd here, and it is used only to force
the initial value property to be textual for certain bibliographic data.
§10. That's everything on setting up these inferences, so the remaining functions
+
§9. That's everything on setting up these inferences, so the remaining functions
are for working out what properties a subject actually has, on the basis of
its inference list.
§11. And this is a variant which does not inherit: e.g. if the kind "bird" has
+
§10. And this is a variant which does not inherit: e.g. if the kind "bird" has
the property "flightless" but Orville, an individual instance of"bird" has no
inference about this property, then we would return LIKELY_CE if asked about
"bird", but UNKNOWN_CE if asked Orville. The previous function would return
@@ -314,7 +305,7 @@ inference about this property, then we would return if (Properties::is_either_or(prn)) prnbar = EitherOrProperties::get_negation(prn);inference *inf;KNOWLEDGE_LOOP(inf, subj, property_inf) {
-property *known = PropertyInferences::get_property(inf);
+property *known = PropertyInferences::get_property(inf);intc = Inferences::get_certainty(inf);if (known) {if ((prn == known) && (c != UNKNOWN_CE)) {
@@ -330,14 +321,14 @@ inference about this property, then we would return returnUNKNOWN_CE;}
-
§12. This function does something a little unexpected, but is used only in indexing
+
§11. This function does something a little unexpected, but is used only in indexing
to work out whether a property is relevant to a given subject.
§13. Moving on to value properties, the following catches some late problems.
+
§12. Moving on to value properties, the following catches some late problems.
Rival values for the same property would be caught as contradictions at
assertion time in some cases, but because kinds are not always exactly known
when assertions are read, we can't yet know for sure. So later checks catch
@@ -358,11 +349,11 @@ anything falling through this crack.
A plugin which maintains run-time-accessible linked lists of instances of kinds, in order to speed up loops; and instance counts within kinds, in order to speed up relation storage; and the object-kind hierarchy, in order to speed up run-time checking of the type safety of property usage.
§1. Every subject contains a pointer to its own unique copy of the following
structure, but it only has relevance if the subject represents an object:
@@ -116,10 +116,9 @@ route-finding through relations on objects.
§4. Initialising. Counting data is actually relevant only for kinds, and remains blank for instances.
@@ -256,7 +255,7 @@ since Inform always compiles code which knows which kind it's looping over.
-inter_name *PL::Counting::first_instance(kind *K) {
+inter_name *PL::Counting::first_instance(kind *K) {kind_constructor *con = Kinds::get_construct(K);inter_name *iname = Kinds::Constructors::first_instance_iname(con);if (iname == NULL) {
@@ -266,7 +265,7 @@ since Inform always compiles code which knows which kind it's looping over.
returniname;}
-inter_name *PL::Counting::next_instance(kind *K) {
+inter_name *PL::Counting::next_instance(kind *K) {kind_constructor *con = Kinds::get_construct(K);inter_name *iname = Kinds::Constructors::next_instance_iname(con);if (iname == NULL) {
@@ -476,23 +475,7 @@ records the next instance in compilation order:
returnNULL;}
-
§13. Memory estimation. We're going to need about 4 words of extra memory to store the two properties
-per instance per kind, so:
-
§14. Loop optimisation. Lastly, then, the coup de gr\^ace: here's where we define loop schemas to
+
§13. Loop optimisation. Lastly, then, the coup de gr\^ace: here's where we define loop schemas to
perform loops through kinds quickly at run-time. We start from the First
constants, and use the Link constants to progress; we stop at nothing.
diff --git a/docs/values-module/3-tod.html b/docs/values-module/3-tod.html
index e19e58437..4ff4b5b6e 100644
--- a/docs/values-module/3-tod.html
+++ b/docs/values-module/3-tod.html
@@ -121,7 +121,7 @@ support for times of day from the Inform language. If so,