mirror of
https://github.com/ganelson/inform.git
synced 2024-07-08 01:54:21 +03:00
177 lines
5.9 KiB
OpenEdge ABL
177 lines
5.9 KiB
OpenEdge ABL
[InterBookmark::] Bookmarks.
|
|
|
|
Write positions for inter code being generated.
|
|
|
|
@ A bookmark does not record an actual position in an Inter tree -- if we needed
|
|
that, a pointer to the relevant |inter_tree_node| would do fine -- but to a
|
|
hypothetical position. It describes where to put a node which has not yet been
|
|
put into position.
|
|
|
|
It does this by recording not only a reference node |R| but a relationship
|
|
which the hypothetical new position will have with respect to it:
|
|
|
|
@e BEFORE_NODEPLACEMENT from 0
|
|
@e AFTER_NODEPLACEMENT
|
|
@e IMMEDIATELY_AFTER_NODEPLACEMENT
|
|
@e AS_FIRST_CHILD_OF_NODEPLACEMENT
|
|
@e AS_LAST_CHILD_OF_NODEPLACEMENT
|
|
|
|
=
|
|
typedef struct inter_bookmark {
|
|
struct inter_tree_node *R;
|
|
int placement_wrt_R; /* one of the |*_NODEPLACEMENT| values */
|
|
} inter_bookmark;
|
|
|
|
@ Bookmarks are used to mark positions in an Inter tree, though they are often
|
|
used in a way which causes them to move forwards through that tree, much as
|
|
a bookmark will migrate through a book as it is slowly read.
|
|
|
|
Because of this, the bookmark structure is one of the few in the Inform tool
|
|
chain to be used sometimes as a value and sometimes a reference -- that is,
|
|
we make use both of |inter_bookmark| and |inter_bookmark *| as types. So a
|
|
function which simply needs to know where to do something will take the
|
|
type |inter_bookmark| as an argument -- see //NodePlacement::move_to//, for
|
|
example -- whereas a function which does something but then nudges the
|
|
bookmark onwards will take an |inter_bookmark *|, as in the caee of
|
|
//NodePlacement::move_to_moving_bookmark//.
|
|
|
|
Dereferencing a bookmark pointer to a bookmark value is called taking a
|
|
"snapshot". The idea is that the original is likely to move on, but we want
|
|
to preserve the position it is currently at. For clarity of the code, we
|
|
give this a name as a function:
|
|
|
|
=
|
|
inter_bookmark InterBookmark::snapshot(inter_bookmark *IBM) {
|
|
return *IBM;
|
|
}
|
|
|
|
@ We can also take a snapshot but change the placement:
|
|
|
|
=
|
|
inter_bookmark InterBookmark::shifted(inter_bookmark *IBM, int new_placement) {
|
|
inter_bookmark new_IBM = InterBookmark::snapshot(IBM);
|
|
new_IBM.placement_wrt_R = new_placement;
|
|
return new_IBM;
|
|
}
|
|
|
|
@ Of course, we can only snapshot a bookmark already existing somewhere else,
|
|
so we still need creator functions:
|
|
|
|
=
|
|
inter_bookmark InterBookmark::at_start_of_this_repository(inter_tree *I) {
|
|
return InterBookmark::after_this_node(I->root_node);
|
|
}
|
|
|
|
inter_bookmark InterBookmark::after_this_node(inter_tree_node *D) {
|
|
return InterBookmark::new(D, AFTER_NODEPLACEMENT);
|
|
}
|
|
|
|
inter_bookmark InterBookmark::at_end_of_root(inter_tree *I) {
|
|
return InterBookmark::last_child_of(I->root_node);
|
|
}
|
|
|
|
inter_bookmark InterBookmark::at_end_of_this_package(inter_package *pack) {
|
|
if (pack == NULL) internal_error("no package supplied");
|
|
return InterBookmark::last_child_of(InterPackage::head(pack));
|
|
}
|
|
|
|
inter_bookmark InterBookmark::last_child_of(inter_tree_node *D) {
|
|
return InterBookmark::new(D, AS_LAST_CHILD_OF_NODEPLACEMENT);
|
|
}
|
|
|
|
inter_bookmark InterBookmark::immediately_after(inter_tree_node *D) {
|
|
return InterBookmark::new(D, IMMEDIATELY_AFTER_NODEPLACEMENT);
|
|
}
|
|
|
|
inter_bookmark InterBookmark::first_child_of(inter_tree_node *D) {
|
|
return InterBookmark::new(D, AS_FIRST_CHILD_OF_NODEPLACEMENT);
|
|
}
|
|
|
|
inter_bookmark InterBookmark::new(inter_tree_node *D, int placement) {
|
|
if (D == NULL) internal_error("no node in bookmark");
|
|
inter_bookmark IBM;
|
|
IBM.R = D;
|
|
IBM.placement_wrt_R = placement;
|
|
return IBM;
|
|
}
|
|
|
|
@ Note that this moves the bookmark, not whatever node in the tree the bookmark
|
|
is (or was) marking.
|
|
|
|
=
|
|
void InterBookmark::move_into_package(inter_bookmark *IBM, inter_package *P) {
|
|
if (IBM == NULL) internal_error("no bookmark supplied");
|
|
if (P == NULL) internal_error("invalid package supplied");
|
|
inter_tree_node *D = InterPackage::head(P);
|
|
if (D == NULL) D = InterPackage::tree(P)->root_node;
|
|
if (InterTree::last_child(D)) {
|
|
IBM->R = InterTree::last_child(D);
|
|
IBM->placement_wrt_R = AFTER_NODEPLACEMENT;
|
|
} else {
|
|
IBM->R = D;
|
|
IBM->placement_wrt_R = AS_FIRST_CHILD_OF_NODEPLACEMENT;
|
|
}
|
|
}
|
|
|
|
@ Following the same conventions, this function returns the package into which
|
|
a node moved to the bookmark would then live. In particular,
|
|
|InterBookmark::package(InterBookmark::move_into_package(IBM, P))| is always
|
|
equal to |P|.
|
|
|
|
=
|
|
inter_package *InterBookmark::package(inter_bookmark *IBM) {
|
|
if (IBM == NULL) return NULL;
|
|
inter_package *pack = IBM->R->package;
|
|
if ((IBM->placement_wrt_R == AS_FIRST_CHILD_OF_NODEPLACEMENT) ||
|
|
(IBM->placement_wrt_R == AS_LAST_CHILD_OF_NODEPLACEMENT)) {
|
|
inter_package *R_defined = PackageInstruction::at_this_head(IBM->R);
|
|
if (R_defined) pack = R_defined;
|
|
}
|
|
return pack;
|
|
}
|
|
|
|
@ Some convenience functions:
|
|
|
|
=
|
|
inter_tree *InterBookmark::tree(inter_bookmark *IBM) {
|
|
if (IBM == NULL) return NULL;
|
|
return IBM->R->tree;
|
|
}
|
|
|
|
inter_warehouse *InterBookmark::warehouse(inter_bookmark *IBM) {
|
|
return InterTree::warehouse(InterBookmark::tree(IBM));
|
|
}
|
|
|
|
int InterBookmark::baseline(inter_bookmark *IBM) {
|
|
inter_package *pack = InterBookmark::package(IBM);
|
|
if (pack) return InterPackage::baseline(pack);
|
|
return 0;
|
|
}
|
|
|
|
inter_symbols_table *InterBookmark::scope(inter_bookmark *IBM) {
|
|
inter_package *pack = InterBookmark::package(IBM);
|
|
if (pack) return InterPackage::scope(pack);
|
|
return InterTree::global_scope(InterBookmark::tree(IBM));
|
|
}
|
|
|
|
@ Logging:
|
|
|
|
=
|
|
void InterBookmark::log(OUTPUT_STREAM, void *virs) {
|
|
inter_bookmark *IBM = (inter_bookmark *) virs;
|
|
if (IBM == NULL) WRITE("<null-bookmark>");
|
|
else {
|
|
LOG("<");
|
|
switch (IBM->placement_wrt_R) {
|
|
case BEFORE_NODEPLACEMENT: WRITE("before:"); break;
|
|
case AFTER_NODEPLACEMENT: WRITE("after:"); break;
|
|
case IMMEDIATELY_AFTER_NODEPLACEMENT: WRITE("immediately-after:"); break;
|
|
case AS_FIRST_CHILD_OF_NODEPLACEMENT: WRITE("first-child:"); break;
|
|
case AS_LAST_CHILD_OF_NODEPLACEMENT: WRITE("last-child:"); break;
|
|
default: WRITE("?:"); break;
|
|
}
|
|
if (IBM->R) WRITE("%d", IBM->R->W.index); else WRITE("<NO-NODE>");
|
|
LOG("(%d)>", InterBookmark::baseline(IBM));
|
|
}
|
|
}
|