A command-line interface for Inter functions which are not part of the normal operation of the Inform compiler.
§1. Settings variables. The following will be set at the command line.
pathname *path_to_inter = NULL; pathname *kit_to_build = NULL; pathname *domain_path = NULL; linked_list *inter_file_list = NULL; of filename filename *output_file = NULL; dictionary *pipeline_vars = NULL; filename *pipeline_as_file = NULL; text_stream *pipeline_as_text = NULL; pathname *internal_path = NULL; text_stream *output_format = NULL; for any -o output int tracing = FALSE; 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) { TEMPORARY_TEXT(fullname) WRITE_TO(fullname, "%f", F); Main::add_pipeline_variable(name, fullname); DISCARD_TEXT(fullname) }
§2. Main routine. When Inter is called at the command line, it begins at main, like all C programs.
Inter can do three different things: build 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 kit-building is also done with a pipeline.
int main(int argc, char **argv) { Start up the modules2.1; Begin with an empty file list and variables dictionary2.2; Read the command line2.6; if (kit_to_build) Select the build-kit pipeline2.3; Run the pipeline2.4; Shut down the modules2.5; if (Errors::have_occurred()) return 1; return 0; }
§2.1. Start up the modules2.1 =
Foundation::start(argc, argv); must be started first ArchModule::start(); BytecodeModule::start(); BuildingModule::start(); PipelineModule::start(); FinalModule::start(); IndexModule::start();
- This code is used in §2.
§2.2. Begin with an empty file list and variables dictionary2.2 =
inter_file_list = NEW_LINKED_LIST(filename); pipeline_vars = ParsingPipelines::basic_dictionary(I"output.i6"); internal_path = Pathnames::from_text(I"inform7/Internal");
- This code is used in §2.
§2.3. Select the build-kit pipeline2.3 =
inter_architecture *A = PipelineModule::get_architecture(); 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"build-kit.interpipeline"); pipeline_as_text = NULL; Main::add_pipeline_variable(I"*kit", Pathnames::directory_name(kit_to_build)); Main::add_pipeline_variable_from_filename(I"*out", Architectures::canonical_binary(kit_to_build, A));
- This code is used in §2.
if ((pipeline_as_file) && (pipeline_as_text)) Errors::fatal("-pipeline-text and -pipeline-file are mutually exclusive"); if (Str::len(output_format) == 0) output_format = I"Text"; target_vm *VM = TargetVMs::find(output_format); if (VM == NULL) Errors::fatal("unrecognised compilation -format"); inter_architecture *A = PipelineModule::get_architecture(); if (A == NULL) PipelineModule::set_architecture( Architectures::to_codename(TargetVMs::get_architecture(VM))); inter_tree *I = InterTree::new(); if (LinkedLists::len(inter_file_list) > 0) { if (LinkedLists::len(inter_file_list) > 1) Errors::fatal("only one file of Inter can be supplied"); filename *F; LOOP_OVER_LINKED_LIST(F, filename, inter_file_list) Main::add_pipeline_variable_from_filename(I"*in", F); } if (output_file) { Main::add_pipeline_variable_from_filename(I"*out", output_file); } inter_pipeline *SS = NULL; Compile the pipeline2.4.1; if (SS) { linked_list *req_list = NEW_LINKED_LIST(attachment_instruction); RunningPipelines::run(domain_path, SS, I, kit_to_build, req_list, VM, tracing); }
- This code is used in §2.
§2.4.1. Compile the pipeline2.4.1 =
if (pipeline_as_file) { SS = ParsingPipelines::from_file(pipeline_as_file, pipeline_vars, NULL); if (SS == NULL) Errors::fatal("pipeline could not be parsed"); } else if (pipeline_as_text) { SS = ParsingPipelines::from_text(pipeline_as_text, pipeline_vars); if (SS == NULL) Errors::fatal("pipeline could not be parsed"); } else if (output_file) { SS = ParsingPipelines::from_text(I"read <- *in, generate -> *out", pipeline_vars); if (SS == NULL) Errors::fatal("pipeline could not be parsed"); } else if (LinkedLists::len(inter_file_list) > 0) { SS = ParsingPipelines::from_text(I"read <- *in", pipeline_vars); if (SS == NULL) Errors::fatal("pipeline could not be parsed"); }
- This code is used in §2.4.
§2.5. Shut down the modules2.5 =
BytecodeModule::end(); BuildingModule::end(); PipelineModule::end(); FinalModule::end(); ArchModule::end(); IndexModule::end(); Foundation::end(); must be ended last
- This code is used in §2.
define PROGRAM_NAME "inter" enum PIPELINE_CLSW enum PIPELINE_FILE_CLSW enum PIPELINE_VARIABLE_CLSW enum DOMAIN_CLSW enum ARCHITECTURE_CLSW enum BUILD_KIT_CLSW enum INTERNAL_CLSW enum CONSTRUCTS_CLSW enum ANNOTATIONS_CLSW enum PRIMITIVES_CLSW enum FORMAT_CLSW enum O_CLSW enum TRACE_CLSW
Read the command line2.6 =
CommandLine::declare_heading( U"[[Purpose]]\n\n" U"usage: inter file1 file2 ... [options]\n"); CommandLine::declare_switch(O_CLSW, U"o", 2, U"code-generate to file X"); CommandLine::declare_textual_switch(FORMAT_CLSW, U"format", 1, U"code-generate -o output to format X (default is Text)"); CommandLine::declare_switch(PIPELINE_CLSW, U"pipeline-text", 2, U"specify pipeline textually, with X being a comma-separated list of stages"); CommandLine::declare_switch(PIPELINE_FILE_CLSW, U"pipeline-file", 2, U"specify pipeline as file X"); CommandLine::declare_switch(PIPELINE_VARIABLE_CLSW, U"variable", 2, U"set pipeline variable X (in form name=value)"); CommandLine::declare_switch(DOMAIN_CLSW, U"domain", 2, U"specify folder to read/write inter files from/to"); CommandLine::declare_switch(INTERNAL_CLSW, U"internal", 2, U"specify folder of internal Inform resources"); CommandLine::declare_switch(ARCHITECTURE_CLSW, U"architecture", 2, U"generate Inter with architecture X"); CommandLine::declare_switch(BUILD_KIT_CLSW, U"build-kit", 2, U"build Inter kit X for the current architecture"); CommandLine::declare_switch(CONSTRUCTS_CLSW, U"constructs", 1, U"print out table of all constructs in the Inter language"); CommandLine::declare_switch(ANNOTATIONS_CLSW, U"annotations", 1, U"print out table of all symbol annotations in the Inter language"); CommandLine::declare_switch(PRIMITIVES_CLSW, U"primitives", 1, U"print out table of all primitive invocations in the Inter language"); CommandLine::declare_boolean_switch(TRACE_CLSW, U"trace", 1, U"print out all pipeline steps as they are followed", FALSE); CommandLine::read(argc, argv, NULL, &Main::respond, &Main::add_file); path_to_inter = Pathnames::installation_path("INTER_PATH", I"inter");
- This code is used in §2.
void Main::respond(int id, int val, text_stream *arg, void *state) { switch (id) { case O_CLSW: output_file = Filenames::from_text(arg); break; case FORMAT_CLSW: output_format = Str::duplicate(arg); break; case PIPELINE_CLSW: pipeline_as_text = Str::duplicate(arg); break; case PIPELINE_FILE_CLSW: pipeline_as_file = Filenames::from_text(arg); break; case PIPELINE_VARIABLE_CLSW: Add a pipeline variable to the dictionary3.1; break; case DOMAIN_CLSW: domain_path = Pathnames::from_text(arg); break; case BUILD_KIT_CLSW: kit_to_build = Pathnames::from_text(arg); break; case INTERNAL_CLSW: internal_path = Pathnames::from_text(arg); break; case ARCHITECTURE_CLSW: if (PipelineModule::set_architecture(arg) == FALSE) Errors::fatal("no such -architecture"); break; case CONSTRUCTS_CLSW: InterInstruction::show_constructs(STDOUT); break; case ANNOTATIONS_CLSW: SymbolAnnotation::show_annotations(STDOUT); break; case PRIMITIVES_CLSW: Primitives::show_primitives(STDOUT); break; case TRACE_CLSW: tracing = (val)?TRUE:FALSE; break; } }
§3.1. Add a pipeline variable to the dictionary3.1 =
match_results mr = Regexp::create_mr(); if (Regexp::match(&mr, arg, U"(%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);
- This code is used in §3.
void Main::add_file(int id, text_stream *arg, void *state) { filename *F = Filenames::from_text(arg); ADD_TO_LINKED_LIST(F, filename, inter_file_list); }
§5. 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.
typedef void kind; kind *K_value = NULL;
§6. This is where the html module can find CSS files and similar resources:
define INSTALLED_FILES_HTML_CALLBACK Main::internal_path
pathname *Main::internal_path(void) { return internal_path; }