- + -

To permit variables to have scopes intermediate between local and global: for example, to be shared by all rules in a given rulebook.

+ +

Shared variables are held in common by all rules in a given rulebook.

-
+
-

§1. Definitions.

+

§1. Introduction. Inform allows some variables to be shared by a number of different rules +(with different stack frames) and yet not be global in scope or permanent +in existence: they are shared by some process carried out by rulebooks. +

+ +

The semantics of shared variables are unusual because rules can be +in multiple rulebooks, or can be moved out of their expected rulebooks. +Their names are therefore not limited in scope — they are global, and +they belong to the same namespace as global variables. But access to them +is restricted to just those rules with permission. +

+ +

Each shared_variable belongs to just one shared_variable_set, but the +code forming the body of a rule may be able to access multiple sets. So +each stack frame has its own shared_variable_access_list of those sets +which it can see. +

+ +

§2. Variables. As can be seen, a shared variable is really just some additional expectations +placed on a global variable: +

-typedef struct stacked_variable {
+typedef struct shared_variable {
+    struct shared_variable_set *owner;  who owns this
     struct wording name;  text of the name
     struct parse_node *assigned_at;  sentence assigning it
     struct nonlocal_variable *underlying_var;  the variable in question
-    int owner_id;  who owns this
     int offset_in_owning_frame;  word offset of storage (counts from 0)
     struct wording match_wording_text;  matching text (relevant for action variables only)
     CLASS_DEFINITION
-} stacked_variable;
-
-typedef struct stacked_variable_set {
-    int no_stvs;
-    int recognition_id;
-    struct linked_list *list_of_stvs;  of stacked_variable
-    struct inter_name *creator_fn_iname;
-    CLASS_DEFINITION
-} stacked_variable_set;
-
-typedef struct stacked_variable_access_list {
-    struct linked_list *sets;  of stacked_variable_set
-    CLASS_DEFINITION
-} stacked_variable_access_list;
+} shared_variable;
 
-
  • The structure stacked_variable is accessed in 4/cii, 4/cste and here.
  • The structure stacked_variable_set is private to this section.
  • The structure stacked_variable_access_list is private to this section.
-

§2.

+
  • The structure shared_variable is accessed in 4/cii, 4/cste and here.
+

§3. And it can only be created within a set: +

-int max_frame_size_needed = 0;
+shared_variable *SharedVariables::new(shared_variable_set *set, wording W, kind *K) {
+    shared_variable *shv = CREATE(shared_variable);
+    W = Articles::remove_the(W);
+    shv->name = W;
+    shv->owner = set;
+    shv->offset_in_owning_frame = LinkedLists::len(set->variables);
+    shv->assigned_at = current_sentence;
+    shv->match_wording_text = EMPTY_WORDING;
+    nonlocal_variable *nlv = NonlocalVariables::new(W, K, shv);
+    shv->underlying_var = nlv;
+    RTVariables::set_I6_identifier(nlv, FALSE, RTVariables::shv_rvalue(shv));
+    RTVariables::set_I6_identifier(nlv, TRUE, RTVariables::shv_lvalue(shv));
+    SharedVariables::add_to_set(shv, set);
+    return shv;
+}
 
-

§3.

+

§4. Some miscellaneous access functions: +

-int StackedVariables::get_owner_id(stacked_variable *stv) {
-    return stv->owner_id;
+int SharedVariables::get_owner_id(shared_variable *shv) {
+    return shv->owner->recognition_id;
 }
 
-int StackedVariables::get_offset(stacked_variable *stv) {
-    return stv->offset_in_owning_frame;
+int SharedVariables::get_offset(shared_variable *shv) {
+    return shv->offset_in_owning_frame;
 }
 
-kind *StackedVariables::get_kind(stacked_variable *stv) {
-    nonlocal_variable *nlv = StackedVariables::get_variable(stv);
+kind *SharedVariables::get_kind(shared_variable *shv) {
+    nonlocal_variable *nlv = SharedVariables::get_variable(shv);
     return NonlocalVariables::kind(nlv);
 }
 
-nonlocal_variable *StackedVariables::get_variable(stacked_variable *stv) {
-    if (stv == NULL) return NULL;
-    return stv->underlying_var;
+nonlocal_variable *SharedVariables::get_variable(shared_variable *shv) {
+    if (shv == NULL) return NULL;
+    return shv->underlying_var;
+}
+
+

§5. The match text associated with a shared variable is used in parsing action +patterns: see Action Name Lists (in if). But for most shared variables, this +text remains empty. +

+ +
+void SharedVariables::set_matching_text(shared_variable *shv, wording W) {
+    shv->match_wording_text = W;
 }
 
-void StackedVariables::set_matching_text(stacked_variable *stv, wording W) {
-    stv->match_wording_text = W;
+wording SharedVariables::get_matching_text(shared_variable *shv) {
+    return shv->match_wording_text;
 }
+
+

§6. Sets. Sets are identified at run-time by an ID number, the "recognition ID", which +must be unique to that set and also small enough to be stored in what might +only be a 16-bit unsigned integer. +

-wording StackedVariables::get_matching_text(stacked_variable *stv) { - return stv->match_wording_text; -} +
+typedef struct shared_variable_set {
+    int recognition_id;
+    struct inter_name *creator_fn_iname;
+    struct linked_list *variables;  of shared_variable
+    CLASS_DEFINITION
+} shared_variable_set;
 
-stacked_variable *StackedVariables::parse_match_clause(stacked_variable_set *set,
-    wording W) {
-    stacked_variable *stv;
-    LOOP_OVER_LINKED_LIST(stv, stacked_variable, set->list_of_stvs)
-        if (Wordings::starts_with(W, stv->match_wording_text))
-            return stv;
-    return NULL;
-}
-
-stacked_variable_set *StackedVariables::new_set(int id) {
-    stacked_variable_set *set = CREATE(stacked_variable_set);
+shared_variable_set *SharedVariables::new_set(int id) {
+    shared_variable_set *set = CREATE(shared_variable_set);
     set->recognition_id = id;
-    set->no_stvs = 0;
-    set->list_of_stvs = NEW_LINKED_LIST(stacked_variable);
+    set->variables = NEW_LINKED_LIST(shared_variable);
     set->creator_fn_iname = NULL;
     return set;
 }
 
-int StackedVariables::set_empty(stacked_variable_set *set) {
-    if (set->no_stvs == 0) return TRUE;
+int SharedVariables::set_empty(shared_variable_set *set) {
+    if (LinkedLists::len(set->variables) == 0) return TRUE;
     return FALSE;
 }
 
-stacked_variable *StackedVariables::add_empty(stacked_variable_set *set,
-    wording W, kind *K) {
-    stacked_variable *stv = CREATE(stacked_variable);
-    nonlocal_variable *q;
-    W = Articles::remove_the(W);
-    stv->name = W;
-    stv->owner_id = set->recognition_id;
-    stv->offset_in_owning_frame = set->no_stvs++;
-    stv->assigned_at = current_sentence;
-    stv->match_wording_text = EMPTY_WORDING;
-    ADD_TO_LINKED_LIST(stv, stacked_variable, set->list_of_stvs);
-    if (set->no_stvs > max_frame_size_needed)
-        max_frame_size_needed = set->no_stvs;
-    q = NonlocalVariables::new_with_scope(W, K, stv);
-    stv->underlying_var = q;
-    RTVariables::set_I6_identifier(q, FALSE, RTVariables::stv_rvalue(stv));
-    RTVariables::set_I6_identifier(q, TRUE, RTVariables::stv_lvalue(stv));
-    return stv;
+int size_of_largest_set = 0;
+
+void SharedVariables::add_to_set(shared_variable *shv, shared_variable_set *set) {
+    ADD_TO_LINKED_LIST(shv, shared_variable, set->variables);
+    if (LinkedLists::len(set->variables) > size_of_largest_set)
+        size_of_largest_set = LinkedLists::len(set->variables);
 }
 
-stacked_variable_access_list *StackedVariables::new_access_list(void) {
-    stacked_variable_access_list *nstvol = CREATE(stacked_variable_access_list);
-    nstvol->sets = NEW_LINKED_LIST(stacked_variable_set);
-    return nstvol;
+int SharedVariables::size_of_largest_set(void) {
+    return size_of_largest_set;
 }
+
+
  • The structure shared_variable_set is private to this section.
+

§7. The creator function claims memory to store these variables, and initialises +them, at runtime. Other parts of Inform creating sets are expected to set this +function name (and thus specify where in the Inter hierarchy it will go), and +also to call RTVariables::compile_frame_creator. +

-void StackedVariables::add_set_to_access_list(stacked_variable_access_list *access, - stacked_variable_set *set) { +
+void SharedVariables::set_frame_creator(shared_variable_set *set, inter_name *iname) {
+    set->creator_fn_iname = iname;
+}
+inter_name *SharedVariables::frame_creator(shared_variable_set *set) {
+    return set->creator_fn_iname;
+}
+
+

§8. Returns the first variable in the set whose matching text begins W. Note +that this requires the match text to be nonempty, so it can only return +variables which have one. +

+ +
+shared_variable *SharedVariables::parse_match_clause(shared_variable_set *set,
+    wording W) {
+    shared_variable *shv;
+    LOOP_OVER_LINKED_LIST(shv, shared_variable, set->variables)
+        if (Wordings::starts_with(W, shv->match_wording_text))
+            return shv;
+    return NULL;
+}
+
+

§9. Access lists. These could hardly be simpler: +

+ +
+typedef struct shared_variable_access_list {
+    struct linked_list *sets;  of shared_variable_set
+    CLASS_DEFINITION
+} shared_variable_access_list;
+
+shared_variable_access_list *SharedVariables::new_access_list(void) {
+    shared_variable_access_list *nshvol = CREATE(shared_variable_access_list);
+    nshvol->sets = NEW_LINKED_LIST(shared_variable_set);
+    return nshvol;
+}
+
+
  • The structure shared_variable_access_list is private to this section.
+

§10. Duplicates are not allowed: +

+ +
+void SharedVariables::add_set_to_access_list(shared_variable_access_list *access,
+    shared_variable_set *set) {
     if (access) {
-        stacked_variable_set *existing;
-        LOOP_OVER_LINKED_LIST(existing, stacked_variable_set, access->sets)
+        shared_variable_set *existing;
+        LOOP_OVER_LINKED_LIST(existing, shared_variable_set, access->sets)
             if (existing == set)
                 return;
-        ADD_TO_LINKED_LIST(set, stacked_variable_set, access->sets);
+        ADD_TO_LINKED_LIST(set, shared_variable_set, access->sets);
     }
 }
+
+

§11. This changes access to the union of access and extras: +

-void StackedVariables::append_access_list(stacked_variable_access_list *access, - stacked_variable_access_list *extras) { - stacked_variable_set *set; +
+void SharedVariables::append_access_list(shared_variable_access_list *access,
+    shared_variable_access_list *extras) {
+    shared_variable_set *set;
     if ((extras) && (access))
-        LOOP_OVER_LINKED_LIST(set, stacked_variable_set, extras->sets)
-            StackedVariables::add_set_to_access_list(access, set);
+        LOOP_OVER_LINKED_LIST(set, shared_variable_set, extras->sets)
+            SharedVariables::add_set_to_access_list(access, set);
 }
+
+

§12. Returns the first shared variable of the given name W in any set in the +access list. This would be inefficient if access lists were ever large, or +if individual sets were, but they are not. Giving each access list its own +associative hash would make little or no saving of time, and would decrease +the predictability of results. +

-void StackedVariables::index_owner(OUTPUT_STREAM, stacked_variable_set *set) { - stacked_variable *stv; - LOOP_OVER_LINKED_LIST(stv, stacked_variable, set->list_of_stvs) - if (stv->underlying_var) { - HTML::open_indented_p(OUT, 2, "tight"); - IXVariables::index_one(OUT, stv->underlying_var); - HTML_CLOSE("p"); - } -} - -stacked_variable *StackedVariables::parse_from_access_list(stacked_variable_access_list *access, +
+shared_variable *SharedVariables::parse_from_access_list(shared_variable_access_list *access,
     wording W) {
     if (Wordings::empty(W)) return NULL;
     W = Articles::remove_the(W);
-    stacked_variable_set *set;
+    shared_variable_set *set;
     if (access)
-        LOOP_OVER_LINKED_LIST(set, stacked_variable_set, access->sets) {
-            stacked_variable *stv = StackedVariables::parse_from_list(set->list_of_stvs, W);
-            if (stv) return stv;
+        LOOP_OVER_LINKED_LIST(set, shared_variable_set, access->sets) {
+            shared_variable *shv;
+            LOOP_OVER_LINKED_LIST(shv, shared_variable, set->variables)
+                if (Wordings::match(shv->name, W))
+                    return shv;
         }
     return NULL;
 }
-
-stacked_variable *StackedVariables::parse_from_list(linked_list *stvl, wording W) {
-    stacked_variable *stv;
-    LOOP_OVER_LINKED_LIST(stv, stacked_variable, stvl)
-        if (Wordings::match(stv->name, W))
-            return stv;
-    return NULL;
-}
-
-int StackedVariables::compile_frame_creator(stacked_variable_set *set, inter_name *iname) {
-    if (set == NULL) return 0;
-
-    packaging_state save = Routines::begin(iname);
-    inter_symbol *pos_s = LocalVariables::add_named_call_as_symbol(I"pos");
-    inter_symbol *state_s = LocalVariables::add_named_call_as_symbol(I"state");
-
-    Produce::inv_primitive(Emit::tree(), IFELSE_BIP);
-    Produce::down(Emit::tree());
-        Produce::inv_primitive(Emit::tree(), EQ_BIP);
-        Produce::down(Emit::tree());
-            Produce::val_symbol(Emit::tree(), K_value, state_s);
-            Produce::val(Emit::tree(), K_number, LITERAL_IVAL, 1);
-        Produce::up(Emit::tree());
-        Produce::code(Emit::tree());
-        Produce::down(Emit::tree());
-            Compile frame creator if state is set3.1;
-        Produce::up(Emit::tree());
-        Produce::code(Emit::tree());
-        Produce::down(Emit::tree());
-            Compile frame creator if state is clear3.2;
-        Produce::up(Emit::tree());
-    Produce::up(Emit::tree());
-
-    int count = LinkedLists::len(set->list_of_stvs);
-
-    Produce::inv_primitive(Emit::tree(), RETURN_BIP);
-    Produce::down(Emit::tree());
-        Produce::val(Emit::tree(), K_number, LITERAL_IVAL, (inter_ti) count);
-    Produce::up(Emit::tree());
-
-    Routines::end(save);
-    set->creator_fn_iname = iname;
-    return count;
-}
-
-

§3.1. Compile frame creator if state is set3.1 = -

- -
-    stacked_variable *stv;
-    LOOP_OVER_LINKED_LIST(stv, stacked_variable, set->list_of_stvs) {
-        nonlocal_variable *q = StackedVariables::get_variable(stv);
-        kind *K = NonlocalVariables::kind(q);
-        Produce::inv_primitive(Emit::tree(), STORE_BIP);
-        Produce::down(Emit::tree());
-            Produce::inv_primitive(Emit::tree(), LOOKUPREF_BIP);
-            Produce::down(Emit::tree());
-                Produce::val_iname(Emit::tree(), K_value, Hierarchy::find(MSTACK_HL));
-                Produce::val_symbol(Emit::tree(), K_value, pos_s);
-            Produce::up(Emit::tree());
-            if (Kinds::Behaviour::uses_pointer_values(K))
-                RTKinds::emit_heap_allocation(RTKinds::make_heap_allocation(K, 1, -1));
-            else
-                RTVariables::emit_initial_value_as_val(q);
-        Produce::up(Emit::tree());
-
-        Produce::inv_primitive(Emit::tree(), POSTINCREMENT_BIP);
-        Produce::down(Emit::tree());
-            Produce::ref_symbol(Emit::tree(), K_value, pos_s);
-        Produce::up(Emit::tree());
-    }
-
-
  • This code is used in §3.
-

§3.2. Compile frame creator if state is clear3.2 = -

- -
-    stacked_variable *stv;
-    LOOP_OVER_LINKED_LIST(stv, stacked_variable, set->list_of_stvs) {
-        nonlocal_variable *q = StackedVariables::get_variable(stv);
-        kind *K = NonlocalVariables::kind(q);
-        if (Kinds::Behaviour::uses_pointer_values(K)) {
-            Produce::inv_call_iname(Emit::tree(), Hierarchy::find(BLKVALUEFREE_HL));
-            Produce::down(Emit::tree());
-                Produce::inv_primitive(Emit::tree(), LOOKUP_BIP);
-                Produce::down(Emit::tree());
-                    Produce::val_iname(Emit::tree(), K_value, Hierarchy::find(MSTACK_HL));
-                    Produce::val_symbol(Emit::tree(), K_value, pos_s);
-                Produce::up(Emit::tree());
-            Produce::up(Emit::tree());
-        }
-        Produce::inv_primitive(Emit::tree(), POSTINCREMENT_BIP);
-        Produce::down(Emit::tree());
-            Produce::ref_symbol(Emit::tree(), K_value, pos_s);
-        Produce::up(Emit::tree());
-    }
-
-
  • This code is used in §3.
-

§4.

- -
-inter_name *StackedVariables::frame_creator(stacked_variable_set *set) {
-    return set->creator_fn_iname;
-}