1
0
Fork 0
mirror of https://github.com/ganelson/inform.git synced 2024-07-05 16:44:21 +03:00
inform7/inter/bytecode-module/Chapter 2/Inter Trees.w

279 lines
9 KiB
OpenEdge ABL
Raw Normal View History

2021-04-16 00:42:28 +03:00
[InterTree::] Inter Trees.
2019-02-05 02:44:07 +02:00
2019-07-24 22:29:29 +03:00
To manage tree structures of inter code, and manage the movement of nodes
within these trees.
2019-02-05 02:44:07 +02:00
2022-01-25 02:20:07 +02:00
@ An //inter_tree// expresses a single program: see //What This Module Does//
for more. At first sight, it's a very small object, but |root_node| leads
to a massive tree structure, and the |inter_warehouse| and |building_site|
compoments can also be huge. Note that the latter is managed entirely by
the //building// module, but that everything else here is ours.
2022-01-05 01:10:34 +02:00
2019-02-05 02:44:07 +02:00
=
typedef struct inter_tree {
2019-07-24 20:15:07 +03:00
struct inter_tree_node *root_node;
struct inter_package *root_package;
2022-01-25 02:20:07 +02:00
struct inter_warehouse *housed;
unsigned int history_bits;
struct building_site site;
2020-05-09 15:07:39 +03:00
CLASS_DEFINITION
} inter_tree;
2019-02-05 02:44:07 +02:00
@ =
2021-04-16 00:42:28 +03:00
inter_tree *InterTree::new(void) {
inter_tree *I = CREATE(inter_tree);
2022-01-25 02:20:07 +02:00
@<Make the warehouse@>;
@<Make the root node and the root package@>;
I->history_bits = 0;
InterTree::set_history(I, CREATED_ITHBIT);
BuildingModule::clear_data(I);
return I;
}
@ This must be done first, since we can't make symbols tables without it:
@<Make the warehouse@> =
2019-07-24 22:29:29 +03:00
I->housed = Inter::Warehouse::new();
2022-01-25 02:20:07 +02:00
@ Now a delicate little dance. The entire content of the tree is contained
inside a special "root package". Packages are visible from the outside but
not the inside, so the root package is effectively invisible: nothing is
outside it. This is why it has no name, and is never referred to by Inter
code written out in textual form. In any case, special restrictions apply
to it, and calling //Inter::Packages::make_rootlike// causes those to be
enforced.
Every package has a "head node": the content of the package will be the
children and descendants of that node. The root node for the tree is by
definition the head node for the root package of the tree.
|N| here is the warehouse ID number for the global symbols table of the tree,
which is by definition the symbols table for the root package.
@<Make the root node and the root package@> =
2020-07-01 02:58:55 +03:00
inter_ti N = Inter::Warehouse::create_symbols_table(I->housed);
2019-07-24 22:29:29 +03:00
inter_symbols_table *globals = Inter::Warehouse::get_symbols_table(I->housed, N);
2020-07-01 02:58:55 +03:00
inter_ti root_package_ID = Inter::Warehouse::create_package(I->housed, I);
2019-07-24 22:29:29 +03:00
I->root_package = Inter::Warehouse::get_package(I->housed, root_package_ID);
2022-01-25 02:20:07 +02:00
I->root_node = Inode::new_root_node(I->housed, I);
2019-07-26 12:14:17 +03:00
I->root_package->package_head = I->root_node;
Inter::Packages::make_rootlike(I->root_package);
Inter::Packages::set_scope(I->root_package, globals);
2019-07-24 22:29:29 +03:00
I->root_node->package = I->root_package;
Inter::Warehouse::attribute_resource(I->housed, N, I->root_package);
2019-02-05 02:44:07 +02:00
2022-01-25 02:20:07 +02:00
@ =
2021-04-16 00:42:28 +03:00
inter_package *InterTree::root_package(inter_tree *I) {
2019-07-24 22:29:29 +03:00
if (I) return I->root_package;
return NULL;
}
2022-01-25 02:20:07 +02:00
inter_symbols_table *InterTree::global_scope(inter_tree *I) {
return Inter::Packages::scope(I->root_package);
}
2021-04-16 00:42:28 +03:00
inter_warehouse *InterTree::warehouse(inter_tree *I) {
2019-07-24 22:29:29 +03:00
return I->housed;
2019-02-05 02:44:07 +02:00
}
2022-01-25 02:20:07 +02:00
@h Walking along branches of the tree.
For operations on individual nodes, including how to create them, see
//Inter Nodes//. Here, we provide functions for walking through the nodes,
making use of the tree structure between them.
2019-02-05 02:44:07 +02:00
2022-01-25 02:20:07 +02:00
=
2021-04-16 00:42:28 +03:00
inter_tree_node *InterTree::previous(inter_tree_node *F) {
2019-07-24 20:15:07 +03:00
if (F == NULL) return NULL;
return F->previous_itn;
2019-02-05 02:44:07 +02:00
}
2021-04-16 00:42:28 +03:00
inter_tree_node *InterTree::next(inter_tree_node *F) {
2019-07-24 20:15:07 +03:00
if (F == NULL) return NULL;
return F->next_itn;
2019-02-05 02:44:07 +02:00
}
2021-04-16 00:42:28 +03:00
inter_tree_node *InterTree::first_child(inter_tree_node *F) {
if (F == NULL) return NULL;
2019-07-24 20:15:07 +03:00
return F->first_child_itn;
2019-02-05 02:44:07 +02:00
}
2021-04-16 00:42:28 +03:00
inter_tree_node *InterTree::second_child(inter_tree_node *P) {
2019-07-24 20:15:07 +03:00
if (P == NULL) return NULL;
P = P->first_child_itn;
if (P == NULL) return NULL;
return P->next_itn;
}
2021-04-16 00:42:28 +03:00
inter_tree_node *InterTree::third_child(inter_tree_node *P) {
2019-07-24 20:15:07 +03:00
if (P == NULL) return NULL;
P = P->first_child_itn;
if (P == NULL) return NULL;
P = P->next_itn;
if (P == NULL) return NULL;
return P->next_itn;
}
2021-04-16 00:42:28 +03:00
inter_tree_node *InterTree::fourth_child(inter_tree_node *P) {
2019-07-24 20:15:07 +03:00
if (P == NULL) return NULL;
P = P->first_child_itn;
if (P == NULL) return NULL;
P = P->next_itn;
if (P == NULL) return NULL;
P = P->next_itn;
if (P == NULL) return NULL;
return P->next_itn;
2019-02-05 02:44:07 +02:00
}
2021-04-16 00:42:28 +03:00
inter_tree_node *InterTree::fifth_child(inter_tree_node *P) {
2019-07-24 20:15:07 +03:00
if (P == NULL) return NULL;
P = P->first_child_itn;
if (P == NULL) return NULL;
P = P->next_itn;
if (P == NULL) return NULL;
P = P->next_itn;
if (P == NULL) return NULL;
P = P->next_itn;
if (P == NULL) return NULL;
return P->next_itn;
2019-02-05 02:44:07 +02:00
}
2021-04-16 00:42:28 +03:00
inter_tree_node *InterTree::sixth_child(inter_tree_node *P) {
2019-07-24 20:15:07 +03:00
if (P == NULL) return NULL;
P = P->first_child_itn;
if (P == NULL) return NULL;
P = P->next_itn;
if (P == NULL) return NULL;
P = P->next_itn;
if (P == NULL) return NULL;
P = P->next_itn;
if (P == NULL) return NULL;
P = P->next_itn;
if (P == NULL) return NULL;
return P->next_itn;
2019-02-05 02:44:07 +02:00
}
2021-04-16 00:42:28 +03:00
inter_tree_node *InterTree::last_child(inter_tree_node *F) {
2019-07-24 22:29:29 +03:00
if (F == NULL) return NULL;
return F->last_child_itn;
}
2019-07-24 20:15:07 +03:00
2021-04-16 00:42:28 +03:00
inter_tree_node *InterTree::parent(inter_tree_node *F) {
2019-07-24 22:29:29 +03:00
if (F == NULL) return NULL;
return F->parent_itn;
}
2022-01-25 02:20:07 +02:00
@ Accessing child nodes one by one -- //InterTree::third_child//, etc. --
can only take you so far. Here's a convenient fast way to loop through:
@d LOOP_THROUGH_INTER_CHILDREN(F, P)
for (inter_tree_node *F = InterTree::first_child(P); F; F = InterTree::next(F))
@ If we want to do this more slowly, making sure that severing the current
node won't cause the loop to terminate early:
@d PROTECTED_LOOP_THROUGH_INTER_CHILDREN(F, P)
for (inter_tree_node *F = InterTree::first_child(P), *FN = F?(InterTree::next(F)):NULL;
F; F = FN, FN = FN?(InterTree::next(FN)):NULL)
@h Traversing an entire tree.
The following traverses through all of the root nodes of a tree, calling the
|visitor| function on each node matching the given type filter. If |filter|
is 0, that's every node; if it is something like |PACKAGE_IST|, then it
visits only nodes of type |PACKAGE_IST|; if it is |-PACKAGE_IST|, it visits
only nodes of types other than |PACKAGE_IST|.
|state| is opaque to us, and is a way for the caller to have persistent state
across visits to different nodes.
=
void InterTree::traverse_root_only(inter_tree *from,
void (*visitor)(inter_tree *, inter_tree_node *, void *),
void *state, int filter) {
PROTECTED_LOOP_THROUGH_INTER_CHILDREN(P, from->root_node) {
if ((filter == 0) ||
((filter > 0) && (P->W.data[ID_IFLD] == (inter_ti) filter)) ||
((filter < 0) && (P->W.data[ID_IFLD] != (inter_ti) -filter)))
(*visitor)(from, P, state);
}
}
@ This is similar, but begins at the root of the package |mp|, and recurses
downwards through it and all its subpackages. If |mp| is null, recursion is
from the tree's |/main| package. Note that this does not visit nodes at the
root level, for which see above.
The same filter conventions apply.
=
void InterTree::traverse(inter_tree *from,
void (*visitor)(inter_tree *, inter_tree_node *, void *),
void *state, inter_package *mp, int filter) {
if (mp == NULL) mp = LargeScale::main_package_if_it_exists(from);
if (mp) {
inter_tree_node *D = Inter::Packages::definition(mp);
if ((filter == 0) ||
((filter > 0) && (D->W.data[ID_IFLD] == (inter_ti) filter)) ||
((filter < 0) && (D->W.data[ID_IFLD] != (inter_ti) -filter)))
(*visitor)(from, D, state);
InterTree::traverse_r(from, D, visitor, state, filter);
}
}
void InterTree::traverse_r(inter_tree *from, inter_tree_node *P,
void (*visitor)(inter_tree *, inter_tree_node *, void *),
void *state, int filter) {
PROTECTED_LOOP_THROUGH_INTER_CHILDREN(C, P) {
if ((filter == 0) ||
((filter > 0) && (C->W.data[ID_IFLD] == (inter_ti) filter)) ||
((filter < 0) && (C->W.data[ID_IFLD] != (inter_ti) -filter)))
(*visitor)(from, C, state);
InterTree::traverse_r(from, C, visitor, state, filter);
}
}
@ It is also convenient to provide a way to loop through the subpackages of
a package.
@d LOOP_THROUGH_SUBPACKAGES(entry, pack, ptype)
inter_symbol *pack##wanted =
(pack)?(LargeScale::package_type(pack->package_head->tree, ptype)):NULL;
if (pack)
LOOP_THROUGH_INTER_CHILDREN(C, Inter::Packages::definition(pack))
if ((C->W.data[ID_IFLD] == PACKAGE_IST) &&
(entry = Inter::Package::defined_by_frame(C)) &&
(Inter::Packages::type(entry) == pack##wanted))
@ As a demonstration of this in action:
=
int InterTree::no_subpackages(inter_package *pack, text_stream *ptype) {
int N = 0;
if (pack) {
inter_package *entry;
LOOP_THROUGH_SUBPACKAGES(entry, pack, ptype) N++;
}
return N;
}
@h History of a tree.
2022-01-26 00:51:12 +02:00
In 1964, a Nevada geologist felled a bristlecone pine and was dismayed to find
2022-01-25 02:20:07 +02:00
that it contained 4862 rings, and had therefore germinated in around 2900 BC.
Inter trees also record their history, though can safely accommodate only 32
different events, identified as flag bits 0 to 31.
2019-07-24 20:15:07 +03:00
2022-01-25 02:20:07 +02:00
Calling |InterTree::set_history(I, B)| sets flag |B|; |InterTree::test_history|
then tests it. There is purposely no way to clear these flags once set. They
should only be used to record that irrevocable, one-time-only, things have
been done.
2019-07-24 20:15:07 +03:00
2022-01-25 02:20:07 +02:00
@e CREATED_ITHBIT from 0
2019-07-24 20:15:07 +03:00
=
2022-01-25 02:20:07 +02:00
void InterTree::set_history(inter_tree *I, int bit) {
I->history_bits |= (1 << bit);
2019-07-13 19:15:26 +03:00
}
2022-01-25 02:20:07 +02:00
int InterTree::test_history(inter_tree *I, int bit) {
if (I->history_bits & (1 << bit)) return TRUE;
return FALSE;
2021-07-24 20:16:56 +03:00
}