From 8c553d6565ee1ff6d7679e65f7958c36a5858522 Mon Sep 17 00:00:00 2001 From: Graham Nelson Date: Mon, 4 Oct 2021 23:35:07 +0100 Subject: [PATCH] Tentative movement of property storage policy into assembly --- docs/BasicInformKit/S-rtp.html | 108 +++---- docs/final-module/2-cg.html | 12 +- docs/final-module/2-cg2.html | 2 +- docs/final-module/2-tvg.html | 2 +- docs/final-module/4-fi6.html | 147 ++++++++- docs/runtime-module/5-prp.html | 117 +++---- inform7/Figures/memory-diagnostics.txt | 16 +- inform7/Figures/timings-diagnostics.txt | 30 +- .../Inter/BasicInformKit/Sections/RTP.i6t | 108 +++---- inform7/Tests/Test Makes/Eg4-C/textual.txt | 294 +++++++----------- inform7/runtime-module/Chapter 5/Properties.w | 104 +++---- inter/final-module/Chapter 4/Final Inform 6.w | 115 +++++++ 12 files changed, 574 insertions(+), 481 deletions(-) diff --git a/docs/BasicInformKit/S-rtp.html b/docs/BasicInformKit/S-rtp.html index 73d208dea..fe076da75 100644 --- a/docs/BasicInformKit/S-rtp.html +++ b/docs/BasicInformKit/S-rtp.html @@ -303,41 +303,40 @@ it doesn't mean it actually does have.

-[ WhetherProvides K obj q issue_rtp  a l holder;
-    if (K ~= OBJECT_TY) {
-        if ((obj < 1) || (obj > value_ranges-->K)) {
-            if (issue_rtp) RunTimeProblem(RTP_BADVALUEPROPERTY);
-            rfalse;
-        } else {
-            holder = value_property_holders-->K;
-            if ((holder) && (holder provides q)) rtrue;
+[ ProvidesProperty K obj q issue_rtp  a l holder;
+    if (K == OBJECT_TY) {
+        if (ScanPropertyMetadata(obj, q, 4)) jump PermissionFound;
+        if (obj provides KD_Count) {
+            l = obj.KD_Count;
+            while (l > 0) {
+                a = l*2;
+                if (ScanPropertyMetadata(KindHierarchy-->a, q, 4)) jump PermissionFound;
+                l = KindHierarchy-->(a+1);
+            }
         }
-    }
-    if (obj == 0) {
-        if (issue_rtp) RunTimeProblem(RTP_PROPOFNOTHING, 0, q);
+        if (ScanPropertyMetadata(K0_kind, q, 4)) jump PermissionFound;
+        if (issue_rtp) RunTimeProblem(RTP_UNPROVIDED, obj, q);
         rfalse;
     }
-    if (metaclass(obj) ~= Object) rfalse;
-    if (q<0) q = ~q;
-
-    if (ScanPropertyMetadata(obj, q, 4)) jump PermissionFound;
-    if (obj provides KD_Count) {
-        l = obj.KD_Count;
-        while (l > 0) {
-            a = l*2;
-            if (ScanPropertyMetadata(KindHierarchy-->a, q, 4)) jump PermissionFound;
-            l = KindHierarchy-->(a+1);
-        }
-    }
-    if (ScanPropertyMetadata(K0_kind, q, 4)) jump PermissionFound;
-    if (issue_rtp) RunTimeProblem(RTP_UNPROVIDED, obj, q);
-    rfalse;
 
     .PermissionFound;
-        if (q-->2) rtrue;
-        if (obj provides q) rtrue;
-        if (issue_rtp) RunTimeProblem(RTP_UNSET, obj, q);
-        rfalse;
+
+    @provides_gprop K obj q a;
+    if (a) rtrue;
+if (K ~= OBJECT_TY) {
+	if ((obj >= 1) && (obj <= value_ranges-->K)) {
+		holder = value_property_holders-->K;
+		if ((holder) && (holder provides q)) rtrue;
+	}
+} else {
+	if ((obj) && (metaclass(obj) == Object)) {
+		if (q-->0 == 2) rtrue;
+		if (obj provides q) rtrue;
+	}
+}
+
+    if (issue_rtp) RunTimeProblem(RTP_UNSET, obj, q);
+    rfalse;
 ];
 
 [ PrintPropertyName  p  textual;
@@ -375,18 +374,20 @@ the one which the player is on.
 

-[ GProperty K V pr err holder;
-    if (WhetherProvides(K, V, pr, 1-err)) {
-        if (K == OBJECT_TY) {
-            if (pr-->0 == 2) {
-                if (V has pr) rtrue; rfalse;
-            }
-            if (pr == door_to) return V.pr();
-            return V.pr;
-        } else {
-            holder = value_property_holders-->K;
-            return (holder.pr)-->(V+COL_HSIZE);
-        }
+[ GProperty K V pr err holder val;
+    if (ProvidesProperty(K, V, pr, 1-err)) {
+        @read_gprop K V pr val;
+        return val;
+	if (K == OBJECT_TY) {
+		if (pr-->0 == 2) {
+			if (V has pr) rtrue; rfalse;
+		}
+		if (pr == door_to) return V.pr();
+		return V.pr;
+	} else {
+		holder = value_property_holders-->K;
+		return (holder.pr)-->(V+COL_HSIZE);
+	}
     }
     return 0;
 ];
@@ -398,17 +399,18 @@ converted from an rvalue to an lvalue.
 
 
 [ WriteGProperty K V pr val holder;
-    if (WhetherProvides(K, V, pr, true)) {
-        if (K == OBJECT_TY) {
-            if (pr-->0 == 2) {
-                if (val) give V pr; else give V ~pr;
-            } else {
-                V.pr = val;
-            }
-        } else {
-            holder = value_property_holders-->K;
-            (holder.pr)-->(V+COL_HSIZE) = val;
-        }
+    if (ProvidesProperty(K, V, pr, true)) {
+        @write_gprop K V pr val;
+	if (K == OBJECT_TY) {
+		if (pr-->0 == 2) {
+			if (val) give V pr; else give V ~pr;
+		} else {
+			V.pr = val;
+		}
+	} else {
+		holder = value_property_holders-->K;
+		(holder.pr)-->(V+COL_HSIZE) = val;
+	}
     }
 ];
 
diff --git a/docs/final-module/2-cg.html b/docs/final-module/2-cg.html index 9c750a932..99a7234c6 100644 --- a/docs/final-module/2-cg.html +++ b/docs/final-module/2-cg.html @@ -334,7 +334,7 @@ but for now about 10 layers is plenty.

-segmentation_pos CodeGen::select(code_generation *gen, int i) {
+segmentation_pos CodeGen::select(code_generation *gen, int i) {
     return CodeGen::select_layered(gen, i, 1);
 }
 
@@ -351,7 +351,7 @@ but for now about 10 layers is plenty.
     return previous_pos;
 }
 
-void CodeGen::deselect(code_generation *gen, segmentation_pos saved) {
+void CodeGen::deselect(code_generation *gen, segmentation_pos saved) {
     if (gen->segmentation.temporarily_diverted) internal_error("poorly timed deselection");
     gen->segmentation.pos = saved;
 }
@@ -361,13 +361,13 @@ some temporary stream somewhere. For that, use the following pair:
 

-void CodeGen::select_temporary(code_generation *gen, text_stream *T) {
+void CodeGen::select_temporary(code_generation *gen, text_stream *T) {
     if (gen->segmentation.temporarily_diverted) internal_error("nested temporary segments");
     gen->segmentation.temporarily_diverted_to = T;
     gen->segmentation.temporarily_diverted = TRUE;
 }
 
-void CodeGen::deselect_temporary(code_generation *gen) {
+void CodeGen::deselect_temporary(code_generation *gen) {
     gen->segmentation.temporarily_diverted_to = NULL;
     gen->segmentation.temporarily_diverted = FALSE;
 }
@@ -377,7 +377,7 @@ if it has been "temporarily diverted" then the regiular selection is ignored.
 

-text_stream *CodeGen::current(code_generation *gen) {
+text_stream *CodeGen::current(code_generation *gen) {
     if (gen->segmentation.temporarily_diverted)
         return gen->segmentation.temporarily_diverted_to;
     if (gen->segmentation.pos.current_segment == NULL) return NULL;
@@ -453,7 +453,7 @@ extracted from some Inter instruction.
     Generate from a value pair15.1;
 }
 
-void CodeGen::pair(code_generation *gen, inter_tree_node *P,
+void CodeGen::pair(code_generation *gen, inter_tree_node *P,
     inter_ti val1, inter_ti val2) {
     inter_symbols_table *T = P?(Inter::Packages::scope_of(P)):NULL;
     Generate from a value pair15.1;
diff --git a/docs/final-module/2-cg2.html b/docs/final-module/2-cg2.html
index 28d3fc018..f736613f1 100644
--- a/docs/final-module/2-cg2.html
+++ b/docs/final-module/2-cg2.html
@@ -233,7 +233,7 @@ I6 code. Still, all pragmas are offered to all generators.
 
 VOID_METHOD_TYPE(MANGLE_IDENTIFIER_MTID, code_generator *generator, text_stream *OUT, text_stream *identifier)
-void Generators::mangle(code_generation *gen, text_stream *OUT, text_stream *identifier) {
+void Generators::mangle(code_generation *gen, text_stream *OUT, text_stream *identifier) {
     VOID_METHOD_CALL(gen->generator, MANGLE_IDENTIFIER_MTID, OUT, identifier);
 }
 
diff --git a/docs/final-module/2-tvg.html b/docs/final-module/2-tvg.html index a81209a25..137e0d4bf 100644 --- a/docs/final-module/2-tvg.html +++ b/docs/final-module/2-tvg.html @@ -254,7 +254,7 @@ well the entire tree by the end. define VNODE_ALLC LOOP_THROUGH_INTER_CHILDREN(C, P) Vanilla::node(gen, C)
-void Vanilla::node(code_generation *gen, inter_tree_node *P) {
+void Vanilla::node(code_generation *gen, inter_tree_node *P) {
     switch (P->W.data[ID_IFLD]) {
         case CONSTANT_IST:      VanillaConstants::constant(gen, P); break;
 
diff --git a/docs/final-module/4-fi6.html b/docs/final-module/4-fi6.html
index 576fc1f17..c9850abaf 100644
--- a/docs/final-module/4-fi6.html
+++ b/docs/final-module/4-fi6.html
@@ -146,15 +146,15 @@ function togglePopup(material_id) {
     METHOD_ADD(cgt, EVALUATE_LABEL_MTID, I6Target::evaluate_label);
     METHOD_ADD(cgt, INVOKE_FUNCTION_MTID, I6Target::invoke_function);
     METHOD_ADD(cgt, INVOKE_OPCODE_MTID, I6Target::invoke_opcode);
-    METHOD_ADD(cgt, BEGIN_ARRAY_MTID, I6Target::begin_array);
-    METHOD_ADD(cgt, ARRAY_ENTRY_MTID, I6Target::array_entry);
-    METHOD_ADD(cgt, COMPILE_LITERAL_SYMBOL_MTID, I6Target::compile_literal_symbol);
-    METHOD_ADD(cgt, ARRAY_ENTRIES_MTID, I6Target::array_entries);
-    METHOD_ADD(cgt, END_ARRAY_MTID, I6Target::end_array);
+    METHOD_ADD(cgt, BEGIN_ARRAY_MTID, I6Target::begin_array);
+    METHOD_ADD(cgt, ARRAY_ENTRY_MTID, I6Target::array_entry);
+    METHOD_ADD(cgt, COMPILE_LITERAL_SYMBOL_MTID, I6Target::compile_literal_symbol);
+    METHOD_ADD(cgt, ARRAY_ENTRIES_MTID, I6Target::array_entries);
+    METHOD_ADD(cgt, END_ARRAY_MTID, I6Target::end_array);
     METHOD_ADD(cgt, OFFER_PRAGMA_MTID, I6Target::offer_pragma)
     METHOD_ADD(cgt, END_GENERATION_MTID, I6Target::end_generation);
-    METHOD_ADD(cgt, PSEUDO_OBJECT_MTID, I6Target::pseudo_object);
-    METHOD_ADD(cgt, NEW_ACTION_MTID, I6Target::new_action);
+    METHOD_ADD(cgt, PSEUDO_OBJECT_MTID, I6Target::pseudo_object);
+    METHOD_ADD(cgt, NEW_ACTION_MTID, I6Target::new_action);
     inform6_target = cgt;
 }
 
@@ -1405,6 +1405,9 @@ or implement assembly-language operations like text_stream *opcode, int operand_count, inter_tree_node **operands, inter_tree_node *label, int label_sense, int void_context) { text_stream *OUT = CodeGen::current(gen); + if (Str::eq(opcode, I"@provides_gprop")) Invoke special provides_gprop9.1; + if (Str::eq(opcode, I"@read_gprop")) Invoke special read_gprop9.2; + if (Str::eq(opcode, I"@write_gprop")) Invoke special write_gprop9.3; WRITE("%S", opcode); for (int opc = 0; opc < operand_count; opc++) { WRITE(" "); @@ -1417,7 +1420,133 @@ or implement assembly-language operations like } if (void_context) WRITE(";\n"); } +
+

§9.1. Invoke special provides_gprop9.1 = +

+
+    TEMPORARY_TEXT(K)
+    TEMPORARY_TEXT(obj)
+    TEMPORARY_TEXT(p)
+    TEMPORARY_TEXT(val)
+    CodeGen::select_temporary(gen, K);
+    Vanilla::node(gen, operands[0]);
+    CodeGen::deselect_temporary(gen);
+    CodeGen::select_temporary(gen, obj);
+    Vanilla::node(gen, operands[1]);
+    CodeGen::deselect_temporary(gen);
+    CodeGen::select_temporary(gen, p);
+    Vanilla::node(gen, operands[2]);
+    CodeGen::deselect_temporary(gen);
+    CodeGen::select_temporary(gen, val);
+    Vanilla::node(gen, operands[3]);
+    CodeGen::deselect_temporary(gen);
+
+    WRITE("if (%S == OBJECT_TY) {\n", K);
+    WRITE("    if ((%S) && (metaclass(%S) == Object)) {\n", obj, obj);
+    WRITE("        if ((%S-->0 == 2) || (%S provides %S-->1)) {\n", p, obj, p);
+    WRITE("            %S = 1;\n", val);
+    WRITE("        } else {\n");
+    WRITE("            %S = 0;\n", val);
+    WRITE("        }\n");
+    WRITE("    } else {\n");
+    WRITE("        %S = 0;\n", val);
+    WRITE("    }\n");
+    WRITE("} else {\n");
+    WRITE("    if ((%S >= 1) && (%S <= value_ranges-->%S)) {\n", obj, obj, K);
+    WRITE("        holder = value_property_holders-->%S;\n", K);
+    WRITE("        if ((holder) && (holder provides %S-->1)) {\n", p);
+    WRITE("            %S = 1;\n", val);
+    WRITE("        } else {\n");
+    WRITE("            %S = 0;\n", val);
+    WRITE("        }\n");
+    WRITE("    } else {\n");
+    WRITE("        %S = 0;\n", val);
+    WRITE("    }\n");
+    WRITE("}\n");
+
+    DISCARD_TEXT(K)
+    DISCARD_TEXT(obj)
+    DISCARD_TEXT(p)
+    DISCARD_TEXT(val)
+    return;
+
+
  • This code is used in §9.
+

§9.2. Invoke special read_gprop9.2 = +

+ +
+    TEMPORARY_TEXT(K)
+    TEMPORARY_TEXT(obj)
+    TEMPORARY_TEXT(p)
+    CodeGen::select_temporary(gen, K);
+    Vanilla::node(gen, operands[0]);
+    CodeGen::deselect_temporary(gen);
+    CodeGen::select_temporary(gen, obj);
+    Vanilla::node(gen, operands[1]);
+    CodeGen::deselect_temporary(gen);
+    CodeGen::select_temporary(gen, p);
+    Vanilla::node(gen, operands[2]);
+    CodeGen::deselect_temporary(gen);
+
+    WRITE("if (%S == OBJECT_TY) {\n", K);
+    WRITE("    if (%S-->0 == 2) {\n", p);
+    WRITE("        if (%S has %S-->1) rtrue; rfalse;\n", obj, p);
+    WRITE("    }\n");
+    WRITE("    if (%S == door_to) return (%S-->1).%S();\n", p, obj, p);
+    WRITE("    return %S.(%S-->1);\n", obj, p);
+    WRITE("} else {\n");
+    WRITE("    holder = value_property_holders-->%S;\n", K);
+    WRITE("    return (holder.(%S-->1))-->(%S+COL_HSIZE);\n", p, obj);
+    WRITE("}\n");
+
+    DISCARD_TEXT(K)
+    DISCARD_TEXT(obj)
+    DISCARD_TEXT(p)
+    return;
+
+
  • This code is used in §9.
+

§9.3. Invoke special write_gprop9.3 = +

+ +
+    TEMPORARY_TEXT(K)
+    TEMPORARY_TEXT(obj)
+    TEMPORARY_TEXT(p)
+    TEMPORARY_TEXT(val)
+    CodeGen::select_temporary(gen, K);
+    Vanilla::node(gen, operands[0]);
+    CodeGen::deselect_temporary(gen);
+    CodeGen::select_temporary(gen, obj);
+    Vanilla::node(gen, operands[1]);
+    CodeGen::deselect_temporary(gen);
+    CodeGen::select_temporary(gen, p);
+    Vanilla::node(gen, operands[2]);
+    CodeGen::deselect_temporary(gen);
+    CodeGen::select_temporary(gen, val);
+    Vanilla::node(gen, operands[3]);
+    CodeGen::deselect_temporary(gen);
+
+    WRITE("if (%S == OBJECT_TY) {\n", K);
+    WRITE("    if (%S-->0 == 2) {\n", p);
+    WRITE("        if (%S) give %S %S-->1; else give %S ~(%S-->1);\n", val, obj, p, obj, p);
+    WRITE("    } else {\n");
+    WRITE("        %S.(%S-->1) = %S;\n", obj, p, val);
+    WRITE("    }\n");
+    WRITE("} else {\n");
+    WRITE("    ((value_property_holders-->%S).(%S-->1))-->(%S+COL_HSIZE) = %S;\n", K, p, obj, val);
+    WRITE("}\n");
+
+    DISCARD_TEXT(K)
+    DISCARD_TEXT(obj)
+    DISCARD_TEXT(p)
+    DISCARD_TEXT(val)
+    return;
+
+
  • This code is used in §9.
+

§10.

+ +
 int I6Target::begin_array(code_generator *cgt, code_generation *gen, text_stream *array_name, inter_symbol *array_s, inter_tree_node *P, int format, segmentation_pos *saved) {
     if (saved) {
         int choice = early_matter_I7CGS;
@@ -1466,7 +1595,7 @@ or implement assembly-language operations like                     else if (aliased == verb_directive_creature_symbol) WRITE("creature");
                     else if (aliased == verb_directive_topic_symbol) WRITE("topic");
                     else if (aliased == verb_directive_multiexcept_symbol) WRITE("multiexcept");
-                    else I6Target::compile_literal_symbol(cgt, gen, aliased);
+                    else I6Target::compile_literal_symbol(cgt, gen, aliased);
                 }
             } else {
                 CodeGen::pair(gen, P, val1, val2);
@@ -1496,7 +1625,7 @@ or implement assembly-language operations like     Generators::mangle(gen, OUT, S);
 }
 
-

§10. Alternatively, we can just specify how many entries there will be: they will +

§11. Alternatively, we can just specify how many entries there will be: they will then be initialised to 0.

diff --git a/docs/runtime-module/5-prp.html b/docs/runtime-module/5-prp.html index 7b9f1bbce..07a025326 100644 --- a/docs/runtime-module/5-prp.html +++ b/docs/runtime-module/5-prp.html @@ -126,7 +126,7 @@ package already supplied: return prn->compilation_data.prop_package; } -inter_name *RTProperties::iname(property *prn) { +inter_name *RTProperties::iname(property *prn) { if (prn == NULL) internal_error("tried to find iname for null property"); if ((Properties::is_either_or(prn)) && (prn->compilation_data.store_in_negation)) return RTProperties::iname(EitherOrProperties::get_negation(prn)); @@ -188,7 +188,7 @@ kit, we'll have to use that one.

-int RTProperties::stored_in_negation(property *prn) {
+int RTProperties::stored_in_negation(property *prn) {
     if ((prn == NULL) || (prn->either_or_data == NULL))
         internal_error("non-EO property");
     return prn->compilation_data.store_in_negation;
@@ -367,89 +367,46 @@ and its analogue for writing,     return TRUE;
 }
 
-

§10. Either-or properties are trickier, though only because they use a different -pair of functions at runtime for EO properties of objects than for EO properties -of anything else: +

§10. Either-or properties work analogously, though note that on reading, GProperty +is called slightly differently so that objects are allowed access to read (though +not write) either/or properties which they do not possess. The result is always +false, but run-time errors do not occur. (This all goes back to the way +attributes were handled on the Z-machine VM, but is an assumption made by some +of the kit code inherited from early days of Inform, and does no actual harm.)

 void RTProperties::write_either_or_schemas(adjective_meaning *am, property *prn, int T) {
     kind *K = AdjectiveMeaningDomains::get_kind(am);
-    if (Kinds::Behaviour::is_object(K))
-        Set the schemata for an either/or property adjective with objects as domain10.1
-    else
-        Set the schemata for an either/or property adjective with some other domain10.2;
+    if (RTProperties::stored_in_negation(prn)) {
+        property *neg = EitherOrProperties::get_negation(prn);
+
+        i6_schema *sch = AdjectiveMeanings::make_schema(am, TEST_ATOM_TASK);
+        Calculus::Schemas::modify(sch, "GProperty(%k, *1, %n, 1) == false", K,
+            RTProperties::iname(neg));
+
+        sch = AdjectiveMeanings::make_schema(am, NOW_ATOM_TRUE_TASK);
+        Calculus::Schemas::modify(sch, "WriteGProperty(%k, *1, %n, 0)", K,
+            RTProperties::iname(neg));
+
+        sch = AdjectiveMeanings::make_schema(am, NOW_ATOM_FALSE_TASK);
+        Calculus::Schemas::modify(sch, "WriteGProperty(%k, *1, %n, 1)", K,
+            RTProperties::iname(neg));
+    } else {
+        i6_schema *sch = AdjectiveMeanings::make_schema(am, TEST_ATOM_TASK);
+        Calculus::Schemas::modify(sch, "GProperty(%k, *1, %n, 1)", K,
+            RTProperties::iname(prn));
+
+        sch = AdjectiveMeanings::make_schema(am, NOW_ATOM_TRUE_TASK);
+        Calculus::Schemas::modify(sch, "WriteGProperty(%k, *1, %n, 1)", K,
+            RTProperties::iname(prn));
+
+        sch = AdjectiveMeanings::make_schema(am, NOW_ATOM_FALSE_TASK);
+        Calculus::Schemas::modify(sch, "WriteGProperty(%k, *1, %n, 0)", K,
+            RTProperties::iname(prn));
+    }
 }
 
-

§10.1. The "objects" domain is not really very different, but it's the one used -overwhelmingly most often, so we will call the relevant routines directly rather -than accessing them via the unifying routines GProperty and WriteGProperty — -which would work just as well, but more slowly. -

- -

Set the schemata for an either/or property adjective with objects as domain10.1 = -

- -
-    if (RTProperties::stored_in_negation(prn)) {
-        property *neg = EitherOrProperties::get_negation(prn);
-        inter_name *identifier = RTProperties::iname(neg);
-
-        i6_schema *sch = AdjectiveMeanings::make_schema(am, TEST_ATOM_TASK);
-        Calculus::Schemas::modify(sch, "GProperty(OBJECT_TY, *1, %n, true) == false", identifier);
-
-        sch = AdjectiveMeanings::make_schema(am, NOW_ATOM_TRUE_TASK);
-        Calculus::Schemas::modify(sch, "WriteGProperty(OBJECT_TY, *1, %n, 0)", identifier);
-
-        sch = AdjectiveMeanings::make_schema(am, NOW_ATOM_FALSE_TASK);
-        Calculus::Schemas::modify(sch, "WriteGProperty(OBJECT_TY, *1, %n, 1)", identifier);
-    } else {
-        inter_name *identifier = RTProperties::iname(prn);
-
-        i6_schema *sch = AdjectiveMeanings::make_schema(am, TEST_ATOM_TASK);
-        Calculus::Schemas::modify(sch, "GProperty(OBJECT_TY, *1, %n, true)", identifier);
-
-        sch = AdjectiveMeanings::make_schema(am, NOW_ATOM_TRUE_TASK);
-        Calculus::Schemas::modify(sch, "WriteGProperty(OBJECT_TY, *1, %n, 1)", identifier);
-
-        sch = AdjectiveMeanings::make_schema(am, NOW_ATOM_FALSE_TASK);
-        Calculus::Schemas::modify(sch, "WriteGProperty(OBJECT_TY, *1, %n, 0)", identifier);
-    }
-
-
  • This code is used in §10.
-

§10.2. Set the schemata for an either/or property adjective with some other domain10.2 = -

- -
-    if (RTProperties::stored_in_negation(prn)) {
-        property *neg = EitherOrProperties::get_negation(prn);
-
-        i6_schema *sch = AdjectiveMeanings::make_schema(am, TEST_ATOM_TASK);
-        Calculus::Schemas::modify(sch, "GProperty(%k, *1, %n) == false", K,
-            RTProperties::iname(neg));
-
-        sch = AdjectiveMeanings::make_schema(am, NOW_ATOM_TRUE_TASK);
-        Calculus::Schemas::modify(sch, "WriteGProperty(%k, *1, %n)", K,
-            RTProperties::iname(neg));
-
-        sch = AdjectiveMeanings::make_schema(am, NOW_ATOM_FALSE_TASK);
-        Calculus::Schemas::modify(sch, "WriteGProperty(%k, *1, %n, true)", K,
-            RTProperties::iname(neg));
-    } else {
-        i6_schema *sch = AdjectiveMeanings::make_schema(am, TEST_ATOM_TASK);
-        Calculus::Schemas::modify(sch, "GProperty(%k, *1, %n)", K,
-            RTProperties::iname(prn));
-
-        sch = AdjectiveMeanings::make_schema(am, NOW_ATOM_TRUE_TASK);
-        Calculus::Schemas::modify(sch, "WriteGProperty(%k, *1, %n, true)", K,
-            RTProperties::iname(prn));
-
-        sch = AdjectiveMeanings::make_schema(am, NOW_ATOM_FALSE_TASK);
-        Calculus::Schemas::modify(sch, "WriteGProperty(%k, *1, %n)", K,
-            RTProperties::iname(prn));
-    }
-
-
  • This code is used in §10.

§11. And finally, provision of a property can be tested at runtime with the following schemas:

@@ -468,7 +425,7 @@ following schemas: } else if (Kinds::Behaviour::is_object(K)) { kind *PK = Cinders::kind_of_term(asch->pt1); if (Kinds::get_construct(PK) == CON_property) { - Calculus::Schemas::modify(asch->schema, "WhetherProvides(%k, *1, *2)", K); + Calculus::Schemas::modify(asch->schema, "ProvidesProperty(%k, *1, *2)", K); return TRUE; } } @@ -484,7 +441,7 @@ of object the left operand is, we can only test property provision at run-time:

-    Calculus::Schemas::modify(asch->schema, "WhetherProvides(%k, *1, *2)", K);
+    Calculus::Schemas::modify(asch->schema, "ProvidesProperty(%k, *1, *2)", K);
 
  • This code is used in §11.

§11.2. For all other kinds, type-checking is strong enough that we can prove the diff --git a/inform7/Figures/memory-diagnostics.txt b/inform7/Figures/memory-diagnostics.txt index 5d558d79e..1d785b107 100644 --- a/inform7/Figures/memory-diagnostics.txt +++ b/inform7/Figures/memory-diagnostics.txt @@ -1,6 +1,6 @@ -Total memory consumption was 394323K = 385 MB +Total memory consumption was 394317K = 385 MB -60.6% was used for 2004452 objects, in 372321 frames in 299 x 800K = 239200K = 233 MB: +60.6% was used for 2004468 objects, in 372337 frames in 299 x 800K = 239200K = 233 MB: 10.3% inter_tree_node_array 58 x 8192 = 475136 objects, 41813824 bytes 7.2% text_stream_array 5187 x 100 = 518700 objects, 29213184 bytes @@ -13,7 +13,7 @@ Total memory consumption was 394323K = 385 MB 0.8% inter_name_array 69 x 1000 = 69000 objects, 3314208 bytes 0.6% kind_array 68 x 1000 = 68000 objects, 2722176 bytes 0.5% inter_name_generator_array 53 x 1000 = 53000 objects, 2121696 bytes - 0.5% inter_schema_token 14185 objects, 2042640 bytes + 0.5% inter_schema_token 14197 objects, 2044368 bytes 0.4% inter_package 26565 objects, 1912680 bytes 0.4% package_request 21137 objects, 1860056 bytes 0.4% vocabulary_entry_array 161 x 100 = 16100 objects, 1808352 bytes @@ -30,7 +30,7 @@ Total memory consumption was 394323K = 385 MB 0.2% ptoken 8382 objects, 871728 bytes 0.2% grammatical_usage 3611 objects, 866640 bytes 0.2% individual_form 2561 objects, 860496 bytes - 0.2% inter_schema_node 8905 objects, 854880 bytes + 0.2% inter_schema_node 8909 objects, 855264 bytes 0.1% unary_predicate_array 16 x 1000 = 16000 objects, 640512 bytes 0.1% local_variable_array 47 x 100 = 4700 objects, 452704 bytes ---- scan_directory 94 objects, 388032 bytes @@ -238,7 +238,7 @@ Total memory consumption was 394323K = 385 MB 39.3% was used for memory not allocated for objects: - 20.5% text stream storage 82882584 bytes in 536688 claims + 20.5% text stream storage 82876796 bytes in 536689 claims 4.5% dictionary storage 18271744 bytes in 33265 claims ---- sorting 736 bytes in 3 claims 1.7% source text 7200000 bytes in 3 claims @@ -246,8 +246,8 @@ Total memory consumption was 394323K = 385 MB ---- documentation fragments 262144 bytes in 1 claim ---- linguistic stock array 81920 bytes in 2 claims ---- small word set array 105600 bytes in 22 claims - 1.0% inter symbols storage 4175072 bytes in 27677 claims - 4.1% inter bytecode storage 16802732 bytes in 14 claims + 1.0% inter symbols storage 4174576 bytes in 27676 claims + 4.1% inter bytecode storage 16802744 bytes in 14 claims 4.0% inter links storage 16174208 bytes in 266 claims ---- inter tree location list storage 191232 bytes in 32 claims 0.4% instance-of-kind counting 1695204 bytes in 1 claim @@ -256,5 +256,5 @@ Total memory consumption was 394323K = 385 MB ---- code generation workspace for objects 4128 bytes in 4 claims ---- emitter array storage 161792 bytes in 2062 claims -18.4% was overhead - 74415928 bytes = 72671K = 70 MB +18.4% was overhead - 74413816 bytes = 72669K = 70 MB diff --git a/inform7/Figures/timings-diagnostics.txt b/inform7/Figures/timings-diagnostics.txt index 2d1f7c083..9e28d97e5 100644 --- a/inform7/Figures/timings-diagnostics.txt +++ b/inform7/Figures/timings-diagnostics.txt @@ -1,11 +1,11 @@ 100.0% in inform7 run - 55.0% in compilation to Inter - 39.5% in //Sequence::undertake_queued_tasks// + 55.1% in compilation to Inter + 39.6% in //Sequence::undertake_queued_tasks// 3.5% in //MajorNodes::pre_pass// - 2.6% in //MajorNodes::pass_1// - 2.1% in //RTPhrasebook::compile_entries// - 1.4% in //ImperativeDefinitions::assess_all// - 1.1% in //RTKindConstructors::compile// + 2.5% in //MajorNodes::pass_1// + 2.0% in //RTPhrasebook::compile_entries// + 1.3% in //ImperativeDefinitions::assess_all// + 1.2% in //RTKindConstructors::compile// 0.4% in //ImperativeDefinitions::compile_first_block// 0.4% in //MajorNodes::pass_2// 0.4% in //Sequence::undertake_queued_tasks// @@ -16,22 +16,22 @@ 0.1% in //RTKindConstructors::compile_permissions// 0.1% in //Task::make_built_in_kind_constructors// 0.1% in //World::stages_II_and_III// - 1.6% not specifically accounted for - 43.1% in running Inter pipeline - 12.4% in step preparation + 1.8% not specifically accounted for + 42.9% in running Inter pipeline + 12.5% in step preparation 9.6% in inter step 7/16: consolidate-text - 7.8% in inter step 2/16: link - 6.8% in inter step 16/16: generate inform6 -> auto.inf + 8.0% in inter step 2/16: link + 6.5% in inter step 16/16: generate inform6 -> auto.inf 1.5% in inter step 11/16: make-identifiers-unique 0.4% in inter step 12/16: reconcile-verbs + 0.2% in inter step 10/16: detect-indirect-calls 0.2% in inter step 14/16: eliminate-redundant-operations 0.2% in inter step 6/16: assimilate 0.2% in inter step 8/16: resolve-external-symbols 0.2% in inter step 9/16: inspect-plugs - 0.1% in inter step 10/16: detect-indirect-calls 0.1% in inter step 13/16: eliminate-redundant-labels 0.1% in inter step 4/16: parse-linked-matter 0.1% in inter step 5/16: resolve-conditional-compilation - 2.7% not specifically accounted for - 1.7% in supervisor - 0.2% not specifically accounted for + 2.4% not specifically accounted for + 1.6% in supervisor + 0.3% not specifically accounted for diff --git a/inform7/Internal/Inter/BasicInformKit/Sections/RTP.i6t b/inform7/Internal/Inter/BasicInformKit/Sections/RTP.i6t index cc3006401..7f62a107c 100644 --- a/inform7/Internal/Inter/BasicInformKit/Sections/RTP.i6t +++ b/inform7/Internal/Inter/BasicInformKit/Sections/RTP.i6t @@ -260,41 +260,40 @@ have the property in question at an I6 level -- having permission to have it doesn't mean it actually does have. = -[ WhetherProvides K obj q issue_rtp a l holder; - if (K ~= OBJECT_TY) { - if ((obj < 1) || (obj > value_ranges-->K)) { - if (issue_rtp) RunTimeProblem(RTP_BADVALUEPROPERTY); - rfalse; - } else { - holder = value_property_holders-->K; - if ((holder) && (holder provides q)) rtrue; +[ ProvidesProperty K obj q issue_rtp a l holder; + if (K == OBJECT_TY) { + if (ScanPropertyMetadata(obj, q, 4)) jump PermissionFound; + if (obj provides KD_Count) { + l = obj.KD_Count; + while (l > 0) { + a = l*2; + if (ScanPropertyMetadata(KindHierarchy-->a, q, 4)) jump PermissionFound; + l = KindHierarchy-->(a+1); + } } - } - if (obj == 0) { - if (issue_rtp) RunTimeProblem(RTP_PROPOFNOTHING, 0, q); + if (ScanPropertyMetadata(K0_kind, q, 4)) jump PermissionFound; + if (issue_rtp) RunTimeProblem(RTP_UNPROVIDED, obj, q); rfalse; } - if (metaclass(obj) ~= Object) rfalse; - if (q<0) q = ~q; - - if (ScanPropertyMetadata(obj, q, 4)) jump PermissionFound; - if (obj provides KD_Count) { - l = obj.KD_Count; - while (l > 0) { - a = l*2; - if (ScanPropertyMetadata(KindHierarchy-->a, q, 4)) jump PermissionFound; - l = KindHierarchy-->(a+1); - } - } - if (ScanPropertyMetadata(K0_kind, q, 4)) jump PermissionFound; - if (issue_rtp) RunTimeProblem(RTP_UNPROVIDED, obj, q); - rfalse; .PermissionFound; - if (q-->2) rtrue; - if (obj provides q) rtrue; - if (issue_rtp) RunTimeProblem(RTP_UNSET, obj, q); - rfalse; + + @provides_gprop K obj q a; + if (a) rtrue; +! if (K ~= OBJECT_TY) { +! if ((obj >= 1) && (obj <= value_ranges-->K)) { +! holder = value_property_holders-->K; +! if ((holder) && (holder provides q)) rtrue; +! } +! } else { +! if ((obj) && (metaclass(obj) == Object)) { +! if (q-->0 == 2) rtrue; +! if (obj provides q) rtrue; +! } +! } + + if (issue_rtp) RunTimeProblem(RTP_UNSET, obj, q); + rfalse; ]; [ PrintPropertyName p textual; @@ -331,18 +330,20 @@ this enables it to be an I6 routine returning the other side of the door from the one which the player is on. = -[ GProperty K V pr err holder; - if (WhetherProvides(K, V, pr, 1-err)) { - if (K == OBJECT_TY) { - if (pr-->0 == 2) { - if (V has pr) rtrue; rfalse; - } - if (pr == door_to) return V.pr(); - return V.pr; - } else { - holder = value_property_holders-->K; - return (holder.pr)-->(V+COL_HSIZE); - } +[ GProperty K V pr err holder val; + if (ProvidesProperty(K, V, pr, 1-err)) { + @read_gprop K V pr val; + return val; +! if (K == OBJECT_TY) { +! if (pr-->0 == 2) { +! if (V has pr) rtrue; rfalse; +! } +! if (pr == door_to) return V.pr(); +! return V.pr; +! } else { +! holder = value_property_holders-->K; +! return (holder.pr)-->(V+COL_HSIZE); +! } } return 0; ]; @@ -354,17 +355,18 @@ converted from an rvalue to an lvalue. = [ WriteGProperty K V pr val holder; - if (WhetherProvides(K, V, pr, true)) { - if (K == OBJECT_TY) { - if (pr-->0 == 2) { - if (val) give V pr; else give V ~pr; - } else { - V.pr = val; - } - } else { - holder = value_property_holders-->K; - (holder.pr)-->(V+COL_HSIZE) = val; - } + if (ProvidesProperty(K, V, pr, true)) { + @write_gprop K V pr val; +! if (K == OBJECT_TY) { +! if (pr-->0 == 2) { +! if (val) give V pr; else give V ~pr; +! } else { +! V.pr = val; +! } +! } else { +! holder = value_property_holders-->K; +! (holder.pr)-->(V+COL_HSIZE) = val; +! } } ]; diff --git a/inform7/Tests/Test Makes/Eg4-C/textual.txt b/inform7/Tests/Test Makes/Eg4-C/textual.txt index 087ecd41f..8d1ecdf79 100644 --- a/inform7/Tests/Test Makes/Eg4-C/textual.txt +++ b/inform7/Tests/Test Makes/Eg4-C/textual.txt @@ -6545,9 +6545,9 @@ package main _plain symbol public misc #dictionary_table symbol public misc #grammar_table symbol public misc __assembly_sp `sp` + symbol public misc KindHierarchy symbol public misc value_ranges symbol public misc value_property_holders - symbol public misc KindHierarchy constant String K_unchecked = 0 __veneer=1 constant Routine K_unchecked = 0 __veneer=1 constant self K_unchecked = 0 __veneer=1 @@ -6558,9 +6558,9 @@ package main _plain constant #dictionary_table K_unchecked = 0 __veneer=1 constant #grammar_table K_unchecked = 0 __veneer=1 constant __assembly_sp K_unchecked = 0 __veneer=1 + constant KindHierarchy K_unchecked = 0 __veneer=1 constant value_ranges K_unchecked = 0 __veneer=1 constant value_property_holders K_unchecked = 0 __veneer=1 - constant KindHierarchy K_unchecked = 0 __veneer=1 package basic_inform_by_graham_nelson _module symbol private misc ^category `^category_U1` symbol external misc K_typeless_int --> /main/generic/kinds/K_typeless_int @@ -39392,11 +39392,9 @@ package main _plain symbol socket misc RunTimeError --> /main/connectors/RunTimeError symbol socket misc ArgumentTypeFailed --> /main/connectors/ArgumentTypeFailed symbol socket misc CheckKindReturned --> /main/connectors/CheckKindReturned - symbol socket misc WhetherProvides --> /main/connectors/WhetherProvides + symbol socket misc ProvidesProperty --> /main/connectors/ProvidesProperty symbol socket misc PrintPropertyName --> /main/connectors/PrintPropertyName symbol socket misc ScanPropertyMetadata --> /main/connectors/ScanPropertyMetadata - symbol socket misc GetEitherOrProperty --> /main/connectors/GetEitherOrProperty - symbol socket misc SetEitherOrProperty --> /main/connectors/SetEitherOrProperty symbol socket misc GProperty --> /main/connectors/GProperty symbol socket misc WriteGProperty --> /main/connectors/WriteGProperty symbol socket misc PROPERTY_TY_Say --> /main/connectors/PROPERTY_TY_Say @@ -97061,10 +97059,10 @@ package main _plain inv !return val K_unchecked V constant CheckKindReturned K_unchecked_function = CheckKindReturned_B __assimilated=1 - package WhetherProvides_fn _function - symbol public misc WhetherProvides + package ProvidesProperty_fn _function + symbol public misc ProvidesProperty symbol external misc K_unchecked_function --> /main/generic/kinds/K_unchecked_function - package WhetherProvides_B _code + package ProvidesProperty_B _code symbol private misc K symbol external misc K_unchecked --> /main/generic/kinds/K_unchecked symbol private misc obj @@ -97074,19 +97072,17 @@ package main _plain symbol private misc l symbol private misc holder symbol external misc plug_00140 --> /main/generic/kinds/kind1/OBJECT_TY - symbol external misc value_ranges --> /main/veneer/value_ranges - symbol external misc RunTimeProblem --> /main/BasicInformKit/functions/RunTimeProblem_fn/RunTimeProblem - symbol external misc RTP_BADVALUEPROPERTY --> /main/BasicInformKit/constants/RTP_BADVALUEPROPERTY_con/RTP_BADVALUEPROPERTY - symbol external misc value_property_holders --> /main/veneer/value_property_holders - symbol external misc RTP_PROPOFNOTHING --> /main/BasicInformKit/constants/RTP_PROPOFNOTHING_con/RTP_PROPOFNOTHING - symbol external misc metaclass --> /main/veneer/metaclass - symbol external misc Object --> /main/veneer/Object symbol external misc ScanPropertyMetadata --> /main/BasicInformKit/functions/ScanPropertyMetadata_fn/ScanPropertyMetadata symbol private label .PermissionFound symbol external misc KD_Count --> /main/BasicInformKit/properties/KD_Count_prop/KD_Count symbol external misc KindHierarchy --> /main/veneer/KindHierarchy symbol external misc plug_00165 --> /main/generic/kinds/kind1/K_object + symbol external misc RunTimeProblem --> /main/BasicInformKit/functions/RunTimeProblem_fn/RunTimeProblem symbol external misc RTP_UNPROVIDED --> /main/BasicInformKit/constants/RTP_UNPROVIDED_con/RTP_UNPROVIDED + symbol external misc value_ranges --> /main/veneer/value_ranges + symbol external misc value_property_holders --> /main/veneer/value_property_holders + symbol external misc metaclass --> /main/veneer/metaclass + symbol external misc Object --> /main/veneer/Object symbol external misc RTP_UNSET --> /main/BasicInformKit/constants/RTP_UNSET_con/RTP_UNSET local K K_unchecked local obj K_unchecked @@ -97097,26 +97093,91 @@ package main _plain local holder K_unchecked code inv !if + inv !eq + val K_unchecked K + val K_unchecked OBJECT_TY + code + inv !if + inv ScanPropertyMetadata + val K_unchecked obj + val K_unchecked q + val K_unchecked 4 + code + inv !jump + lab .PermissionFound + inv !if + inv !provides + val K_unchecked obj + val K_unchecked KD_Count + code + inv !store + reference + val K_unchecked l + inv !propertyvalue + val K_unchecked obj + val K_unchecked KD_Count + inv !while + inv !gt + val K_unchecked l + val K_unchecked 0 + code + inv !store + reference + val K_unchecked a + inv !times + val K_unchecked l + val K_unchecked 2 + inv !if + inv ScanPropertyMetadata + inv !lookup + val K_unchecked KindHierarchy + val K_unchecked a + val K_unchecked q + val K_unchecked 4 + code + inv !jump + lab .PermissionFound + inv !store + reference + val K_unchecked l + inv !lookup + val K_unchecked KindHierarchy + inv !plus + val K_unchecked a + val K_unchecked 1 + inv !if + inv ScanPropertyMetadata + val K_unchecked K_object + val K_unchecked q + val K_unchecked 4 + code + inv !jump + lab .PermissionFound + inv !if + val K_unchecked issue_rtp + code + inv RunTimeProblem + val K_unchecked RTP_UNPROVIDED + val K_unchecked obj + val K_unchecked q + inv !return + val K_unchecked 0 + .PermissionFound + inv !ifelse inv !ne val K_unchecked K val K_unchecked OBJECT_TY code - inv !ifelse - inv !or - inv !lt + inv !if + inv !and + inv !ge val K_unchecked obj val K_unchecked 1 - inv !gt + inv !le val K_unchecked obj inv !lookup val K_unchecked value_ranges val K_unchecked K - code - inv !if - val K_unchecked issue_rtp - code - inv RunTimeProblem - val K_unchecked RTP_BADVALUEPROPERTY code inv !store reference @@ -97133,120 +97194,31 @@ package main _plain code inv !return val K_unchecked 1 - inv !return - val K_unchecked 0 - inv !if - inv !eq - val K_unchecked obj - val K_unchecked 0 code inv !if - val K_unchecked issue_rtp - code - inv RunTimeProblem - val K_unchecked RTP_PROPOFNOTHING - val K_unchecked 0 - val K_unchecked q - inv !return - val K_unchecked 0 - inv !if - inv !ne - inv metaclass - val K_unchecked obj - val K_unchecked Object - code - inv !return - val K_unchecked 0 - inv !if - inv !lt - val K_unchecked q - val K_unchecked 0 - code - inv !store - reference - val K_unchecked q - inv !bitwisenot - val K_unchecked q - inv !if - inv ScanPropertyMetadata - val K_unchecked obj - val K_unchecked q - val K_unchecked 4 - code - inv !jump - lab .PermissionFound - inv !if - inv !provides - val K_unchecked obj - val K_unchecked KD_Count - code - inv !store - reference - val K_unchecked l - inv !propertyvalue + inv !and val K_unchecked obj - val K_unchecked KD_Count - inv !while - inv !gt - val K_unchecked l - val K_unchecked 0 + inv !eq + inv metaclass + val K_unchecked obj + val K_unchecked Object code - inv !store - reference - val K_unchecked a - inv !times - val K_unchecked l - val K_unchecked 2 inv !if - inv ScanPropertyMetadata + inv !eq inv !lookup - val K_unchecked KindHierarchy - val K_unchecked a - val K_unchecked q - val K_unchecked 4 + val K_unchecked q + val K_unchecked 0 + val K_unchecked 2 code - inv !jump - lab .PermissionFound - inv !store - reference - val K_unchecked l - inv !lookup - val K_unchecked KindHierarchy - inv !plus - val K_unchecked a + inv !return + val K_unchecked 1 + inv !if + inv !provides + val K_unchecked obj + val K_unchecked q + code + inv !return val K_unchecked 1 - inv !if - inv ScanPropertyMetadata - val K_unchecked K_object - val K_unchecked q - val K_unchecked 4 - code - inv !jump - lab .PermissionFound - inv !if - val K_unchecked issue_rtp - code - inv RunTimeProblem - val K_unchecked RTP_UNPROVIDED - val K_unchecked obj - val K_unchecked q - inv !return - val K_unchecked 0 - .PermissionFound - inv !if - inv !lookup - val K_unchecked q - val K_unchecked 2 - code - inv !return - val K_unchecked 1 - inv !if - inv !provides - val K_unchecked obj - val K_unchecked q - code - inv !return - val K_unchecked 1 inv !if val K_unchecked issue_rtp code @@ -97256,7 +97228,7 @@ package main _plain val K_unchecked q inv !return val K_unchecked 0 - constant WhetherProvides K_unchecked_function = WhetherProvides_B __assimilated=1 + constant ProvidesProperty K_unchecked_function = ProvidesProperty_B __assimilated=1 package PrintPropertyName_fn _function symbol public misc PrintPropertyName symbol external misc K_unchecked_function --> /main/generic/kinds/K_unchecked_function @@ -97326,56 +97298,6 @@ package main _plain inv !return val K_unchecked 0 constant ScanPropertyMetadata K_unchecked_function = ScanPropertyMetadata_B __assimilated=1 - package GetEitherOrProperty_fn _function - symbol public misc GetEitherOrProperty - symbol external misc K_unchecked_function --> /main/generic/kinds/K_unchecked_function - package GetEitherOrProperty_B _code - symbol private misc o - symbol external misc K_unchecked --> /main/generic/kinds/K_unchecked - symbol private misc p - symbol external misc GProperty --> /main/BasicInformKit/functions/GProperty_fn/GProperty - symbol external misc plug_00140 --> /main/generic/kinds/kind1/OBJECT_TY - local o K_unchecked - local p K_unchecked - code - inv !return - inv GProperty - val K_unchecked OBJECT_TY - val K_unchecked o - val K_unchecked p - val K_unchecked 1 - constant GetEitherOrProperty K_unchecked_function = GetEitherOrProperty_B __assimilated=1 - package SetEitherOrProperty_fn _function - symbol public misc SetEitherOrProperty - symbol external misc K_unchecked_function --> /main/generic/kinds/K_unchecked_function - package SetEitherOrProperty_B _code - symbol private misc o - symbol external misc K_unchecked --> /main/generic/kinds/K_unchecked - symbol private misc p - symbol private misc negate - symbol private misc adj - symbol external misc WriteGProperty --> /main/BasicInformKit/functions/WriteGProperty_fn/WriteGProperty - symbol external misc plug_00140 --> /main/generic/kinds/kind1/OBJECT_TY - local o K_unchecked - local p K_unchecked - local negate K_unchecked - local adj K_unchecked - code - inv !ifelse - val K_unchecked negate - code - inv WriteGProperty - val K_unchecked OBJECT_TY - val K_unchecked o - val K_unchecked p - val K_unchecked 0 - code - inv WriteGProperty - val K_unchecked OBJECT_TY - val K_unchecked o - val K_unchecked p - val K_unchecked 1 - constant SetEitherOrProperty K_unchecked_function = SetEitherOrProperty_B __assimilated=1 package GProperty_fn _function symbol public misc GProperty symbol external misc K_unchecked_function --> /main/generic/kinds/K_unchecked_function @@ -97386,7 +97308,7 @@ package main _plain symbol private misc pr symbol private misc err symbol private misc holder - symbol external misc WhetherProvides --> /main/BasicInformKit/functions/WhetherProvides_fn/WhetherProvides + symbol external misc ProvidesProperty --> /main/BasicInformKit/functions/ProvidesProperty_fn/ProvidesProperty symbol external misc plug_00140 --> /main/generic/kinds/kind1/OBJECT_TY symbol external misc door_to --> /main/BasicInformKit/properties/door_to_prop/door_to symbol external misc value_property_holders --> /main/veneer/value_property_holders @@ -97398,7 +97320,7 @@ package main _plain local holder K_unchecked code inv !if - inv WhetherProvides + inv ProvidesProperty val K_unchecked K val K_unchecked V val K_unchecked pr @@ -97468,7 +97390,7 @@ package main _plain symbol private misc pr symbol private misc val symbol private misc holder - symbol external misc WhetherProvides --> /main/BasicInformKit/functions/WhetherProvides_fn/WhetherProvides + symbol external misc ProvidesProperty --> /main/BasicInformKit/functions/ProvidesProperty_fn/ProvidesProperty symbol external misc plug_00140 --> /main/generic/kinds/kind1/OBJECT_TY symbol external misc value_property_holders --> /main/veneer/value_property_holders symbol external misc COL_HSIZE --> /main/BasicInformKit/constants/COL_HSIZE_con/COL_HSIZE @@ -97479,7 +97401,7 @@ package main _plain local holder K_unchecked code inv !if - inv WhetherProvides + inv ProvidesProperty val K_unchecked K val K_unchecked V val K_unchecked pr diff --git a/inform7/runtime-module/Chapter 5/Properties.w b/inform7/runtime-module/Chapter 5/Properties.w index 6f4b2035c..757cee925 100644 --- a/inform7/runtime-module/Chapter 5/Properties.w +++ b/inform7/runtime-module/Chapter 5/Properties.w @@ -268,79 +268,45 @@ int RTProperties::set_property_value_schema(annotated_i6_schema *asch, property return TRUE; } -@ Either-or properties are trickier, though only because they use a different -pair of functions at runtime for EO properties of objects than for EO properties -of anything else: +@ Either-or properties work analogously, though note that on reading, |GProperty| +is called slightly differently so that objects are allowed access to read (though +not write) either/or properties which they do not possess. The result is always +|false|, but run-time errors do not occur. (This all goes back to the way +attributes were handled on the Z-machine VM, but is an assumption made by some +of the kit code inherited from early days of Inform, and does no actual harm.) = void RTProperties::write_either_or_schemas(adjective_meaning *am, property *prn, int T) { kind *K = AdjectiveMeaningDomains::get_kind(am); - if (Kinds::Behaviour::is_object(K)) - @ - else - @; + if (RTProperties::stored_in_negation(prn)) { + property *neg = EitherOrProperties::get_negation(prn); + + i6_schema *sch = AdjectiveMeanings::make_schema(am, TEST_ATOM_TASK); + Calculus::Schemas::modify(sch, "GProperty(%k, *1, %n, 1) == false", K, + RTProperties::iname(neg)); + + sch = AdjectiveMeanings::make_schema(am, NOW_ATOM_TRUE_TASK); + Calculus::Schemas::modify(sch, "WriteGProperty(%k, *1, %n, 0)", K, + RTProperties::iname(neg)); + + sch = AdjectiveMeanings::make_schema(am, NOW_ATOM_FALSE_TASK); + Calculus::Schemas::modify(sch, "WriteGProperty(%k, *1, %n, 1)", K, + RTProperties::iname(neg)); + } else { + i6_schema *sch = AdjectiveMeanings::make_schema(am, TEST_ATOM_TASK); + Calculus::Schemas::modify(sch, "GProperty(%k, *1, %n, 1)", K, + RTProperties::iname(prn)); + + sch = AdjectiveMeanings::make_schema(am, NOW_ATOM_TRUE_TASK); + Calculus::Schemas::modify(sch, "WriteGProperty(%k, *1, %n, 1)", K, + RTProperties::iname(prn)); + + sch = AdjectiveMeanings::make_schema(am, NOW_ATOM_FALSE_TASK); + Calculus::Schemas::modify(sch, "WriteGProperty(%k, *1, %n, 0)", K, + RTProperties::iname(prn)); + } } -@ The "objects" domain is not really very different, but it's the one used -overwhelmingly most often, so we will call the relevant routines directly rather -than accessing them via the unifying routines |GProperty| and |WriteGProperty| -- -which would work just as well, but more slowly. - -@ = - if (RTProperties::stored_in_negation(prn)) { - property *neg = EitherOrProperties::get_negation(prn); - inter_name *identifier = RTProperties::iname(neg); - - i6_schema *sch = AdjectiveMeanings::make_schema(am, TEST_ATOM_TASK); - Calculus::Schemas::modify(sch, "GProperty(OBJECT_TY, *1, %n, true) == false", identifier); - - sch = AdjectiveMeanings::make_schema(am, NOW_ATOM_TRUE_TASK); - Calculus::Schemas::modify(sch, "WriteGProperty(OBJECT_TY, *1, %n, 0)", identifier); - - sch = AdjectiveMeanings::make_schema(am, NOW_ATOM_FALSE_TASK); - Calculus::Schemas::modify(sch, "WriteGProperty(OBJECT_TY, *1, %n, 1)", identifier); - } else { - inter_name *identifier = RTProperties::iname(prn); - - i6_schema *sch = AdjectiveMeanings::make_schema(am, TEST_ATOM_TASK); - Calculus::Schemas::modify(sch, "GProperty(OBJECT_TY, *1, %n, true)", identifier); - - sch = AdjectiveMeanings::make_schema(am, NOW_ATOM_TRUE_TASK); - Calculus::Schemas::modify(sch, "WriteGProperty(OBJECT_TY, *1, %n, 1)", identifier); - - sch = AdjectiveMeanings::make_schema(am, NOW_ATOM_FALSE_TASK); - Calculus::Schemas::modify(sch, "WriteGProperty(OBJECT_TY, *1, %n, 0)", identifier); - } - -@ = - if (RTProperties::stored_in_negation(prn)) { - property *neg = EitherOrProperties::get_negation(prn); - - i6_schema *sch = AdjectiveMeanings::make_schema(am, TEST_ATOM_TASK); - Calculus::Schemas::modify(sch, "GProperty(%k, *1, %n) == false", K, - RTProperties::iname(neg)); - - sch = AdjectiveMeanings::make_schema(am, NOW_ATOM_TRUE_TASK); - Calculus::Schemas::modify(sch, "WriteGProperty(%k, *1, %n)", K, - RTProperties::iname(neg)); - - sch = AdjectiveMeanings::make_schema(am, NOW_ATOM_FALSE_TASK); - Calculus::Schemas::modify(sch, "WriteGProperty(%k, *1, %n, true)", K, - RTProperties::iname(neg)); - } else { - i6_schema *sch = AdjectiveMeanings::make_schema(am, TEST_ATOM_TASK); - Calculus::Schemas::modify(sch, "GProperty(%k, *1, %n)", K, - RTProperties::iname(prn)); - - sch = AdjectiveMeanings::make_schema(am, NOW_ATOM_TRUE_TASK); - Calculus::Schemas::modify(sch, "WriteGProperty(%k, *1, %n, true)", K, - RTProperties::iname(prn)); - - sch = AdjectiveMeanings::make_schema(am, NOW_ATOM_FALSE_TASK); - Calculus::Schemas::modify(sch, "WriteGProperty(%k, *1, %n)", K, - RTProperties::iname(prn)); - } - @ And finally, provision of a property can be tested at runtime with the following schemas: @@ -358,7 +324,7 @@ int RTProperties::test_provision_schema(annotated_i6_schema *asch) { } else if (Kinds::Behaviour::is_object(K)) { kind *PK = Cinders::kind_of_term(asch->pt1); if (Kinds::get_construct(PK) == CON_property) { - Calculus::Schemas::modify(asch->schema, "WhetherProvides(%k, *1, *2)", K); + Calculus::Schemas::modify(asch->schema, "ProvidesProperty(%k, *1, *2)", K); return TRUE; } } @@ -370,7 +336,7 @@ int RTProperties::test_provision_schema(annotated_i6_schema *asch) { of object the left operand is, we can only test property provision at run-time: @ = - Calculus::Schemas::modify(asch->schema, "WhetherProvides(%k, *1, *2)", K); + Calculus::Schemas::modify(asch->schema, "ProvidesProperty(%k, *1, *2)", K); @ For all other kinds, type-checking is strong enough that we can prove the answer now. diff --git a/inter/final-module/Chapter 4/Final Inform 6.w b/inter/final-module/Chapter 4/Final Inform 6.w index 34c91b845..89dd1c085 100644 --- a/inter/final-module/Chapter 4/Final Inform 6.w +++ b/inter/final-module/Chapter 4/Final Inform 6.w @@ -1219,6 +1219,9 @@ void I6Target::invoke_opcode(code_generator *cgt, code_generation *gen, text_stream *opcode, int operand_count, inter_tree_node **operands, inter_tree_node *label, int label_sense, int void_context) { text_stream *OUT = CodeGen::current(gen); + if (Str::eq(opcode, I"@provides_gprop")) @; + if (Str::eq(opcode, I"@read_gprop")) @; + if (Str::eq(opcode, I"@write_gprop")) @; WRITE("%S", opcode); for (int opc = 0; opc < operand_count; opc++) { WRITE(" "); @@ -1232,6 +1235,118 @@ void I6Target::invoke_opcode(code_generator *cgt, code_generation *gen, if (void_context) WRITE(";\n"); } +@ = + TEMPORARY_TEXT(K) + TEMPORARY_TEXT(obj) + TEMPORARY_TEXT(p) + TEMPORARY_TEXT(val) + CodeGen::select_temporary(gen, K); + Vanilla::node(gen, operands[0]); + CodeGen::deselect_temporary(gen); + CodeGen::select_temporary(gen, obj); + Vanilla::node(gen, operands[1]); + CodeGen::deselect_temporary(gen); + CodeGen::select_temporary(gen, p); + Vanilla::node(gen, operands[2]); + CodeGen::deselect_temporary(gen); + CodeGen::select_temporary(gen, val); + Vanilla::node(gen, operands[3]); + CodeGen::deselect_temporary(gen); + + WRITE("if (%S == OBJECT_TY) {\n", K); + WRITE(" if ((%S) && (metaclass(%S) == Object)) {\n", obj, obj); + WRITE(" if ((%S-->0 == 2) || (%S provides %S-->1)) {\n", p, obj, p); + WRITE(" %S = 1;\n", val); + WRITE(" } else {\n"); + WRITE(" %S = 0;\n", val); + WRITE(" }\n"); + WRITE(" } else {\n"); + WRITE(" %S = 0;\n", val); + WRITE(" }\n"); + WRITE("} else {\n"); + WRITE(" if ((%S >= 1) && (%S <= value_ranges-->%S)) {\n", obj, obj, K); + WRITE(" holder = value_property_holders-->%S;\n", K); + WRITE(" if ((holder) && (holder provides %S-->1)) {\n", p); + WRITE(" %S = 1;\n", val); + WRITE(" } else {\n"); + WRITE(" %S = 0;\n", val); + WRITE(" }\n"); + WRITE(" } else {\n"); + WRITE(" %S = 0;\n", val); + WRITE(" }\n"); + WRITE("}\n"); + + DISCARD_TEXT(K) + DISCARD_TEXT(obj) + DISCARD_TEXT(p) + DISCARD_TEXT(val) + return; + +@ = + TEMPORARY_TEXT(K) + TEMPORARY_TEXT(obj) + TEMPORARY_TEXT(p) + CodeGen::select_temporary(gen, K); + Vanilla::node(gen, operands[0]); + CodeGen::deselect_temporary(gen); + CodeGen::select_temporary(gen, obj); + Vanilla::node(gen, operands[1]); + CodeGen::deselect_temporary(gen); + CodeGen::select_temporary(gen, p); + Vanilla::node(gen, operands[2]); + CodeGen::deselect_temporary(gen); + + WRITE("if (%S == OBJECT_TY) {\n", K); + WRITE(" if (%S-->0 == 2) {\n", p); + WRITE(" if (%S has %S-->1) rtrue; rfalse;\n", obj, p); + WRITE(" }\n"); + WRITE(" if (%S == door_to) return (%S-->1).%S();\n", p, obj, p); + WRITE(" return %S.(%S-->1);\n", obj, p); + WRITE("} else {\n"); + WRITE(" holder = value_property_holders-->%S;\n", K); + WRITE(" return (holder.(%S-->1))-->(%S+COL_HSIZE);\n", p, obj); + WRITE("}\n"); + + DISCARD_TEXT(K) + DISCARD_TEXT(obj) + DISCARD_TEXT(p) + return; + +@ = + TEMPORARY_TEXT(K) + TEMPORARY_TEXT(obj) + TEMPORARY_TEXT(p) + TEMPORARY_TEXT(val) + CodeGen::select_temporary(gen, K); + Vanilla::node(gen, operands[0]); + CodeGen::deselect_temporary(gen); + CodeGen::select_temporary(gen, obj); + Vanilla::node(gen, operands[1]); + CodeGen::deselect_temporary(gen); + CodeGen::select_temporary(gen, p); + Vanilla::node(gen, operands[2]); + CodeGen::deselect_temporary(gen); + CodeGen::select_temporary(gen, val); + Vanilla::node(gen, operands[3]); + CodeGen::deselect_temporary(gen); + + WRITE("if (%S == OBJECT_TY) {\n", K); + WRITE(" if (%S-->0 == 2) {\n", p); + WRITE(" if (%S) give %S %S-->1; else give %S ~(%S-->1);\n", val, obj, p, obj, p); + WRITE(" } else {\n"); + WRITE(" %S.(%S-->1) = %S;\n", obj, p, val); + WRITE(" }\n"); + WRITE("} else {\n"); + WRITE(" ((value_property_holders-->%S).(%S-->1))-->(%S+COL_HSIZE) = %S;\n", K, p, obj, val); + WRITE("}\n"); + + DISCARD_TEXT(K) + DISCARD_TEXT(obj) + DISCARD_TEXT(p) + DISCARD_TEXT(val) + return; + +@ = int I6Target::begin_array(code_generator *cgt, code_generation *gen, text_stream *array_name, inter_symbol *array_s, inter_tree_node *P, int format, segmentation_pos *saved) { if (saved) { int choice = early_matter_I7CGS;