1
0
Fork 0
mirror of https://github.com/ganelson/inform.git synced 2024-07-06 00:54:21 +03:00
inform7/inter/pipeline-module/Chapter 6/Eliminate Redundant Matter Stage.w
2022-02-03 15:51:44 +00:00

130 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 = InterPackage::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 = Inter::Symbols::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 (C->W.instruction[ID_IFLD] == PACKAGE_IST) {
inter_package *P = InterPackage::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 = InterPackage::at_this_head(P);
if ((pack) && ((pack->package_flags & USED_PACKAGE_FLAG) == 0)) {
LOGIF(ELIMINATION, "Striking unused package $6 (type %S)\n",
pack, InterPackage::type(pack)->symbol_name);
NodePlacement::remove(P);
}
}