To build and run through pipelines of code generation stages.
§1. Steps. A "step" is a single step in a pipeline of commands: it consists of a choice of stage, together with a choice of argument. The other elements here are all temporary storage for information needed when the step is run; they have no meaningful contents when the step is not running.
typedef struct pipeline_step { struct pipeline_stage *step_stage; struct text_stream *step_argument; struct code_generation_target *target_argument; struct text_stream *package_argument; struct filename *parsed_filename; struct linked_list *the_PP; of pathname int to_debugging_log; int from_memory; int repository_argument; struct text_stream *text_out_file; struct linked_list *requirements_list; of inter_library struct inter_tree *repository; struct codegen_pipeline *pipeline; CLASS_DEFINITION } pipeline_step; pipeline_step *CodeGen::Pipeline::new_step(void) { pipeline_step *step = CREATE(pipeline_step); step->step_stage = NULL; step->step_argument = NULL; step->package_argument = NULL; step->repository_argument = 0; CodeGen::Pipeline::clean_step(step); return step; }
- The structure pipeline_step is accessed in 1/stg, 1/arc, 1/li, 2/mt, 2/plm, 2/rcc, 2/ass, 2/res, 2/ip, 2/unq, 2/rv, 2/erm, 2/erl, 2/ero, 3/su and here.
§2. This wipes clean the temporary storage for a step.
void CodeGen::Pipeline::clean_step(pipeline_step *step) { step->parsed_filename = NULL; step->text_out_file = NULL; step->to_debugging_log = FALSE; step->from_memory = FALSE; step->the_PP = NULL; step->repository = NULL; step->pipeline = NULL; step->requirements_list = NEW_LINKED_LIST(inter_library); }
§3. Here we write a textual description to a string, which is useful for logging:
void CodeGen::Pipeline::write_step(OUTPUT_STREAM, pipeline_step *step) { WRITE("%S", step->step_stage->stage_name); if (step->step_stage->stage_arg != NO_STAGE_ARG) { if (step->repository_argument > 0) { WRITE(" %d", step->repository_argument); if (Str::len(step->package_argument) > 0) WRITE(":%S", step->package_argument); } else { if (Str::len(step->package_argument) > 0) WRITE(" %S", step->package_argument); } if (step->step_stage->takes_repository) WRITE(" <- %S", step->step_argument); if (step->target_argument) WRITE(" %S -> %S", step->target_argument->target_name, step->step_argument); } } pipeline_step *CodeGen::Pipeline::read_step(text_stream *step, dictionary *D, text_file_position *tfp) { CodeGen::Stage::make_stages(); CodeGen::Targets::make_targets(); pipeline_step *ST = CodeGen::Pipeline::new_step(); match_results mr = Regexp::create_mr(); int left_arrow_used = FALSE; if (Regexp::match(&mr, step, L"(%c+?) *<- *(%c*)")) { if (Str::len(mr.exp[1]) > 0) { ST->step_argument = CodeGen::Pipeline::read_parameter(mr.exp[1], D, tfp); if (ST->step_argument == NULL) return NULL; } else { Errors::in_text_file_S(I"no source to right of arrow", tfp); return NULL; } Str::copy(step, mr.exp[0]); left_arrow_used = TRUE; } else if (Regexp::match(&mr, step, L"(%c+?) *(%C*) *-> *(%c*)")) { code_generation_target *cgt; LOOP_OVER(cgt, code_generation_target) if (Str::eq(mr.exp[1], cgt->target_name)) ST->target_argument = cgt; if (ST->target_argument == NULL) { TEMPORARY_TEXT(ERR) WRITE_TO(ERR, "no such code generation format as '%S'\n", mr.exp[1]); Errors::in_text_file_S(ERR, tfp); DISCARD_TEXT(ERR) return NULL; } ST->step_argument = CodeGen::Pipeline::read_parameter(mr.exp[2], D, tfp); if (ST->step_argument == NULL) return NULL; Str::copy(step, mr.exp[0]); } if (Regexp::match(&mr, step, L"(%C+?) (%d)")) { ST->repository_argument = Str::atoi(mr.exp[1], 0); Str::copy(step, mr.exp[0]); } else if (Regexp::match(&mr, step, L"(%C+?) (%d):(%c*)")) { ST->repository_argument = Str::atoi(mr.exp[1], 0); if (Str::len(mr.exp[2]) > 0) { ST->package_argument = CodeGen::Pipeline::read_parameter(mr.exp[2], D, tfp); if (ST->package_argument == NULL) return NULL; } Str::copy(step, mr.exp[0]); } else if (Regexp::match(&mr, step, L"(%C+?) (%c+)")) { ST->package_argument = CodeGen::Pipeline::read_parameter(mr.exp[1], D, tfp); if (ST->package_argument == NULL) return NULL; Str::copy(step, mr.exp[0]); } pipeline_stage *stage; LOOP_OVER(stage, pipeline_stage) if (Str::eq(step, stage->stage_name)) ST->step_stage = stage; if (ST->step_stage == NULL) { TEMPORARY_TEXT(ERR) WRITE_TO(ERR, "no such stage as '%S'\n", step); Errors::in_text_file_S(ERR, tfp); DISCARD_TEXT(ERR) return NULL; } if (ST->step_stage->takes_repository) { if (left_arrow_used == FALSE) { Errors::in_text_file_S(I"this stage should take a left arrow and a source", tfp); return NULL; } } else { if (left_arrow_used) { Errors::in_text_file_S(I"this stage should not take a left arrow and a source", tfp); return NULL; } } Regexp::dispose_of(&mr); return ST; } text_stream *CodeGen::Pipeline::read_parameter(text_stream *from, dictionary *D, text_file_position *tfp) { if (Str::get_first_char(from) == '*') { text_stream *find = Dictionaries::get_text(D, from); if (find) return Str::duplicate(find); TEMPORARY_TEXT(ERR) WRITE_TO(ERR, "no such pipeline variable as '%S'\n", from); Errors::in_text_file_S(ERR, tfp); DISCARD_TEXT(ERR) } return Str::duplicate(from); }
§4. Pipelines. And then a pipeline is just a linked list of steps.
typedef struct codegen_pipeline { struct dictionary *variables; struct inter_tree *memory_repository; struct inter_tree *repositories[10]; struct linked_list *steps; of pipeline_step int erroneous; CLASS_DEFINITION } codegen_pipeline; dictionary *CodeGen::Pipeline::basic_dictionary(text_stream *leafname) { dictionary *D = Dictionaries::new(16, TRUE); if (Str::len(leafname) > 0) Str::copy(Dictionaries::create_text(D, I"*out"), leafname); Str::copy(Dictionaries::create_text(D, I"*log"), I"*log"); return D; } codegen_pipeline *CodeGen::Pipeline::new(dictionary *D) { codegen_pipeline *S = CREATE(codegen_pipeline); S->variables = D; S->steps = NEW_LINKED_LIST(pipeline_step); S->memory_repository = NULL; S->erroneous = FALSE; for (int i=0; i<10; i++) S->repositories[i] = NULL; return S; } codegen_pipeline *CodeGen::Pipeline::parse_from_file(filename *F, dictionary *D) { codegen_pipeline *S = CodeGen::Pipeline::new(D); TextFiles::read(F, FALSE, "can't open inter pipeline file", TRUE, CodeGen::Pipeline::scan_line, NULL, (void *) S); if (S->erroneous) return NULL; return S; } void CodeGen::Pipeline::scan_line(text_stream *line, text_file_position *tfp, void *X) { codegen_pipeline *S = (codegen_pipeline *) X; CodeGen::Pipeline::parse_into(S, line, tfp); } codegen_pipeline *CodeGen::Pipeline::parse(text_stream *instructions, dictionary *D) { codegen_pipeline *S = CodeGen::Pipeline::new(D); CodeGen::Pipeline::parse_into(S, instructions, NULL); if (S->erroneous) return NULL; return S; } void CodeGen::Pipeline::parse_into(codegen_pipeline *S, text_stream *instructions, text_file_position *tfp) { TEMPORARY_TEXT(T) LOOP_THROUGH_TEXT(P, instructions) if (Characters::is_babel_whitespace(Str::get(P))) PUT_TO(T, ' '); else PUT_TO(T, Str::get(P)); match_results mr = Regexp::create_mr(); while (Regexp::match(&mr, T, L" *(%c+?) *,+ *(%c*?) *")) { pipeline_step *ST = CodeGen::Pipeline::read_step(mr.exp[0], S->variables, tfp); if (ST) ADD_TO_LINKED_LIST(ST, pipeline_step, S->steps); else S->erroneous = TRUE; Str::copy(T, mr.exp[1]); } if (Regexp::match(&mr, T, L" *(%c+?) *")) { pipeline_step *ST = CodeGen::Pipeline::read_step(mr.exp[0], S->variables, tfp); if (ST) ADD_TO_LINKED_LIST(ST, pipeline_step, S->steps); else S->erroneous = TRUE; } Regexp::dispose_of(&mr); DISCARD_TEXT(T) } void CodeGen::Pipeline::set_repository(codegen_pipeline *S, inter_tree *I) { S->memory_repository = I; } void CodeGen::Pipeline::run(pathname *P, codegen_pipeline *S, linked_list *PP, linked_list *requirements_list) { if (S == NULL) return; stopwatch_timer *within = NULL; #ifdef CORE_MODULE within = inform7_timer; #endif stopwatch_timer *pipeline_timer = Time::start_stopwatch(within, I"running Inter pipeline"); int step_count = 0, step_total = 0; pipeline_step *step; LOOP_OVER_LINKED_LIST(step, pipeline_step, S->steps) step_total++; int active = TRUE; stopwatch_timer *prep_timer = NULL; LOOP_OVER_LINKED_LIST(step, pipeline_step, S->steps) if (active) { if (prep_timer == NULL) prep_timer = Time::start_stopwatch(pipeline_timer, I"step preparation"); else Time::resume_stopwatch(prep_timer); if (S->repositories[step->repository_argument] == NULL) S->repositories[step->repository_argument] = InterTree::new(); inter_tree *I = S->repositories[step->repository_argument]; if (I == NULL) internal_error("no repository"); CodeGen::Pipeline::prepare_to_run(I); CodeGen::Pipeline::lint(I); CodeGen::Pipeline::clean_step(step); step->the_PP = PP; step->repository = I; step->pipeline = S; step->requirements_list = requirements_list; Time::stop_stopwatch(prep_timer); int skip_step = FALSE; TEMPORARY_TEXT(STAGE_NAME) WRITE_TO(STAGE_NAME, "inter step %d/%d: ", ++step_count, step_total); CodeGen::Pipeline::write_step(STAGE_NAME, step); Log::new_stage(STAGE_NAME); stopwatch_timer *step_timer = Time::start_stopwatch(pipeline_timer, STAGE_NAME); DISCARD_TEXT(STAGE_NAME) if ((step->step_stage->stage_arg == FILE_STAGE_ARG) || (step->step_stage->stage_arg == TEXT_OUT_STAGE_ARG) || (step->step_stage->stage_arg == EXT_FILE_STAGE_ARG) || (step->step_stage->stage_arg == EXT_TEXT_OUT_STAGE_ARG)) { if (Str::eq(step->step_argument, I"*log")) { step->to_debugging_log = TRUE; } else if (Str::eq(step->step_argument, I"*memory")) { S->repositories[step->repository_argument] = S->memory_repository; skip_step = TRUE; } else { int slashes = FALSE; LOOP_THROUGH_TEXT(pos, step->step_argument) if (Str::get(pos) == '/') slashes = TRUE; if (slashes) step->parsed_filename = Filenames::from_text(step->step_argument); else step->parsed_filename = Filenames::in(P, step->step_argument); } } text_stream text_output_struct; For any text file we might write text_stream *T = &text_output_struct; if (step->to_debugging_log) { step->text_out_file = DL; } else if ((step->step_stage->stage_arg == TEXT_OUT_STAGE_ARG) || (step->step_stage->stage_arg == EXT_TEXT_OUT_STAGE_ARG)) { if (STREAM_OPEN_TO_FILE(T, step->parsed_filename, ISO_ENC) == FALSE) { #ifdef PROBLEMS_MODULE Problems::fatal_on_file("Can't open output file", step->parsed_filename); #endif #ifndef PROBLEMS_MODULE Errors::fatal_with_file("Can't open output file", step->parsed_filename); exit(1); #endif } step->text_out_file = T; } if (skip_step == FALSE) active = (*(step->step_stage->execute))(step); if (((step->step_stage->stage_arg == TEXT_OUT_STAGE_ARG) || (step->step_stage->stage_arg == EXT_TEXT_OUT_STAGE_ARG)) && (step->to_debugging_log == FALSE)) { STREAM_CLOSE(T); } Time::stop_stopwatch(step_timer); } Time::stop_stopwatch(pipeline_timer); }
- The structure codegen_pipeline is accessed in 1/stg and here.
inter_symbol *unchecked_kind_symbol = NULL; inter_symbol *unchecked_function_symbol = NULL; inter_symbol *typeless_int_symbol = NULL; inter_symbol *list_of_unchecked_kind_symbol = NULL; inter_symbol *object_kind_symbol = NULL; inter_symbol *action_kind_symbol = NULL; inter_symbol *truth_state_kind_symbol = NULL; inter_symbol *direction_kind_symbol = NULL; inter_symbol *verb_directive_reverse_symbol = NULL; inter_symbol *verb_directive_slash_symbol = NULL; inter_symbol *verb_directive_divider_symbol = NULL; inter_symbol *verb_directive_result_symbol = NULL; inter_symbol *verb_directive_special_symbol = NULL; inter_symbol *verb_directive_number_symbol = NULL; inter_symbol *verb_directive_noun_symbol = NULL; inter_symbol *verb_directive_multi_symbol = NULL; inter_symbol *verb_directive_multiinside_symbol = NULL; inter_symbol *verb_directive_multiheld_symbol = NULL; inter_symbol *verb_directive_held_symbol = NULL; inter_symbol *verb_directive_creature_symbol = NULL; inter_symbol *verb_directive_topic_symbol = NULL; inter_symbol *verb_directive_multiexcept_symbol = NULL; inter_symbol *code_ptype_symbol = NULL; inter_symbol *plain_ptype_symbol = NULL; inter_symbol *submodule_ptype_symbol = NULL; inter_symbol *function_ptype_symbol = NULL; inter_symbol *action_ptype_symbol = NULL; inter_symbol *command_ptype_symbol = NULL; inter_symbol *property_ptype_symbol = NULL; inter_symbol *to_phrase_ptype_symbol = NULL; void CodeGen::Pipeline::prepare_to_run(inter_tree *I) { code_ptype_symbol = InterSymbolsTables::url_name_to_symbol(I, NULL, I"/_code"); plain_ptype_symbol = InterSymbolsTables::url_name_to_symbol(I, NULL, I"/_plain"); submodule_ptype_symbol = InterSymbolsTables::url_name_to_symbol(I, NULL, I"/_submodule"); function_ptype_symbol = InterSymbolsTables::url_name_to_symbol(I, NULL, I"/_function"); action_ptype_symbol = InterSymbolsTables::url_name_to_symbol(I, NULL, I"/_action"); command_ptype_symbol = InterSymbolsTables::url_name_to_symbol(I, NULL, I"/_command"); property_ptype_symbol = InterSymbolsTables::url_name_to_symbol(I, NULL, I"/_property"); to_phrase_ptype_symbol = InterSymbolsTables::url_name_to_symbol(I, NULL, I"/_to_phrase"); unchecked_kind_symbol = Inter::Packages::search_resources_exhaustively(I, I"K_unchecked"); unchecked_function_symbol = Inter::Packages::search_resources_exhaustively(I, I"K_unchecked_function"); typeless_int_symbol = Inter::Packages::search_resources_exhaustively(I, I"K_typeless_int"); list_of_unchecked_kind_symbol = Inter::Packages::search_resources_exhaustively(I, I"K_list_of_values"); object_kind_symbol = Inter::Packages::search_resources_exhaustively(I, I"K_object"); action_kind_symbol = Inter::Packages::search_resources_exhaustively(I, I"K_action_name"); truth_state_kind_symbol = Inter::Packages::search_resources_exhaustively(I, I"K_truth_state"); direction_kind_symbol = Inter::Packages::search_resources_exhaustively(I, I"K3_direction"); verb_directive_reverse_symbol = Inter::Packages::search_resources_exhaustively(I, I"VERB_DIRECTIVE_REVERSE"); verb_directive_slash_symbol = Inter::Packages::search_resources_exhaustively(I, I"VERB_DIRECTIVE_SLASH"); verb_directive_divider_symbol = Inter::Packages::search_resources_exhaustively(I, I"VERB_DIRECTIVE_DIVIDER"); verb_directive_result_symbol = Inter::Packages::search_resources_exhaustively(I, I"VERB_DIRECTIVE_RESULT"); verb_directive_special_symbol = Inter::Packages::search_resources_exhaustively(I, I"VERB_DIRECTIVE_SPECIAL"); verb_directive_number_symbol = Inter::Packages::search_resources_exhaustively(I, I"VERB_DIRECTIVE_NUMBER"); verb_directive_noun_symbol = Inter::Packages::search_resources_exhaustively(I, I"VERB_DIRECTIVE_NOUN"); verb_directive_multi_symbol = Inter::Packages::search_resources_exhaustively(I, I"VERB_DIRECTIVE_MULTI"); verb_directive_multiinside_symbol = Inter::Packages::search_resources_exhaustively(I, I"VERB_DIRECTIVE_MULTIINSIDE"); verb_directive_multiheld_symbol = Inter::Packages::search_resources_exhaustively(I, I"VERB_DIRECTIVE_MULTIHELD"); verb_directive_held_symbol = Inter::Packages::search_resources_exhaustively(I, I"VERB_DIRECTIVE_HELD"); verb_directive_creature_symbol = Inter::Packages::search_resources_exhaustively(I, I"VERB_DIRECTIVE_CREATURE"); verb_directive_topic_symbol = Inter::Packages::search_resources_exhaustively(I, I"VERB_DIRECTIVE_TOPIC"); verb_directive_multiexcept_symbol = Inter::Packages::search_resources_exhaustively(I, I"VERB_DIRECTIVE_MULTIEXCEPT"); } void CodeGen::Pipeline::lint(inter_tree *I) { InterTree::traverse(I, CodeGen::Pipeline::visitor, NULL, NULL, -PACKAGE_IST); } void CodeGen::Pipeline::visitor(inter_tree *I, inter_tree_node *P, void *state) { inter_ti c = Inode::get_package(P)->index_n; inter_ti a = Inode::get_package_alt(P); if (c != a) { LOG("Frame gives package as $6, but its location is in package $6\n", Inode::ID_to_package(P, c), Inode::ID_to_package(P, a)); WRITE_TO(STDERR, "Frame gives package as %d, but its location is in package %d\n", Inode::ID_to_package(P, c)->index_n, Inode::ID_to_package(P, a)->index_n); internal_error("misplaced package"); } Produce::guard(Inter::Defn::verify_children_inner(P)); } inter_symbol *CodeGen::Pipeline::uks(void) { if (unchecked_kind_symbol == NULL) internal_error("no unchecked kind symbol"); return unchecked_kind_symbol; }