1
0
Fork 0
mirror of https://github.com/ganelson/inform.git synced 2024-07-08 10:04:21 +03:00
inform7/inbuild/inbuild-module/Chapter 4/Kit Services.w

292 lines
9.4 KiB
OpenEdge ABL
Raw Normal View History

2020-01-26 13:44:27 +02:00
[Kits::] Kits.
A kit is a combination of Inter code with an Inform 7 extension.
2020-02-08 12:34:58 +02:00
@h Genre definition.
2020-01-26 13:44:27 +02:00
=
typedef struct inform_kit {
struct inbuild_copy *as_copy;
2020-01-26 13:44:27 +02:00
struct text_stream *name;
struct text_stream *attachment_point;
2020-01-26 13:44:27 +02:00
struct text_stream *early_source;
struct linked_list *ittt; /* of |inform_kit_ittt| */
struct linked_list *kind_definitions; /* of |text_stream| */
2020-01-27 02:49:57 +02:00
struct linked_list *extensions; /* of |text_stream| */
2020-01-26 16:55:32 +02:00
struct linked_list *activations; /* of |element_activation| */
2020-01-27 02:49:57 +02:00
struct text_stream *index_template;
struct inbuild_version_number version;
2020-01-27 02:49:57 +02:00
int defines_Main;
2020-01-27 23:54:07 +02:00
int supports_natural_language;
2020-01-26 13:44:27 +02:00
int priority;
MEMORY_MANAGEMENT
} inform_kit;
typedef struct inform_kit_ittt {
struct text_stream *if_name;
int if_included;
struct text_stream *then_name;
MEMORY_MANAGEMENT
} inform_kit_ittt;
2020-01-26 16:55:32 +02:00
typedef struct element_activation {
struct text_stream *element_name;
int activate;
MEMORY_MANAGEMENT
} element_activation;
2020-02-01 01:04:39 +02:00
pathname *Kits::find(text_stream *name, linked_list *nest_list) {
inbuild_nest *N;
LOOP_OVER_LINKED_LIST(N, inbuild_nest, nest_list) {
2020-02-08 12:34:58 +02:00
pathname *P = KitManager::path_within_nest(N);
2020-02-01 01:04:39 +02:00
P = Pathnames::subfolder(P, name);
filename *F = Filenames::in_folder(P, I"kit_metadata.txt");
if (TextFiles::exists(F)) return P;
}
return NULL;
}
2020-02-08 12:34:58 +02:00
inform_kit *Kits::new_ik(text_stream *name, pathname *P) {
2020-01-26 13:44:27 +02:00
inform_kit *K = CREATE(inform_kit);
2020-02-08 12:34:58 +02:00
K->as_copy = NULL;
2020-01-26 13:44:27 +02:00
K->name = Str::duplicate(name);
K->attachment_point = Str::new();
WRITE_TO(K->attachment_point, "/main/%S", name);
2020-01-26 13:44:27 +02:00
K->early_source = NULL;
K->priority = 10;
K->ittt = NEW_LINKED_LIST(inform_kit_ittt);
K->kind_definitions = NEW_LINKED_LIST(text_stream);
2020-01-27 02:49:57 +02:00
K->extensions = NEW_LINKED_LIST(text_stream);
2020-01-26 16:55:32 +02:00
K->activations = NEW_LINKED_LIST(element_activation);
2020-01-27 02:49:57 +02:00
K->defines_Main = FALSE;
2020-01-27 23:54:07 +02:00
K->supports_natural_language = FALSE;
2020-01-27 02:49:57 +02:00
K->index_template = NULL;
K->version = VersionNumbers::null();
2020-01-26 13:44:27 +02:00
filename *F = Filenames::in_folder(P, I"kit_metadata.txt");
2020-01-26 13:44:27 +02:00
TextFiles::read(F, FALSE,
NULL, FALSE, Kits::read_metadata, NULL, (void *) K);
return K;
}
2020-02-01 01:04:39 +02:00
inform_kit *Kits::load(text_stream *name, linked_list *nest_list) {
pathname *P = Kits::find(name, nest_list);
2020-01-28 01:20:49 +02:00
if (P == NULL) Errors::fatal_with_text("cannot find kit", name);
2020-02-08 12:34:58 +02:00
inbuild_copy *C = KitManager::new_copy(name, P);
KitManager::build_graph(C);
return KitManager::from_copy(C);
}
2020-01-26 13:44:27 +02:00
void Kits::dependency(inform_kit *K, text_stream *if_text, int inc, text_stream *then_text) {
inform_kit_ittt *ITTT = CREATE(inform_kit_ittt);
ITTT->if_name = Str::duplicate(if_text);
ITTT->if_included = inc;
ITTT->then_name = Str::duplicate(then_text);
ADD_TO_LINKED_LIST(ITTT, inform_kit_ittt, K->ittt);
}
2020-01-26 16:55:32 +02:00
void Kits::activation(inform_kit *K, text_stream *name, int act) {
element_activation *EA = CREATE(element_activation);
EA->element_name = Str::duplicate(name);
EA->activate = act;
ADD_TO_LINKED_LIST(EA, element_activation, K->activations);
}
2020-01-26 13:44:27 +02:00
void Kits::read_metadata(text_stream *text, text_file_position *tfp, void *state) {
inform_kit *K = (inform_kit *) state;
match_results mr = Regexp::create_mr();
if ((Str::is_whitespace(text)) || (Regexp::match(&mr, text, L" *#%c*"))) {
;
} else if (Regexp::match(&mr, text, L"version: (%C+)")) {
K->version = VersionNumbers::from_text(mr.exp[0]);
2020-01-27 02:49:57 +02:00
} else if (Regexp::match(&mr, text, L"defines Main: yes")) {
K->defines_Main = TRUE;
} else if (Regexp::match(&mr, text, L"defines Main: no")) {
K->defines_Main = FALSE;
2020-01-27 23:54:07 +02:00
} else if (Regexp::match(&mr, text, L"natural language: yes")) {
K->supports_natural_language = TRUE;
} else if (Regexp::match(&mr, text, L"natural language: no")) {
K->supports_natural_language = FALSE;
2020-01-26 13:44:27 +02:00
} else if (Regexp::match(&mr, text, L"insert: (%c*)")) {
K->early_source = Str::duplicate(mr.exp[0]);
WRITE_TO(K->early_source, "\n\n");
} else if (Regexp::match(&mr, text, L"priority: (%d*)")) {
K->priority = Str::atoi(mr.exp[0], 0);
} else if (Regexp::match(&mr, text, L"kinds: (%C+)")) {
ADD_TO_LINKED_LIST(Str::duplicate(mr.exp[0]), text_stream, K->kind_definitions);
2020-01-27 02:49:57 +02:00
} else if (Regexp::match(&mr, text, L"extension: (%c+)")) {
ADD_TO_LINKED_LIST(Str::duplicate(mr.exp[0]), text_stream, K->extensions);
2020-01-26 16:55:32 +02:00
} else if (Regexp::match(&mr, text, L"activate: (%c+)")) {
Kits::activation(K, mr.exp[0], TRUE);
} else if (Regexp::match(&mr, text, L"deactivate: (%c+)")) {
Kits::activation(K, mr.exp[0], FALSE);
2020-01-26 13:44:27 +02:00
} else if (Regexp::match(&mr, text, L"dependency: if (%C+) then (%C+)")) {
Kits::dependency(K, mr.exp[0], TRUE, mr.exp[1]);
} else if (Regexp::match(&mr, text, L"dependency: if not (%C+) then (%C+)")) {
Kits::dependency(K, mr.exp[0], FALSE, mr.exp[1]);
2020-01-27 02:49:57 +02:00
} else if (Regexp::match(&mr, text, L"index from: (%c*)")) {
K->index_template = Str::duplicate(mr.exp[0]);
2020-01-26 13:44:27 +02:00
} else {
Errors::in_text_file("illegible line in kit metadata file", tfp);
2020-01-27 02:49:57 +02:00
WRITE_TO(STDERR, "'%S'\n", text);
2020-01-26 13:44:27 +02:00
}
Regexp::dispose_of(&mr);
}
int Kits::loaded(text_stream *name) {
inform_kit *K;
LOOP_OVER(K, inform_kit)
if (Str::eq(K->name, name))
return TRUE;
return FALSE;
}
2020-02-01 01:04:39 +02:00
void Kits::perform_ittt(linked_list *nest_list) {
2020-01-26 13:44:27 +02:00
int changes_made = TRUE;
while (changes_made) {
changes_made = FALSE;
inform_kit *K;
LOOP_OVER(K, inform_kit) {
inform_kit_ittt *ITTT;
LOOP_OVER_LINKED_LIST(ITTT, inform_kit_ittt, K->ittt)
if ((Kits::loaded(ITTT->then_name) == FALSE) &&
(Kits::loaded(ITTT->if_name) == ITTT->if_included)) {
2020-02-01 01:04:39 +02:00
Kits::load(ITTT->then_name, nest_list);
2020-01-26 13:44:27 +02:00
changes_made = TRUE;
}
}
}
}
2020-01-27 02:49:57 +02:00
linked_list *kits_requested = NULL;
2020-01-26 13:44:27 +02:00
linked_list *kits_to_include = NULL;
2020-01-27 02:49:57 +02:00
void Kits::request(text_stream *name) {
if (kits_requested == NULL) kits_requested = NEW_LINKED_LIST(text_stream);
text_stream *kit_name;
LOOP_OVER_LINKED_LIST(kit_name, text_stream, kits_requested)
if (Str::eq(kit_name, name))
return;
ADD_TO_LINKED_LIST(Str::duplicate(name), text_stream, kits_requested);
}
2020-01-26 13:44:27 +02:00
2020-01-28 01:20:49 +02:00
#ifdef CORE_MODULE
2020-02-01 01:04:39 +02:00
void Kits::determine(linked_list *nest_list) {
2020-01-27 02:49:57 +02:00
if (kits_requested == NULL) Kits::request(I"CommandParserKit");
Kits::request(I"BasicInformKit");
2020-01-27 23:54:07 +02:00
NaturalLanguages::request_required_kits();
2020-01-27 02:49:57 +02:00
text_stream *kit_name;
LOOP_OVER_LINKED_LIST(kit_name, text_stream, kits_requested)
2020-02-01 01:04:39 +02:00
Kits::load(kit_name, nest_list);
2020-01-27 02:49:57 +02:00
2020-02-01 01:04:39 +02:00
Kits::perform_ittt(nest_list);
2020-01-26 13:44:27 +02:00
kits_to_include = NEW_LINKED_LIST(inform_kit);
for (int p=0; p<100; p++) {
inform_kit *K;
LOOP_OVER(K, inform_kit)
if (K->priority == p)
ADD_TO_LINKED_LIST(K, inform_kit, kits_to_include);
}
inform_kit *K;
LOOP_OVER_LINKED_LIST(K, inform_kit, kits_to_include)
LOG("Using Inform kit '%S' (priority %d).\n", K->name, K->priority);
}
2020-01-28 01:20:49 +02:00
#endif
2020-01-26 13:44:27 +02:00
2020-01-28 01:20:49 +02:00
#ifdef CORE_MODULE
2020-01-26 13:44:27 +02:00
void Kits::load_types(void) {
inform_kit *K;
LOOP_OVER_LINKED_LIST(K, inform_kit, kits_to_include) {
text_stream *segment;
LOOP_OVER_LINKED_LIST(segment, text_stream, K->kind_definitions) {
pathname *P = Pathnames::subfolder(K->as_copy->location_if_path, I"kinds");
2020-01-26 13:44:27 +02:00
filename *F = Filenames::in_folder(P, segment);
LOG("Loading kinds definitions from %f\n", F);
I6T::interpret_kindt(F);
}
}
}
2020-01-28 01:20:49 +02:00
#endif
2020-01-26 13:44:27 +02:00
2020-01-28 01:20:49 +02:00
#ifdef CORE_MODULE
2020-01-26 16:55:32 +02:00
void Kits::activate_plugins(void) {
LOG("Activate plugins...\n");
Plugins::Manage::activate(CORE_PLUGIN_NAME);
inform_kit *K;
LOOP_OVER_LINKED_LIST(K, inform_kit, kits_to_include) {
element_activation *EA;
LOOP_OVER_LINKED_LIST(EA, element_activation, K->activations) {
int S = Plugins::Manage::parse(EA->element_name);
if (S == -1)
Problems::Issue::sentence_problem(_p_(Untestable),
"one of the Inform kits made reference to a language segment which does not exist",
"which strongly suggests that Inform is not properly installed.");
if (S >= 0) {
if (EA->activate) Plugins::Manage::activate(S);
else Plugins::Manage::deactivate(S);
}
}
}
Plugins::Manage::show(DL, "Included", TRUE);
Plugins::Manage::show(DL, "Excluded", FALSE);
}
2020-01-28 01:20:49 +02:00
#endif
2020-01-26 16:55:32 +02:00
2020-01-27 02:49:57 +02:00
int Kits::Main_defined(void) {
inform_kit *K;
LOOP_OVER_LINKED_LIST(K, inform_kit, kits_to_include)
if (K->defines_Main)
return TRUE;
return FALSE;
}
text_stream *Kits::index_template(void) {
text_stream *I = NULL;
inform_kit *K;
LOOP_OVER_LINKED_LIST(K, inform_kit, kits_to_include)
if (K->index_template)
I = K->index_template;
return I;
}
2020-01-31 02:13:50 +02:00
@ Every source text read into Inform is automatically prefixed by a few words
loading the fundamental "extensions" -- text such as "Include Basic Inform by
Graham Nelson." If Inform were a computer, this would be the BIOS which boots
up its operating system. Each kit can contribute such extensions, so there
may be multiple sentences, which we need to count up.
2020-01-26 13:44:27 +02:00
=
2020-01-27 02:49:57 +02:00
void Kits::feed_early_source_text(OUTPUT_STREAM) {
2020-01-26 13:44:27 +02:00
inform_kit *K;
2020-01-27 02:49:57 +02:00
LOOP_OVER_LINKED_LIST(K, inform_kit, kits_to_include) {
text_stream *X;
LOOP_OVER_LINKED_LIST(X, text_stream, K->extensions)
WRITE("Include %S.\n\n", X);
if (K->early_source) WRITE("%S\n\n", K->early_source);
}
2020-01-26 13:44:27 +02:00
}
2020-01-27 12:54:21 +02:00
int Kits::number_of_early_fed_sentences(void) {
int N = 0;
inform_kit *K;
LOOP_OVER_LINKED_LIST(K, inform_kit, kits_to_include) {
text_stream *X;
LOOP_OVER_LINKED_LIST(X, text_stream, K->extensions) N++;
if (K->early_source) N++;
}
return N;
}
2020-01-28 01:20:49 +02:00
#ifdef CODEGEN_MODULE
2020-01-26 13:44:27 +02:00
linked_list *requirements_list = NULL;
linked_list *Kits::list_of_inter_libraries(void) {
requirements_list = NEW_LINKED_LIST(link_instruction);
2020-01-26 13:44:27 +02:00
inform_kit *K;
LOOP_OVER_LINKED_LIST(K, inform_kit, kits_to_include) {
link_instruction *link = CodeGen::LinkInstructions::new(K->as_copy->location_if_path, K->attachment_point);
ADD_TO_LINKED_LIST(link, link_instruction, requirements_list);
}
2020-01-26 13:44:27 +02:00
return requirements_list;
}
2020-01-28 01:20:49 +02:00
#endif