1
0
Fork 0
mirror of https://github.com/ganelson/inform.git synced 2024-07-08 18:14:21 +03:00
inform7/inter/bytecode-module/Chapter 2/Transmigration.w

294 lines
12 KiB
OpenEdge ABL
Raw Normal View History

2019-08-02 20:51:21 +03:00
[Inter::Transmigration::] Transmigration.
To move packages between repositories.
2022-02-04 02:55:12 +02:00
@
=
typedef struct transmigration_data {
int link_time;
struct inter_symbol *linked_to;
} transmigration_data;
transmigration_data Inter::Transmigration::new_transmigration_data(inter_symbol *S) {
transmigration_data td;
td.link_time = 0;
td.linked_to = NULL;
return td;
}
2019-08-02 20:51:21 +03:00
int ipct_cache_count = 0;
void Inter::Transmigration::cache(inter_symbol *S, inter_symbol *V) {
2022-02-04 02:55:12 +02:00
S->transmigration.linked_to = V;
S->transmigration.link_time = ipct_cache_count;
2019-08-02 20:51:21 +03:00
}
inter_symbol *Inter::Transmigration::cached_equivalent(inter_symbol *S) {
2022-02-04 02:55:12 +02:00
if (S->transmigration.link_time == ipct_cache_count) return S->transmigration.linked_to;
2019-08-02 20:51:21 +03:00
return NULL;
}
void Inter::Transmigration::move(inter_package *migrant, inter_package *destination, int tidy_origin) {
2022-02-03 01:35:38 +02:00
inter_package *P = migrant; while (P) P = InterPackage::parent(P); /* make names exist */
2022-01-31 01:49:12 +02:00
inter_tree *origin_tree = InterPackage::tree(migrant);
inter_tree *destination_tree = InterPackage::tree(destination);
inter_package *origin = InterPackage::parent(migrant);
2020-01-12 02:35:36 +02:00
inter_bookmark deletion_point, insertion_point, primitives_point, ptypes_point;
2019-08-02 20:51:21 +03:00
@<Create these bookmarks@>;
@<Mark the insertion and deletion points with comments@>;
@<Physically move the subtree to its new home@>;
@<Correct any references from the migrant to the origin@>;
if (tidy_origin) @<Correct any references from the origin to the migrant@>;
inter_package *connectors = LargeScale::connectors_package_if_it_exists(origin_tree);
if (connectors) {
2022-01-31 01:49:12 +02:00
inter_symbols_table *T = InterPackage::scope(connectors);
if (T == NULL) internal_error("package with no symbols");
2022-02-03 17:51:44 +02:00
LOOP_OVER_SYMBOLS_TABLE(symb, T) {
2022-02-04 12:04:41 +02:00
if (InterSymbol::is_socket(symb)) {
2022-01-04 01:40:23 +02:00
inter_symbol *target = Wiring::cable_end(symb);
inter_package *target_package = InterSymbol::package(target);
while ((target_package) && (target_package != migrant)) {
2022-01-31 01:49:12 +02:00
target_package = InterPackage::parent(target_package);
}
if (target_package == migrant) {
LOGIF(INTER_CONNECTORS, "Origin offers socket inside migrant: $3 == $3\n", symb, target);
2022-01-04 01:40:23 +02:00
inter_symbol *equivalent = Wiring::find_socket(destination_tree, symb->symbol_name);
if (equivalent) {
2022-01-04 01:40:23 +02:00
inter_symbol *e_target = Wiring::cable_end(equivalent);
if (!InterSymbol::is_defined(e_target)) {
2022-01-04 01:40:23 +02:00
LOGIF(INTER_CONNECTORS, "Able to match with $3 ~~> $3\n", equivalent, Wiring::cable_end(equivalent));
Wiring::wire_to(equivalent, target);
Wiring::wire_to(e_target, target);
} else {
LOGIF(INTER_CONNECTORS, "Clash of sockets\n");
}
} else {
2022-01-04 01:40:23 +02:00
Wiring::socket(destination_tree, symb->symbol_name, symb);
}
}
}
}
}
2019-08-02 20:51:21 +03:00
}
@<Log sockets in origin tree@> =
LOG("\n\n\nList of sockets in origin tree:\n");
inter_package *connectors = LargeScale::connectors_package_if_it_exists(origin_tree);
if (connectors) {
2022-01-31 01:49:12 +02:00
inter_symbols_table *T = InterPackage::scope(connectors);
if (T == NULL) internal_error("package with no symbols");
2022-02-03 17:51:44 +02:00
LOOP_OVER_SYMBOLS_TABLE(symb, T) {
2022-02-04 12:04:41 +02:00
if (InterSymbol::is_socket(symb)) {
LOG("$3\n", symb);
}
}
}
LOG("---\n\n");
2019-08-02 20:51:21 +03:00
@<Create these bookmarks@> =
2022-01-27 01:59:02 +02:00
deletion_point = InterBookmark::after_this_node(migrant->package_head);
insertion_point = InterBookmark::at_end_of_this_package(destination);
2019-08-02 20:51:21 +03:00
inter_tree_node *prims = NULL;
LOOP_THROUGH_INTER_CHILDREN(F, destination->package_head->tree->root_node)
2022-01-30 15:32:38 +02:00
if (F->W.instruction[ID_IFLD] == PRIMITIVE_IST)
2019-08-02 20:51:21 +03:00
prims = F;
if (prims == NULL) internal_error("dest has no prims");
2022-01-27 01:59:02 +02:00
primitives_point = InterBookmark::after_this_node(prims);
2020-01-12 02:35:36 +02:00
inter_tree_node *ptypes = NULL;
LOOP_THROUGH_INTER_CHILDREN(F, destination->package_head->tree->root_node)
2022-01-30 15:32:38 +02:00
if (F->W.instruction[ID_IFLD] == PACKAGETYPE_IST)
2020-01-12 02:35:36 +02:00
ptypes = F;
if (ptypes == NULL) internal_error("dest has no prims");
2022-01-27 01:59:02 +02:00
ptypes_point = InterBookmark::after_this_node(ptypes);
2019-08-02 20:51:21 +03:00
@<Mark the insertion and deletion points with comments@> =
2022-01-30 15:32:38 +02:00
inter_ti C1 = InterWarehouse::create_text(InterBookmark::warehouse(&deletion_point), InterBookmark::package(&deletion_point));
WRITE_TO(InterWarehouse::get_text(InterBookmark::warehouse(&deletion_point), C1),
2022-01-31 01:49:12 +02:00
"Exported %S here", InterPackage::name(migrant));
Inter::Comment::new(&deletion_point, (inter_ti) InterPackage::baseline(migrant), NULL, C1);
2019-08-02 20:51:21 +03:00
2022-01-30 15:32:38 +02:00
inter_ti C2 = InterWarehouse::create_text(InterBookmark::warehouse(&insertion_point), InterBookmark::package(&insertion_point));
WRITE_TO(InterWarehouse::get_text(InterBookmark::warehouse(&insertion_point), C2),
2022-01-31 01:49:12 +02:00
"Imported %S here", InterPackage::name(migrant));
Inter::Comment::new(&insertion_point, (inter_ti) InterPackage::baseline(destination) + 1, NULL, C2);
2019-08-02 20:51:21 +03:00
@<Physically move the subtree to its new home@> =
2022-01-31 01:49:12 +02:00
InterPackage::remove_subpackage_name(InterPackage::parent(migrant), migrant);
InterPackage::add_subpackage_name(destination, migrant);
2022-01-27 01:59:02 +02:00
NodePlacement::move_to_moving_bookmark(migrant->package_head, &insertion_point);
2019-08-02 20:51:21 +03:00
@ =
typedef struct ipct_state {
inter_package *migrant;
inter_package *destination;
inter_bookmark *primitives_point;
2020-01-12 02:35:36 +02:00
inter_bookmark *ptypes_point;
2019-08-04 15:04:42 +03:00
inter_tree *origin_tree;
inter_tree *destination_tree;
2019-08-02 20:51:21 +03:00
} ipct_state;
2019-08-04 15:04:42 +03:00
@<Initialise the IPCT state@> =
2019-08-02 20:51:21 +03:00
ipct_cache_count++;
ipct.migrant = migrant;
ipct.destination = destination;
2019-08-04 15:04:42 +03:00
ipct.origin_tree = origin_tree;
ipct.destination_tree = destination_tree;
2019-08-02 20:51:21 +03:00
ipct.primitives_point = &primitives_point;
2020-01-12 02:35:36 +02:00
ipct.ptypes_point = &ptypes_point;
2019-08-04 15:04:42 +03:00
@<Correct any references from the migrant to the origin@> =
ipct_state ipct;
@<Initialise the IPCT state@>;
2021-04-16 00:42:28 +03:00
InterTree::traverse(destination->package_head->tree,
2019-08-02 20:51:21 +03:00
Inter::Transmigration::correct_migrant, &ipct, migrant, 0);
@ =
void Inter::Transmigration::correct_migrant(inter_tree *I, inter_tree_node *P, void *state) {
ipct_state *ipct = (ipct_state *) state;
P->tree = I;
2022-01-30 15:32:38 +02:00
if ((P->W.instruction[ID_IFLD] == INV_IST) && (P->W.instruction[METHOD_INV_IFLD] == INVOKED_PRIMITIVE)) {
2019-08-02 20:51:21 +03:00
inter_symbol *primitive =
2022-02-03 17:51:44 +02:00
InterSymbolsTable::symbol_from_ID(InterTree::global_scope(ipct->origin_tree), P->W.instruction[INVOKEE_INV_IFLD]);
2019-08-02 20:51:21 +03:00
if (primitive) @<Correct the reference to this primitive@>;
}
2022-01-30 15:32:38 +02:00
if (P->W.instruction[ID_IFLD] == PACKAGE_IST) {
2022-01-31 01:49:12 +02:00
inter_package *pack = InterPackage::at_this_head(P);
2019-08-02 20:51:21 +03:00
if (pack == NULL) internal_error("no package defined here");
2022-01-31 01:49:12 +02:00
if (InterPackage::is_a_linkage_package(pack)) return;
2020-01-12 02:35:36 +02:00
@<Correct the reference to this package type@>;
2022-01-31 01:49:12 +02:00
inter_symbols_table *T = InterPackage::scope(pack);
2019-08-02 20:51:21 +03:00
if (T == NULL) internal_error("package with no symbols");
2022-02-03 17:51:44 +02:00
LOOP_OVER_SYMBOLS_TABLE(symb, T) {
2022-01-04 01:40:23 +02:00
if (Wiring::is_wired(symb)) {
inter_symbol *target = Wiring::cable_end(symb);
if (SymbolAnnotation::get_b(target, ARCHITECTURAL_IANN)) {
2022-01-04 01:40:23 +02:00
Wiring::wire_to(symb,
LargeScale::find_architectural_symbol(ipct->destination->package_head->tree, target->symbol_name, Produce::kind_to_symbol(NULL)));
2022-02-04 12:04:41 +02:00
} else if (InterSymbol::is_plug(target)) {
inter_symbol *equivalent = Inter::Transmigration::cached_equivalent(target);
if (equivalent == NULL) {
2022-01-04 01:40:23 +02:00
text_stream *N = Wiring::wired_to_name(target);
equivalent = Wiring::find_plug(ipct->destination->package_head->tree, N);
if (equivalent == NULL)
2022-01-04 01:40:23 +02:00
equivalent = Wiring::plug(ipct->destination->package_head->tree, N);
Inter::Transmigration::cache(target, equivalent);
}
2022-01-04 01:40:23 +02:00
Wiring::wire_to(symb, equivalent);
} else {
inter_package *target_package = InterSymbol::package(target);
while ((target_package) && (target_package != ipct->migrant)) {
2022-01-31 01:49:12 +02:00
target_package = InterPackage::parent(target_package);
}
if (target_package != ipct->migrant)
@<Correct the reference to this symbol@>;
2019-08-02 20:51:21 +03:00
}
}
}
}
}
@<Correct the reference to this primitive@> =
inter_symbol *equivalent_primitive = Inter::Transmigration::cached_equivalent(primitive);
if (equivalent_primitive == NULL) {
2022-02-03 17:51:44 +02:00
equivalent_primitive = InterSymbolsTable::symbol_from_name(InterTree::global_scope(ipct->destination_tree), primitive->symbol_name);
2019-08-02 20:51:21 +03:00
if (equivalent_primitive == NULL) @<Duplicate this primitive@>;
if (equivalent_primitive) Inter::Transmigration::cache(primitive, equivalent_primitive);
}
if (equivalent_primitive)
2022-02-03 17:51:44 +02:00
P->W.instruction[INVOKEE_INV_IFLD] = InterSymbolsTable::id_from_symbol(ipct->destination_tree, NULL, equivalent_primitive);
2019-08-02 20:51:21 +03:00
@<Duplicate this primitive@> =
2022-02-03 17:51:44 +02:00
equivalent_primitive = InterSymbolsTable::symbol_from_name_creating(InterTree::global_scope(ipct->destination_tree), primitive->symbol_name);
inter_tree_node *D = Inode::new_with_1_data_field(ipct->primitives_point, PRIMITIVE_IST, InterSymbolsTable::id_from_symbol(ipct->destination_tree, NULL, equivalent_primitive), NULL, 0);
2019-08-02 20:51:21 +03:00
inter_tree_node *old_D = primitive->definition;
for (int i=CAT_PRIM_IFLD; i<old_D->W.extent; i++) {
2022-01-30 15:32:38 +02:00
Inode::extend_instruction_by(D, 1);
D->W.instruction[i] = old_D->W.instruction[i];
2019-08-02 20:51:21 +03:00
}
2022-01-27 01:59:02 +02:00
inter_error_message *E = Inter::Defn::verify_construct(InterBookmark::package(ipct->primitives_point), D);
2019-08-02 20:51:21 +03:00
if (E) {
Inter::Errors::issue(E);
equivalent_primitive = NULL;
} else {
2022-01-27 01:59:02 +02:00
NodePlacement::move_to_moving_bookmark(D, ipct->primitives_point);
2019-08-02 20:51:21 +03:00
}
2020-01-12 02:35:36 +02:00
@<Correct the reference to this package type@> =
inter_symbol *original_ptype =
2022-02-03 17:51:44 +02:00
InterSymbolsTable::symbol_from_ID(
2022-01-30 15:32:38 +02:00
InterTree::global_scope(ipct->origin_tree), P->W.instruction[PTYPE_PACKAGE_IFLD]);
2020-01-12 02:35:36 +02:00
inter_symbol *equivalent_ptype = Inter::Transmigration::cached_equivalent(original_ptype);
if (equivalent_ptype == NULL) {
2022-02-03 17:51:44 +02:00
equivalent_ptype = InterSymbolsTable::symbol_from_name(InterTree::global_scope(ipct->destination_tree), original_ptype->symbol_name);
2020-01-12 02:35:36 +02:00
if (equivalent_ptype == NULL) @<Duplicate this package type@>;
if (equivalent_ptype) Inter::Transmigration::cache(original_ptype, equivalent_ptype);
}
if (equivalent_ptype)
2022-02-03 17:51:44 +02:00
P->W.instruction[PTYPE_PACKAGE_IFLD] = InterSymbolsTable::id_from_symbol(ipct->destination_tree, NULL, equivalent_ptype);
2020-01-12 02:35:36 +02:00
@<Duplicate this package type@> =
2022-02-03 17:51:44 +02:00
equivalent_ptype = InterSymbolsTable::symbol_from_name_creating(InterTree::global_scope(ipct->destination_tree), original_ptype->symbol_name);
inter_tree_node *D = Inode::new_with_1_data_field(ipct->ptypes_point, PACKAGETYPE_IST, InterSymbolsTable::id_from_symbol(ipct->destination_tree, NULL, equivalent_ptype), NULL, 0);
2022-01-27 01:59:02 +02:00
inter_error_message *E = Inter::Defn::verify_construct(InterBookmark::package(ipct->ptypes_point), D);
2020-01-12 02:35:36 +02:00
if (E) {
Inter::Errors::issue(E);
equivalent_ptype = NULL;
} else {
2022-01-27 01:59:02 +02:00
NodePlacement::move_to_moving_bookmark(D, ipct->ptypes_point);
2020-01-12 02:35:36 +02:00
}
2019-08-02 20:51:21 +03:00
@<Correct the reference to this symbol@> =
inter_symbol *equivalent = Inter::Transmigration::cached_equivalent(target);
if (equivalent == NULL) {
2020-06-28 01:18:54 +03:00
TEMPORARY_TEXT(URL)
2022-02-03 17:51:44 +02:00
InterSymbolsTable::write_symbol_URL(URL, target);
equivalent = InterSymbolsTable::URL_to_symbol(ipct->destination->package_head->tree, URL);
2019-09-01 23:17:40 +03:00
if ((equivalent == NULL) && (Inter::Kind::is(target)))
2022-02-03 01:35:38 +02:00
equivalent = LargeScale::find_symbol_in_tree(ipct->destination->package_head->tree, target->symbol_name);
2019-08-02 20:51:21 +03:00
if (equivalent == NULL)
equivalent = Wiring::plug(ipct->destination_tree, target->symbol_name);
2020-06-28 01:18:54 +03:00
DISCARD_TEXT(URL)
2019-08-02 20:51:21 +03:00
Inter::Transmigration::cache(target, equivalent);
}
2022-01-04 01:40:23 +02:00
Wiring::wire_to(symb, equivalent);
2019-08-02 20:51:21 +03:00
@<Correct any references from the origin to the migrant@> =
ipct_state ipct;
2019-08-04 15:04:42 +03:00
@<Initialise the IPCT state@>;
2021-04-16 00:42:28 +03:00
InterTree::traverse(origin->package_head->tree,
2019-08-02 20:51:21 +03:00
Inter::Transmigration::correct_origin, &ipct, NULL, 0);
@ =
void Inter::Transmigration::correct_origin(inter_tree *I, inter_tree_node *P, void *state) {
ipct_state *ipct = (ipct_state *) state;
2022-01-30 15:32:38 +02:00
if (P->W.instruction[ID_IFLD] == PACKAGE_IST) {
2022-01-31 01:49:12 +02:00
inter_package *pack = InterPackage::at_this_head(P);
2019-08-02 20:51:21 +03:00
if (pack == NULL) internal_error("no package defined here");
2022-01-31 01:49:12 +02:00
if (InterPackage::is_a_linkage_package(pack)) return;
inter_symbols_table *T = InterPackage::scope(pack);
2019-08-02 20:51:21 +03:00
if (T == NULL) internal_error("package with no symbols");
2022-02-03 17:51:44 +02:00
LOOP_OVER_SYMBOLS_TABLE(symb, T) {
2022-01-04 01:40:23 +02:00
if (Wiring::is_wired(symb)) {
inter_symbol *target = Wiring::cable_end(symb);
inter_package *target_package = InterSymbol::package(target);
2019-08-02 20:51:21 +03:00
while ((target_package) && (target_package != ipct->migrant)) {
2022-01-31 01:49:12 +02:00
target_package = InterPackage::parent(target_package);
2019-08-02 20:51:21 +03:00
}
if (target_package == ipct->migrant)
@<Correct the origin reference to this migrant symbol@>;
}
}
}
}
@<Correct the origin reference to this migrant symbol@> =
inter_symbol *equivalent = Inter::Transmigration::cached_equivalent(target);
if (equivalent == NULL) {
2020-06-28 01:18:54 +03:00
TEMPORARY_TEXT(URL)
2022-02-03 17:51:44 +02:00
InterSymbolsTable::write_symbol_URL(URL, target);
2022-01-04 01:40:23 +02:00
equivalent = Wiring::plug(ipct->origin_tree, URL);
2020-06-28 01:18:54 +03:00
DISCARD_TEXT(URL)
2019-08-02 20:51:21 +03:00
Inter::Transmigration::cache(target, equivalent);
}
2022-01-04 01:40:23 +02:00
Wiring::wire_to(symb, equivalent);