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 4/Shorten Wiring Stage.w
2022-02-03 15:51:44 +00:00

113 lines
4.1 KiB
OpenEdge ABL

[ShortenWiringStage::] Shorten Wiring Stage.
To catch missing resources with suitable errors, to remove plugs and sockets
as no longer necessary, and to shorten wiring as much as possible.
@ =
void ShortenWiringStage::create_pipeline_stage(void) {
ParsingPipelines::new_stage(I"shorten-wiring",
ShortenWiringStage::run, NO_STAGE_ARG, FALSE);
}
@ In practice, linking errors can occur when the source text refers to a function
which doesn't exist in any kit: if the user has mistyped |ExmapleKitFunction|, say,
then the plug would never find a socket with a matching name. We want to catch
and report these errors efficiently, so we keep the bad names in both a dictionary
(for quick lookup) and a list (for reporting).
=
typedef struct plug_inspection_state {
struct dictionary *bad_plugs;
struct linked_list *bad_plug_names; /* of |text_stream| */
} plug_inspection_state;
int ShortenWiringStage::run(pipeline_step *step) {
inter_tree *I = step->ephemera.tree;
@<Shorten the wiring and report loose plugs@>;
inter_package *connectors = LargeScale::connectors_package_if_it_exists(I);
if (connectors) @<Remove the now unnecessary plugs and sockets@>;
return TRUE;
}
@<Shorten the wiring and report loose plugs@> =
plug_inspection_state state;
state.bad_plugs = Dictionaries::new(16, FALSE);
state.bad_plug_names = NEW_LINKED_LIST(text_stream);
InterTree::traverse(I, ShortenWiringStage::visitor, &state, NULL, PACKAGE_IST);
if (LinkedLists::len(state.bad_plug_names) > 0) {
TEMPORARY_TEXT(NS)
text_stream *N;
LOOP_OVER_LINKED_LIST(N, text_stream, state.bad_plug_names) {
if (Str::len(NS) > 0) WRITE_TO(NS, ", ");
WRITE_TO(NS, "%S", N);
}
PipelineErrors::error_with(step,
"unable to find definitions for the following name(s): %S", NS);
DISCARD_TEXT(NS)
return FALSE;
}
@ Note that it is not necessarily an error to have a loose plug, that is, a plug
which does not connect to any socket. It is only an error if a symbol is trying
to connect to this plug. So we make a traverse of the tree to look for such symbols.
Note that we also take the opportunity to simplify chains of equations down to just
the minimum. For example, if we have |S1 -> S2 -> plug -> socket -> T1 -> T2 -> T3|,
we simplify just to |S1 -> T3|.
=
void ShortenWiringStage::visitor(inter_tree *I, inter_tree_node *P, void *v_state) {
plug_inspection_state *state = (plug_inspection_state *) v_state;
inter_package *Q = InterPackage::at_this_head(P);
inter_symbols_table *ST = InterPackage::scope(Q);
LOOP_OVER_SYMBOLS_TABLE(S, ST) {
inter_symbol *E = Wiring::cable_end(S);
if (S != E) {
Wiring::shorten_wiring(S);
if (Wiring::is_loose_plug(E))
@<This is an error, because a loose plug has been used@>;
}
}
}
@<This is an error, because a loose plug has been used@> =
text_stream *N = Wiring::plug_name(E);
if (Dictionaries::find(state->bad_plugs, N) == NULL) {
Dictionaries::create(state->bad_plugs, N);
ADD_TO_LINKED_LIST(N, text_stream, state->bad_plug_names);
}
@ At this point there will be plugs with no incoming connections, but which
are each wired to sockets. Removing the plugs first then leaves the sockets
with no incoming connections either, and so the sockets can go too.
The result should be a completely empty |connectors| module.
@<Remove the now unnecessary plugs and sockets@> =
inter_symbols_table *ST = InterPackage::scope(connectors);
@<Remove plugs with no incoming connections@>;
@<Remove sockets with no incoming connections@>;
@<Report any remaining symbols in this table as errors@>;
@<Remove plugs with no incoming connections@> =
LOOP_OVER_SYMBOLS_TABLE(S, ST) {
if ((Wiring::is_plug(S)) && (Wiring::has_no_incoming_connections(S)))
InterSymbolsTable::remove_symbol(S);
}
@<Remove sockets with no incoming connections@> =
LOOP_OVER_SYMBOLS_TABLE(S, ST) {
if ((Wiring::is_socket(S)) && (Wiring::has_no_incoming_connections(S)))
InterSymbolsTable::remove_symbol(S);
}
@ This should never happen:
@<Report any remaining symbols in this table as errors@> =
int errors = 0;
LOOP_OVER_SYMBOLS_TABLE(S, ST) {
LOG("Connector not deleted: %3\n", S);
errors++;
}
if (errors > 0) internal_error("plugs and sockets mismanaged");