1
0
Fork 0
mirror of https://github.com/ganelson/inform.git synced 2024-07-03 07:24:58 +03:00
inform7/inter/pipeline-module/Chapter 4/Make Identifiers Unique Stage.w
2022-02-03 19:44:57 +00:00

99 lines
3.4 KiB
OpenEdge ABL

[MakeIdentifiersUniqueStage::] Make Identifiers Unique Stage.
To make sure certain symbol names translate into globally unique target symbols.
@ Inter frequently contains multiple symbols with different meanings but the
same name: for example, the active part of a function package is referred to
with the symbol |call|, so Inter trees tend to be full of symbols called that.
This overlap of names is not convenient when we eventually generate code from
the Inter tree: we want different meanings to produce different "translated"
names. (Recall that a symbol has a "translated" name as well as its real name;
the "translated" name is the identifier used for it in the code we generated.)
So the following gives unique translated names to symbols marked with the
|MAKE_NAME_UNIQUE| bit. So for example
= (text)
NAME MAKE_NAME_UNIQUE TRANSLATION
call TRUE --
call TRUE --
example FALSE --
call TRUE --
=
will become
= (text)
NAME MAKE_NAME_UNIQUE TRANSLATION
call FALSE call_U1
call FALSE call_U2
example FALSE --
call FALSE call_U3
=
Only the translation changes, not the name itself, which remains |call|.
Note that this operation is done at the end of linking because these |call|
symbols (or whatever) may occur in multiple compilation units; it would be no
good to uniquely number them within each kit, for example, because then each
kit would have its own |call_U1|, causing a collision.
=
void MakeIdentifiersUniqueStage::create_pipeline_stage(void) {
ParsingPipelines::new_stage(I"make-identifiers-unique",
MakeIdentifiersUniqueStage::run_pipeline_stage, NO_STAGE_ARG, FALSE);
}
int MakeIdentifiersUniqueStage::run_pipeline_stage(pipeline_step *step) {
inter_tree *I = step->ephemera.tree;
dictionary *D = Dictionaries::new(16, FALSE);
InterTree::traverse(I, MakeIdentifiersUniqueStage::visitor, D, NULL, 0);
return TRUE;
}
@ The dictionary efficiently connects names such as |call| to an integer count
for each one, but //foundation// does not provide dictionaries from texts to
integers, only to structures allocated by the memory manager: so we must use
the following.
=
typedef struct uniqueness_count {
int count;
CLASS_DEFINITION
} uniqueness_count;
@ Note that if |S| is equated to some other symbol, then its translated
name will never matter, because identifiers in the eventual code will come
from the symbol |S| is equated to. So we needn't bother to have a unique
translation in that case.
=
void MakeIdentifiersUniqueStage::visitor(inter_tree *I, inter_tree_node *P, void *state) {
dictionary *D = (dictionary *) state;
if (P->W.instruction[ID_IFLD] == PACKAGE_IST) {
inter_package *Q = InterPackage::at_this_head(P);
inter_symbols_table *ST = InterPackage::scope(Q);
LOOP_OVER_SYMBOLS_TABLE(S, ST) {
if ((Wiring::is_wired(S) == FALSE) &&
(InterSymbol::get_flag(S, MAKE_NAME_UNIQUE))) {
@<Give this symbol a unique translation@>;
InterSymbol::clear_flag(S, MAKE_NAME_UNIQUE);
}
}
}
}
@<Give this symbol a unique translation@> =
text_stream *N = S->symbol_name;
uniqueness_count *U = NULL;
if (Dictionaries::find(D, N)) {
U = (uniqueness_count *) Dictionaries::read_value(D, N);
} else {
U = CREATE(uniqueness_count);
U->count = 0;
Dictionaries::create(D, N);
Dictionaries::write_value(D, N, (void *) U);
}
U->count++;
TEMPORARY_TEXT(T)
WRITE_TO(T, "%S_U%d", N, U->count);
InterSymbol::set_translate(S, T);
DISCARD_TEXT(T)