1
0
Fork 0
mirror of https://github.com/ganelson/inform.git synced 2024-07-03 07:24:58 +03:00
inform7/inter/Chapter 1/Main.w

229 lines
8.1 KiB
OpenEdge ABL
Raw Normal View History

2019-02-05 02:44:07 +02:00
[Main::] Main.
2020-03-29 02:22:31 +02:00
A command-line interface for Inter functions which are not part of the
normal operation of the Inform compiler.
2019-02-05 02:44:07 +02:00
2020-03-29 02:22:31 +02:00
@h Settings variables.
The following will be set at the command line.
2019-02-05 02:44:07 +02:00
2020-03-29 02:22:31 +02:00
=
pathname *path_to_inter = NULL;
2020-03-28 15:00:08 +02:00
2020-03-29 02:22:31 +02:00
pathname *kit_to_assimilate = NULL;
pathname *domain_path = NULL;
linked_list *inter_file_list = NULL; /* of |filename| */
filename *output_textually = NULL;
filename *output_binarily = NULL;
dictionary *pipeline_vars = NULL;
filename *pipeline_as_file = NULL;
text_stream *pipeline_as_text = NULL;
pathname *internal_path = NULL;
2020-03-29 02:22:31 +02:00
void Main::add_pipeline_variable(text_stream *name, text_stream *value) {
Str::copy(Dictionaries::create_text(pipeline_vars, name), value);
}
void Main::add_pipeline_variable_from_filename(text_stream *name, filename *F) {
2020-06-28 01:18:54 +03:00
TEMPORARY_TEXT(fullname)
2020-03-29 02:22:31 +02:00
WRITE_TO(fullname, "%f", F);
Main::add_pipeline_variable(name, fullname);
2020-06-28 01:18:54 +03:00
DISCARD_TEXT(fullname)
2020-03-29 02:22:31 +02:00
}
2020-03-29 02:22:31 +02:00
@h Main routine.
When Inter is called at the command line, it begins at |main|, like all C
programs.
2020-03-29 02:22:31 +02:00
Inter can do three different things: assimilate a kit, run a pipeline of
code generation stages, and verify/transcode files of Inter code. In fact,
though, that's really only two different things, because assimilation is
also done with a pipeline.
=
2020-03-29 02:22:31 +02:00
int main(int argc, char **argv) {
@<Start up the modules@>;
@<Begin with an empty file list and variables dictionary@>;
@<Read the command line@>;
if (kit_to_assimilate) @<Set up a pipeline for assimilation@>;
if ((pipeline_as_file) || (pipeline_as_text))
@<Run the pipeline@>
else
@<Read the list of inter files, and perhaps transcode them@>;
@<Shut down the modules@>;
if (Errors::have_occurred()) return 1;
return 0;
}
2020-03-29 02:22:31 +02:00
@<Start up the modules@> =
Foundation::start(argc, argv); /* must be started first */
2020-03-29 02:22:31 +02:00
ArchModule::start();
2020-04-14 19:56:54 +03:00
BytecodeModule::start();
2020-03-29 02:22:31 +02:00
BuildingModule::start();
CodegenModule::start();
2021-06-27 18:04:28 +03:00
IndexModule::start();
2020-03-29 02:22:31 +02:00
@<Begin with an empty file list and variables dictionary@> =
inter_file_list = NEW_LINKED_LIST(filename);
pipeline_vars = CodeGen::Pipeline::basic_dictionary(I"output.i6");
internal_path = Pathnames::from_text(I"inform7/Internal");
2020-03-29 02:22:31 +02:00
@ This pipeline is supplied built in to the installation of |inter|. In fact,
it only ever writes the binary form of the code it produces, so only |*out|
is used. But at times in the past it has been useful to debug with the text
form, which would be written to |*outt|.
@<Set up a pipeline for assimilation@> =
inter_architecture *A = CodeGen::Architecture::current();
if (A == NULL) Errors::fatal("no -architecture given");
pathname *path_to_pipelines = Pathnames::down(path_to_inter, I"Pipelines");
pipeline_as_file = Filenames::in(path_to_pipelines, I"assimilate.interpipeline");
2020-03-29 02:22:31 +02:00
pipeline_as_text = NULL;
Main::add_pipeline_variable(I"*kit",
Pathnames::directory_name(kit_to_assimilate));
Main::add_pipeline_variable_from_filename(I"*out",
Architectures::canonical_binary(kit_to_assimilate, A));
Main::add_pipeline_variable_from_filename(I"*outt",
Architectures::canonical_textual(kit_to_assimilate, A));
@<Run the pipeline@> =
if (LinkedLists::len(inter_file_list) > 0)
Errors::fatal("-pipeline-text and -pipeline-file cannot be combined with inter files");
if ((pipeline_as_file) && (pipeline_as_text))
Errors::fatal("-pipeline-text and -pipeline-file are mutually exclusive");
linked_list *inter_paths = NEW_LINKED_LIST(pathname);
if (kit_to_assimilate) ADD_TO_LINKED_LIST(kit_to_assimilate, pathname, inter_paths);
codegen_pipeline *SS;
if (pipeline_as_file)
SS = CodeGen::Pipeline::parse_from_file(pipeline_as_file, pipeline_vars);
else
SS = CodeGen::Pipeline::parse(pipeline_as_text, pipeline_vars);
linked_list *requirements_list = NEW_LINKED_LIST(inter_library);
if (SS) CodeGen::Pipeline::run(domain_path, SS, inter_paths, requirements_list);
else Errors::fatal("pipeline could not be parsed");
@<Read the list of inter files, and perhaps transcode them@> =
2021-04-16 00:42:28 +03:00
inter_tree *I = InterTree::new();
2020-03-29 02:22:31 +02:00
filename *F;
LOOP_OVER_LINKED_LIST(F, filename, inter_file_list) {
if (Inter::Binary::test_file(F))
Inter::Binary::read(I, F);
else
Inter::Textual::read(I, F);
}
if (output_textually) {
text_stream C_struct; text_stream *OUT = &C_struct;
if (STREAM_OPEN_TO_FILE(OUT, output_textually, UTF8_ENC) == FALSE)
Errors::fatal_with_file("unable to open textual inter file for output: %f",
output_textually);
Inter::Textual::write(OUT, I, NULL, 1);
STREAM_CLOSE(OUT);
}
if (output_binarily) Inter::Binary::write(output_binarily, I);
@<Shut down the modules@> =
2020-04-14 19:56:54 +03:00
BytecodeModule::end();
2020-03-29 02:22:31 +02:00
BuildingModule::end();
CodegenModule::end();
ArchModule::end();
2021-06-27 18:04:28 +03:00
IndexModule::end();
2020-03-29 02:22:31 +02:00
Foundation::end(); /* must be ended last */
@h Command line.
@d PROGRAM_NAME "inter"
2019-02-05 02:44:07 +02:00
@e TEXTUAL_CLSW
@e BINARY_CLSW
2019-07-20 14:40:27 +03:00
@e PIPELINE_CLSW
@e PIPELINE_FILE_CLSW
@e PIPELINE_VARIABLE_CLSW
2019-02-05 02:44:07 +02:00
@e DOMAIN_CLSW
@e ARCHITECTURE_CLSW
2019-09-17 14:55:51 +03:00
@e ASSIMILATE_CLSW
@e INTERNAL_CLSW
2019-02-05 02:44:07 +02:00
2020-03-29 02:22:31 +02:00
@<Read the command line@> =
2019-02-05 02:44:07 +02:00
CommandLine::declare_heading(
L"[[Purpose]]\n\n"
L"usage: inter file1 file2 ... [options]\n");
CommandLine::declare_switch(TEXTUAL_CLSW, L"textual", 2,
L"write to file X in textual format");
CommandLine::declare_switch(BINARY_CLSW, L"binary", 2,
L"write to file X in binary format");
CommandLine::declare_switch(PIPELINE_CLSW, L"pipeline-text", 2,
L"specify pipeline textually, with X being a comma-separated list of stages");
2019-07-20 14:40:27 +03:00
CommandLine::declare_switch(PIPELINE_FILE_CLSW, L"pipeline-file", 2,
L"specify pipeline as file X");
2019-07-20 14:40:27 +03:00
CommandLine::declare_switch(PIPELINE_VARIABLE_CLSW, L"variable", 2,
L"set pipeline variable X (in form name=value)");
2019-02-05 02:44:07 +02:00
CommandLine::declare_switch(DOMAIN_CLSW, L"domain", 2,
L"specify folder to read/write inter files from/to");
CommandLine::declare_switch(INTERNAL_CLSW, L"internal", 2,
L"specify folder of internal Inform resources");
CommandLine::declare_switch(ARCHITECTURE_CLSW, L"architecture", 2,
L"generate Inter with architecture X");
2019-09-17 14:55:51 +03:00
CommandLine::declare_switch(ASSIMILATE_CLSW, L"assimilate", 2,
L"assimilate (i.e., build) Inter kit X for the current architecture");
2019-07-20 14:40:27 +03:00
2019-02-05 02:44:07 +02:00
CommandLine::read(argc, argv, NULL, &Main::respond, &Main::add_file);
2020-03-29 02:22:31 +02:00
path_to_inter = Pathnames::installation_path("INTER_PATH", I"inter");
2020-03-28 15:00:08 +02:00
2019-02-05 02:44:07 +02:00
@ =
void Main::respond(int id, int val, text_stream *arg, void *state) {
switch (id) {
case TEXTUAL_CLSW: output_textually = Filenames::from_text(arg); break;
2020-03-29 02:22:31 +02:00
case BINARY_CLSW: output_binarily = Filenames::from_text(arg); break;
2019-07-20 14:40:27 +03:00
case PIPELINE_CLSW: pipeline_as_text = Str::duplicate(arg); break;
case PIPELINE_FILE_CLSW: pipeline_as_file = Filenames::from_text(arg); break;
2020-03-29 02:22:31 +02:00
case PIPELINE_VARIABLE_CLSW: @<Add a pipeline variable to the dictionary@>; break;
case DOMAIN_CLSW: domain_path = Pathnames::from_text(arg); break;
case ASSIMILATE_CLSW: kit_to_assimilate = Pathnames::from_text(arg); break;
case INTERNAL_CLSW: internal_path = Pathnames::from_text(arg); break;
case ARCHITECTURE_CLSW:
2019-09-17 14:55:51 +03:00
if (CodeGen::Architecture::set(arg) == FALSE)
Errors::fatal("no such -architecture");
break;
2019-02-05 02:44:07 +02:00
}
}
2020-03-29 02:22:31 +02:00
@<Add a pipeline variable to the dictionary@> =
match_results mr = Regexp::create_mr();
if (Regexp::match(&mr, arg, L"(%c+)=(%c+)")) {
if (Str::get_first_char(arg) != '*') {
Errors::fatal("-variable names must begin with '*'");
} else {
Main::add_pipeline_variable(mr.exp[0], mr.exp[1]);
}
} else {
Errors::fatal("-variable should take the form 'name=value'");
}
Regexp::dispose_of(&mr);
2019-02-05 02:44:07 +02:00
2020-03-29 02:22:31 +02:00
@ =
2019-02-05 02:44:07 +02:00
void Main::add_file(int id, text_stream *arg, void *state) {
2020-03-29 02:22:31 +02:00
filename *F = Filenames::from_text(arg);
ADD_TO_LINKED_LIST(F, filename, inter_file_list);
2019-02-05 02:44:07 +02:00
}
2020-03-29 02:22:31 +02:00
@ The modules included in |inter| make use of the Inform 7 module |kinds|,
but when we are using |inter| on its own, kinds have no meaning for us.
We are required to create a |kind| type, in order for |kinds| to compile;
but no instances of this kind will ever in fact exist. |K_value| is a
global constant meaning "any kind at all", and that also must exist.
= (early code)
typedef void kind;
kind *K_value = NULL;
@ This is where the //html// module can find CSS files and similar resources:
@d INSTALLED_FILES_HTML_CALLBACK Main::internal_path
=
pathname *Main::internal_path(void) {
return internal_path;
}