mirror of
https://github.com/ganelson/inform.git
synced 2024-07-18 06:54:26 +03:00
129 lines
5.5 KiB
OpenEdge ABL
129 lines
5.5 KiB
OpenEdge ABL
[EliminateRedundantMatterStage::] Eliminate Redundant Matter Stage.
|
|
|
|
To remove definitions which are never used: for example, functions which are
|
|
never called or referred to.
|
|
|
|
@ Experience shows that around 20 per cent of the code generated by //inform7//
|
|
and, especially, //inter// consists of functions which are never in fact needed.
|
|
(A kit, of its nature, is a library of code: some will be useful, some not, in
|
|
any given circumstance. Many Inform 7 works will never need to sort a table,
|
|
for example.)
|
|
|
|
This stage removes everything that isn't used.
|
|
|
|
NB: At present (January 2022) it doesn't work on some test cases, so it's not
|
|
included in the standard pipeline.
|
|
|
|
=
|
|
void EliminateRedundantMatterStage::create_pipeline_stage(void) {
|
|
ParsingPipelines::new_stage(I"eliminate-redundant-matter",
|
|
EliminateRedundantMatterStage::run, NO_STAGE_ARG, FALSE);
|
|
}
|
|
|
|
int EliminateRedundantMatterStage::run(pipeline_step *step) {
|
|
inter_tree *I = step->ephemera.tree;
|
|
InterTree::traverse(I, EliminateRedundantMatterStage::preserver, step, NULL, PACKAGE_IST);
|
|
InterTree::traverse(I, EliminateRedundantMatterStage::destroyer, step, NULL, PACKAGE_IST);
|
|
return TRUE;
|
|
}
|
|
|
|
@ We operate on a presumption of guilt: any package which we cannot prove is
|
|
needed will be deleted. |Main_fn| is clearly needed, since it is where
|
|
execution will begin. A handful of other functions, not called yet but
|
|
needed in the final compilation stage (and which replace stubs which would
|
|
otherwise be provided by the veneer), must also be included. Command
|
|
packages contain grammar for command verbs typed at run-time: these affect
|
|
an essential data structure (i.e., the parser grammar) implicitly, and so
|
|
we can't detect the dependency here. So we require all command packages to
|
|
be included.
|
|
|
|
=
|
|
void EliminateRedundantMatterStage::preserver(inter_tree *I, inter_tree_node *P, void *state) {
|
|
pipeline_step *step = (pipeline_step *) state;
|
|
inter_package *pack = PackageInstruction::at_this_head(P);
|
|
inter_symbol *ptype = InterPackage::type(pack);
|
|
if (ptype == RunningPipelines::get_symbol(step, command_ptype_RPSYM))
|
|
EliminateRedundantMatterStage::preserve(pack, step, NULL, I"it's a _command package");
|
|
else if (ptype == RunningPipelines::get_symbol(step, property_ptype_RPSYM)) {
|
|
text_stream *N = InterPackage::name(pack);
|
|
if (Str::eq(N, I"workflag_prop"))
|
|
EliminateRedundantMatterStage::preserve(pack, step, NULL, I"it's workflag");
|
|
if (Str::eq(N, I"pluralname_prop"))
|
|
EliminateRedundantMatterStage::preserve(pack, step, NULL, I"it's pluralname");
|
|
if (Str::eq(N, I"ambigpluralname_prop"))
|
|
EliminateRedundantMatterStage::preserve(pack, step, NULL, I"it's ambigpluralname");
|
|
if (Str::eq(N, I"proper_prop"))
|
|
EliminateRedundantMatterStage::preserve(pack, step, NULL, I"it's proper");
|
|
}
|
|
else if (ptype == RunningPipelines::get_symbol(step, function_ptype_RPSYM)) {
|
|
text_stream *N = InterPackage::name(pack);
|
|
if (Str::eq(N, I"Main_fn"))
|
|
EliminateRedundantMatterStage::preserve(pack, step, NULL, I"it's Main");
|
|
if (Str::eq(N, I"MistakeActionSub_fn"))
|
|
EliminateRedundantMatterStage::preserve(pack, step, NULL, I"it's MistakeActionSub");
|
|
if (Str::eq(N, I"TestScriptSub_fn"))
|
|
EliminateRedundantMatterStage::preserve(pack, step, NULL, I"it's TestScriptSub");
|
|
}
|
|
}
|
|
|
|
@ Once you need a package, what else do you need?
|
|
|
|
=
|
|
void EliminateRedundantMatterStage::preserve(inter_package *pack, pipeline_step *step,
|
|
inter_package *witness, text_stream *reason) {
|
|
if ((pack->package_flags) & USED_PACKAGE_FLAG) return;
|
|
pack->package_flags |= USED_PACKAGE_FLAG;
|
|
if (witness) {
|
|
LOGIF(ELIMINATION, "Need $6 because of $6 (because %S)\n", pack, witness, reason);
|
|
} else {
|
|
LOGIF(ELIMINATION, "Need $6 (because %S)\n", pack, reason);
|
|
}
|
|
@<If you need a package, you need its parent@>;
|
|
@<If you need a package, you need its external dependencies@>;
|
|
@<If you need a function or action, you need its internal resources@>;
|
|
}
|
|
|
|
@<If you need a package, you need its parent@> =
|
|
inter_package *parent = InterPackage::parent(pack);
|
|
if (parent) EliminateRedundantMatterStage::preserve(parent, step, pack,
|
|
I"it's the parent");
|
|
|
|
@<If you need a package, you need its external dependencies@> =
|
|
inter_symbols_table *tab = InterPackage::scope(pack);
|
|
LOOP_OVER_SYMBOLS_TABLE(symb, tab) {
|
|
if (Wiring::is_wired(symb)) {
|
|
inter_symbol *E = Wiring::cable_end(symb);
|
|
inter_package *needed = InterSymbol::package(E);
|
|
EliminateRedundantMatterStage::preserve(needed, step, pack,
|
|
I"it's an external symbol");
|
|
}
|
|
}
|
|
|
|
@<If you need a function or action, you need its internal resources@> =
|
|
text_stream *rationale = NULL;
|
|
inter_symbol *ptype = InterPackage::type(pack);
|
|
if (ptype == RunningPipelines::get_symbol(step, function_ptype_RPSYM))
|
|
rationale = I"it's a _function block";
|
|
if (ptype == RunningPipelines::get_symbol(step, action_ptype_RPSYM))
|
|
rationale = I"it's an _action subpackage";
|
|
if (rationale) {
|
|
inter_tree_node *D = InterPackage::head(pack);
|
|
LOOP_THROUGH_INTER_CHILDREN(C, D)
|
|
if (Inode::is(C, PACKAGE_IST)) {
|
|
inter_package *P = PackageInstruction::at_this_head(C);
|
|
EliminateRedundantMatterStage::preserve(P, step, pack, rationale);
|
|
}
|
|
}
|
|
|
|
@ Whatever has not been preserved, is now destroyed.
|
|
|
|
=
|
|
void EliminateRedundantMatterStage::destroyer(inter_tree *I, inter_tree_node *P, void *state) {
|
|
inter_package *pack = PackageInstruction::at_this_head(P);
|
|
if ((pack) && ((pack->package_flags & USED_PACKAGE_FLAG) == 0)) {
|
|
LOGIF(ELIMINATION, "Striking unused package $6 (type %S)\n",
|
|
pack, InterSymbol::identifier(InterPackage::type(pack)));
|
|
NodePlacement::remove(P);
|
|
}
|
|
}
|