From b8c2a178e84a41ff06c7ec3498bfe0a690ad250f Mon Sep 17 00:00:00 2001 From: Graham Nelson Date: Tue, 18 Feb 2020 11:56:09 +0000 Subject: [PATCH] Added arch module and inbuild unit testing --- inbuild/.gitignore | 2 + inbuild/Chapter 1/Main.w | 57 ++++--- inbuild/Contents.w | 1 + .../Units/_Results_Ideal/compatibility.txt | 14 ++ inbuild/Tests/Units/compatibility.txt | 143 +++++++++++++++++ inbuild/Tests/inbuild.intest | 18 +++ inbuild/arch-module/Chapter 1/Arch Module.w | 53 +++++++ inbuild/arch-module/Chapter 2/Architectures.w | 68 ++++++++ inbuild/arch-module/Chapter 2/Compatibility.w | 148 ++++++++++++++++++ inbuild/arch-module/Contents.w | 12 ++ inbuild/gitignorescript.txt | 2 + .../inbuild-module/Chapter 4/Kit Services.w | 26 +-- .../Chapter 4/Project Services.w | 18 +++ inform7/Chapter 1/Main.w | 2 + inform7/Contents.w | 1 + .../core-module/Chapter 26/Virtual Machines.w | 19 --- inform7/multimedia-module/Chapter 2/Figures.w | 2 +- .../Chapter 2/Sound Effects.w | 2 +- inter/Chapter 1/Main.w | 15 +- inter/Contents.w | 1 + inter/codegen-module/Chapter 1/Architecture.w | 44 ++---- .../Chapter 1/Link Instructions.w | 7 +- scripts/makescript.txt | 4 + 23 files changed, 559 insertions(+), 100 deletions(-) create mode 100644 inbuild/Tests/Units/_Results_Ideal/compatibility.txt create mode 100644 inbuild/Tests/Units/compatibility.txt create mode 100644 inbuild/Tests/inbuild.intest create mode 100644 inbuild/arch-module/Chapter 1/Arch Module.w create mode 100644 inbuild/arch-module/Chapter 2/Architectures.w create mode 100644 inbuild/arch-module/Chapter 2/Compatibility.w create mode 100644 inbuild/arch-module/Contents.w diff --git a/inbuild/.gitignore b/inbuild/.gitignore index d388b4738..decf3f1f8 100644 --- a/inbuild/.gitignore +++ b/inbuild/.gitignore @@ -12,3 +12,5 @@ Tests/_Results_Actual/ inbuild.mk +Tests/Units/_Results_Actual/ + diff --git a/inbuild/Chapter 1/Main.w b/inbuild/Chapter 1/Main.w index 1ce0ca988..dd695aaee 100644 --- a/inbuild/Chapter 1/Main.w +++ b/inbuild/Chapter 1/Main.w @@ -23,11 +23,13 @@ int dry_run_mode = FALSE; linked_list *targets = NULL; /* of |inbuild_copy| */ inbuild_nest *destination_nest = NULL; text_stream *filter_text = NULL; +text_stream *unit_test = NULL; linked_list *inbuild_nest_list = NULL; int main(int argc, char **argv) { Foundation::start(); WordsModule::start(); + ArchModule::start(); InbuildModule::start(); targets = NEW_LINKED_LIST(inbuild_copy); @; @@ -37,33 +39,40 @@ int main(int argc, char **argv) { if (path_to_tools) BM = BuildSteps::methodology(path_to_tools, FALSE); else BM = BuildSteps::methodology(Pathnames::up(path_to_inbuild), TRUE); if (dry_run_mode == FALSE) BM->methodology = SHELL_METHODOLOGY; - if (Str::len(filter_text) > 0) { - TEMPORARY_TEXT(errors); - inbuild_requirement *req = Requirements::from_text(filter_text, errors); - if (Str::len(errors) > 0) { - Errors::with_text("requirement malformed: %S", errors); - } else { - linked_list *L = NEW_LINKED_LIST(inbuild_search_result); - Nests::search_for(req, inbuild_nest_list, L); - inbuild_search_result *R; - LOOP_OVER_LINKED_LIST(R, inbuild_search_result, L) { - ADD_TO_LINKED_LIST(R->copy, inbuild_copy, targets); + if (Str::len(unit_test) > 0) { + BM->methodology = DRY_RUN_METHODOLOGY; + if (Str::eq(unit_test, I"compatibility")) Compatibility::test(STDOUT); + else Errors::with_text("no such unit test: %S", unit_test); + } else { + if (Str::len(filter_text) > 0) { + TEMPORARY_TEXT(errors); + inbuild_requirement *req = Requirements::from_text(filter_text, errors); + if (Str::len(errors) > 0) { + Errors::with_text("requirement malformed: %S", errors); + } else { + linked_list *L = NEW_LINKED_LIST(inbuild_search_result); + Nests::search_for(req, inbuild_nest_list, L); + inbuild_search_result *R; + LOOP_OVER_LINKED_LIST(R, inbuild_search_result, L) { + ADD_TO_LINKED_LIST(R->copy, inbuild_copy, targets); + } } + DISCARD_TEXT(errors); } - DISCARD_TEXT(errors); - } - inbuild_copy *C; - LOOP_OVER_LINKED_LIST(C, inbuild_copy, targets) { - switch (inbuild_task) { - case INSPECT_TTASK: Copies::inspect(STDOUT, C); break; - case GRAPH_TTASK: Graphs::describe(STDOUT, C->vertex, TRUE); break; - case BUILD_TTASK: Graphs::build(C->vertex, BM); break; - case REBUILD_TTASK: Graphs::rebuild(C->vertex, BM); break; - case COPY_TO_TTASK: if (destination_nest) Nests::copy_to(C, destination_nest, FALSE, BM); break; - case SYNC_TO_TTASK: if (destination_nest) Nests::copy_to(C, destination_nest, TRUE, BM); break; + inbuild_copy *C; + LOOP_OVER_LINKED_LIST(C, inbuild_copy, targets) { + switch (inbuild_task) { + case INSPECT_TTASK: Copies::inspect(STDOUT, C); break; + case GRAPH_TTASK: Graphs::describe(STDOUT, C->vertex, TRUE); break; + case BUILD_TTASK: Graphs::build(C->vertex, BM); break; + case REBUILD_TTASK: Graphs::rebuild(C->vertex, BM); break; + case COPY_TO_TTASK: if (destination_nest) Nests::copy_to(C, destination_nest, FALSE, BM); break; + case SYNC_TO_TTASK: if (destination_nest) Nests::copy_to(C, destination_nest, TRUE, BM); break; + } } } WordsModule::end(); + ArchModule::end(); InbuildModule::end(); Foundation::end(); return 0; @@ -81,6 +90,7 @@ int main(int argc, char **argv) { @e MATCHING_CLSW @e COPY_TO_CLSW @e SYNC_TO_CLSW +@e UNIT_TEST_CLSW @ = CommandLine::declare_heading( @@ -106,6 +116,8 @@ int main(int argc, char **argv) { L"apply to all works in nest(s) matching requirement X"); CommandLine::declare_switch(CONTENTS_OF_CLSW, L"contents-of", 2, L"apply to all targets in the directory X"); + CommandLine::declare_switch(UNIT_TEST_CLSW, L"unit-test", 2, + L"perform unit test X (for debugging inbuild only)"); Inbuild::declare_options(); CommandLine::read(argc, argv, NULL, &Main::option, &Main::bareword); @@ -152,6 +164,7 @@ void Main::option(int id, int val, text_stream *arg, void *state) { case SYNC_TO_CLSW: inbuild_task = SYNC_TO_TTASK; destination_nest = Nests::new(Pathnames::from_text(arg)); break; + case UNIT_TEST_CLSW: unit_test = Str::duplicate(arg); break; } Inbuild::option(id, val, arg, state); } diff --git a/inbuild/Contents.w b/inbuild/Contents.w index cfa505cab..4ff9a9402 100644 --- a/inbuild/Contents.w +++ b/inbuild/Contents.w @@ -8,6 +8,7 @@ Version Name: Avignon Import: foundation Import: inform7/words +Import: arch Import: inbuild Preliminaries diff --git a/inbuild/Tests/Units/_Results_Ideal/compatibility.txt b/inbuild/Tests/Units/_Results_Ideal/compatibility.txt new file mode 100644 index 000000000..2b1a0371a --- /dev/null +++ b/inbuild/Tests/Units/_Results_Ideal/compatibility.txt @@ -0,0 +1,14 @@ +'for all': for all: 16=yes 16d=yes 32=yes 32d=yes +'all': for all: 16=yes 16d=yes 32=yes 32d=yes +'not for all': not a valid compatibility specification +'not all': not a valid compatibility specification +'for none': for none: 16=no 16d=no 32=no 32d=no +'none': for none: 16=no 16d=no 32=no 32d=no +'not for none': not a valid compatibility specification +'not none': not a valid compatibility specification +'for 16d': for 16d: 16=no 16d=yes 32=no 32d=no +'not for 32': not for 32: 16=yes 16d=yes 32=no 32d=yes +'for 16d or 32d': for 16d or 32d: 16=no 16d=yes 32=no 32d=yes +'not for 32 or 16': not for 32 or 16: 16=no 16d=yes 32=no 32d=yes +'for 16d, 32d or 32': for 16d, 32d or 32: 16=no 16d=yes 32=yes 32d=yes +'not for 16d, 32d or 32': not for 16d, 32d or 32: 16=yes 16d=no 32=no 32d=no diff --git a/inbuild/Tests/Units/compatibility.txt b/inbuild/Tests/Units/compatibility.txt new file mode 100644 index 000000000..ccaf2d747 --- /dev/null +++ b/inbuild/Tests/Units/compatibility.txt @@ -0,0 +1,143 @@ +schema + alpha.beta() +end +schema + alpha.beta(x) +end +schema + routine.call(x) +end +schema + (alpha.beta)(x) +end +schema + debug_rules = 2; say__p = 1; + "Rules tracing now switched to ~all~. Type ~rules off~ to switch it off again."; +end +schema + @erase_window -1; +end +schema + restore Somewhere; + .Somewhere; print "Here!"; +end +schema + "Hello, this + is a multiline string literal"; +end +schema + for (n=0:((n10) && (n<10)): n++) + print n; +end +schema + spaces j; + print (I7_string) str; +end +schema + if (i == 1) print "Okay"; + else "*** Arrcpy doesn't support this ***"; +end +schema + a-1 +end +schema + do { + print "Hi!"; + } until (x); +end +schema + do { + if (a) return wd; + } until (a); +end +schema + do { + if (line_tdata-->index == wd) return wd; + index++; + } until ((line_token-->index == ENDIT_TOKEN) || (((line_token-->index)->0 & $10) == 0)); +end +schema + print ""; +end +schema + switch (Y) { + X: print "A ", (string) o; + } +end +schema + #ifdef RANKING_TABLE; + ANNOUNCE_SCORE_RM('B'); + j = TableRows(RANKING_TABLE); + for (i=j:i>=1:i--) + if (score >= TableLookUpEntry(RANKING_TABLE, 1, i)) { + v = TableLookUpEntry(RANKING_TABLE, 2, i); + TEXT_TY_Say(v); + "."; + } + #endif; + ".";' +end +schema + if (B) if (A) { print "Yes"; } + print "No"; +end +schema + switch (scope_stage) { + 2: objectloop (obj) + PlaceInScope(obj, true); + } +end +schema + while (token ~= NULL) { + switch (token-->RE_CCLASS) { + DISJUNCTION_RE_CC: token-->RE_CONSTRAINT = -1; + QUANTIFIER_RE_CC: token-->RE_CONSTRAINT = -1; + } + if (token-->RE_DOWN) TEXT_TY_RE_EraseConstraints(token-->RE_DOWN); + token = token-->RE_NEXT; + } +end +schema + if (b) print 1; else print 2; +end +schema + a: if (b) print 1; else print 2; +end +schema + print_ret "This is ", (char) X, "."; +end +schema + @jl y 0 ?X; + @jl y 0 ?~X; + @jl y 0 ?rtrue; + @jl y 0 ?rfalse; + @jl y 0 ?~rtrue; + @jl y 0 ?~rfalse; +end +schema + switch (token-->RE_CCLASS) { + + ! Should never happen + + CHOICE_RE_CC: return "internal error"; + + ! Mode switches + + SENSITIVITY_RE_CC: + if (token-->RE_PAR1) mode_flags = mode_flags | CIS_MFLAG; + else mode_flags = mode_flags & (~CIS_MFLAG); + outcome = true; + + ! Zero-length positional markers + + ALWAYS_RE_CC: + outcome = true; + NEVER_RE_CC: + START_RE_CC: + if (ipos == 0) outcome = true; + END_RE_CC: + if (BlkValueRead(txt, ipos) == 0) outcome = true; + SOMETIMES_RE_CC: + outcome = true; + } +end diff --git a/inbuild/Tests/inbuild.intest b/inbuild/Tests/inbuild.intest new file mode 100644 index 000000000..6431e9998 --- /dev/null +++ b/inbuild/Tests/inbuild.intest @@ -0,0 +1,18 @@ +-cases [Units] 'inbuild/Tests/Units' + +-recipe [Units] + set: $A = $PATH/_Results_Actual/$CASE.txt + set: $I = $PATH/_Results_Ideal/$CASE.txt + + mkdir: $PATH/_Results_Actual + mkdir: $PATH/_Results_Ideal + + debugger: llvm -f inbuild/Tangled/inbuild -- -unit-test $CASE + step: inbuild/Tangled/inbuild -unit-test $CASE >$A 2>&1 + or: 'failed to produce output' $A + + show: $A + + match text: $A $I + or: 'produced incorrect output' +-end diff --git a/inbuild/arch-module/Chapter 1/Arch Module.w b/inbuild/arch-module/Chapter 1/Arch Module.w new file mode 100644 index 000000000..ee008424f --- /dev/null +++ b/inbuild/arch-module/Chapter 1/Arch Module.w @@ -0,0 +1,53 @@ +[ArchModule::] Arch Module. + +Setting up the use of this module. + +@h Introduction. + +@d ARCH_MODULE TRUE + +@ To begin with, this module needs to allocate memory: + +@e inter_architecture_MT +@e compatibility_specification_MT + += +ALLOCATE_INDIVIDUALLY(inter_architecture) +ALLOCATE_INDIVIDUALLY(compatibility_specification) + +@h The beginning. + += +void ArchModule::start(void) { + @; + @; + @; + @; + @; + Architectures::create(); +} + +@ + +@ = + ; + +@ = + ; + +@ + +@ = + ; + +@ = + ; + +@ = + ; + +@h The end. + += +void ArchModule::end(void) { +} diff --git a/inbuild/arch-module/Chapter 2/Architectures.w b/inbuild/arch-module/Chapter 2/Architectures.w new file mode 100644 index 000000000..c456c751d --- /dev/null +++ b/inbuild/arch-module/Chapter 2/Architectures.w @@ -0,0 +1,68 @@ +[Architectures::] Architectures. + +To deal with multiple inter architectures. + +@h Architectures. + += +typedef struct inter_architecture { + struct text_stream *shorthand; /* such as |32d| */ + int sixteen_bit; + int debug_enabled; + MEMORY_MANAGEMENT +} inter_architecture; + +inter_architecture *Architectures::new(text_stream *code, int s, int d) { + inter_architecture *A = CREATE(inter_architecture); + A->shorthand = Str::duplicate(code); + A->sixteen_bit = s; + A->debug_enabled = d; + return A; +} + +void Architectures::create(void) { + Architectures::new(I"16", TRUE, FALSE); + Architectures::new(I"16d", TRUE, TRUE); + Architectures::new(I"32", FALSE, FALSE); + Architectures::new(I"32d", FALSE, TRUE); +} + +filename *Architectures::canonical_binary(pathname *P, inter_architecture *A) { + if (A == NULL) internal_error("no arch"); + TEMPORARY_TEXT(leafname); + WRITE_TO(leafname, "arch-%S.interb", A->shorthand); + filename *F = Filenames::in_folder(P, leafname); + DISCARD_TEXT(leafname); + return F; +} + +filename *Architectures::canonical_textual(pathname *P, inter_architecture *A) { + if (A == NULL) internal_error("no arch"); + TEMPORARY_TEXT(leafname); + WRITE_TO(leafname, "arch-%S.intert", A->shorthand); + filename *F = Filenames::in_folder(P, leafname); + DISCARD_TEXT(leafname); + return F; +} + +text_stream *Architectures::to_codename(inter_architecture *A) { + if (A == NULL) return NULL; + return A->shorthand; +} + +inter_architecture *Architectures::from_codename(text_stream *name) { + inter_architecture *A; + LOOP_OVER(A, inter_architecture) + if (Str::eq_insensitive(A->shorthand, name)) + return A; + return NULL; +} + +int Architectures::sixteen_bit(inter_architecture *A) { + if (A == NULL) internal_error("no arch"); + return A->sixteen_bit; +} +int Architectures::debug_enabled(inter_architecture *A) { + if (A == NULL) internal_error("no arch"); + return A->debug_enabled; +} diff --git a/inbuild/arch-module/Chapter 2/Compatibility.w b/inbuild/arch-module/Chapter 2/Compatibility.w new file mode 100644 index 000000000..27aafac3a --- /dev/null +++ b/inbuild/arch-module/Chapter 2/Compatibility.w @@ -0,0 +1,148 @@ +[Compatibility::] Compatibility. + +To manage compatibility lists: what can be compiled to what format. + +@ + += +typedef struct compatibility_specification { + int default_allows; + struct linked_list *exceptions; /* of |inter_architecture| */ + MEMORY_MANAGEMENT +} compatibility_specification; + +compatibility_specification *Compatibility::all(void) { + compatibility_specification *C = CREATE(compatibility_specification); + C->default_allows = TRUE; + C->exceptions = NEW_LINKED_LIST(inter_architecture); + return C; +} + +void Compatibility::write(OUTPUT_STREAM, compatibility_specification *C) { + if (C == NULL) { WRITE("for none"); return; } + int x = LinkedLists::len(C->exceptions); + if (x == 0) { + if (C->default_allows) WRITE("for all"); + else WRITE("for none"); + } else { + if (C->default_allows) WRITE("not "); + WRITE("for "); + int n = 0; + inter_architecture *A; + LOOP_OVER_LINKED_LIST(A, inter_architecture, C->exceptions) { + n++; + if ((n > 1) && (n < x)) WRITE(", "); + if ((n > 1) && (n == x)) WRITE(" or "); + WRITE("%S", Architectures::to_codename(A)); + } + } +} + +compatibility_specification *Compatibility::from_text(text_stream *text) { + compatibility_specification *C = Compatibility::all(); + int incorrect = FALSE; + if (Str::len(text) == 0) return C; + TEMPORARY_TEXT(parse); + WRITE_TO(parse, "%S", text); + Str::trim_white_space(parse); + + C->default_allows = FALSE; + match_results mr = Regexp::create_mr(); + int negated = FALSE; + if (Regexp::match(&mr, parse, L"not (%c+)")) { + Str::clear(parse); + WRITE_TO(parse, "%S", mr.exp[0]); + Str::trim_white_space(parse); + C->default_allows = TRUE; + negated = TRUE; + } + + if (Regexp::match(&mr, parse, L"for (%c+)")) { + Str::clear(parse); + WRITE_TO(parse, "%S", mr.exp[0]); + Str::trim_white_space(parse); + } + + if (Str::eq(parse, I"all")) { + if (negated) incorrect = TRUE; /* "not for all" */ + C->default_allows = TRUE; + } else if (Str::eq(parse, I"none")) { + if (negated) incorrect = TRUE; /* "not for none" */ + C->default_allows = FALSE; + } else if (Compatibility::clause(C, parse) == FALSE) + incorrect = TRUE; + + DISCARD_TEXT(parse); + Regexp::dispose_of(&mr); + if (incorrect) C = NULL; + return C; +} + +int Compatibility::clause(compatibility_specification *C, text_stream *text) { + int correct = FALSE; + match_results mr = Regexp::create_mr(); + if (Regexp::match(&mr, text, L"(%c+?), (%c+)")) { + int a = Compatibility::clause(C, mr.exp[0]); + int b = Compatibility::clause(C, mr.exp[1]); + correct = a && b; + } else if (Regexp::match(&mr, text, L"(%c+?) or (%c+)")) { + int a = Compatibility::clause(C, mr.exp[0]); + int b = Compatibility::clause(C, mr.exp[1]); + correct = a && b; + } else { + inter_architecture *A = Architectures::from_codename(text); + if (A) { + int already_there = FALSE; + inter_architecture *X; + LOOP_OVER_LINKED_LIST(X, inter_architecture, C->exceptions) + if (A == X) + already_there = TRUE; + if (already_there == FALSE) { + ADD_TO_LINKED_LIST(A, inter_architecture, C->exceptions); + correct = TRUE; + } + } + } + Regexp::dispose_of(&mr); + return correct; +} + +int Compatibility::with(compatibility_specification *C, inter_architecture *A) { + if (C == NULL) return FALSE; + int decision = C->default_allows; + inter_architecture *X; + LOOP_OVER_LINKED_LIST(X, inter_architecture, C->exceptions) + if (A == X) + decision = decision?FALSE:TRUE; + return decision; +} + +void Compatibility::test(OUTPUT_STREAM) { + Compatibility::test_one(OUT, I"for all"); + Compatibility::test_one(OUT, I"all"); + Compatibility::test_one(OUT, I"not for all"); + Compatibility::test_one(OUT, I"not all"); + Compatibility::test_one(OUT, I"for none"); + Compatibility::test_one(OUT, I"none"); + Compatibility::test_one(OUT, I"not for none"); + Compatibility::test_one(OUT, I"not none"); + Compatibility::test_one(OUT, I"for 16d"); + Compatibility::test_one(OUT, I"not for 32"); + Compatibility::test_one(OUT, I"for 16d or 32d"); + Compatibility::test_one(OUT, I"not for 32 or 16"); + Compatibility::test_one(OUT, I"for 16d, 32d or 32"); + Compatibility::test_one(OUT, I"not for 16d, 32d or 32"); +} + +void Compatibility::test_one(OUTPUT_STREAM, text_stream *test) { + WRITE("'%S': ", test); + compatibility_specification *C = Compatibility::from_text(test); + if (C == NULL) { WRITE("not a valid compatibility specification\n"); return; } + Compatibility::write(OUT, C); + WRITE(":"); + inter_architecture *A; + LOOP_OVER(A, inter_architecture) + WRITE(" %S=%S", Architectures::to_codename(A), + (Compatibility::with(C, A))?I"yes":I"no"); + WRITE("\n"); +} diff --git a/inbuild/arch-module/Contents.w b/inbuild/arch-module/Contents.w new file mode 100644 index 000000000..b3cf2c2ac --- /dev/null +++ b/inbuild/arch-module/Contents.w @@ -0,0 +1,12 @@ +Title: arch +Author: Graham Nelson +Purpose: Definitions of Inter and final VM architectures. +Language: InC +Licence: Artistic License 2.0 + +Chapter 1: Setting Up + Arch Module + +Chapter 2: Architectures + Architectures + Compatibility diff --git a/inbuild/gitignorescript.txt b/inbuild/gitignorescript.txt index a2a4ef67d..29ae70259 100644 --- a/inbuild/gitignorescript.txt +++ b/inbuild/gitignorescript.txt @@ -1,3 +1,5 @@ {basics} inbuild.mk + +Tests/Units/_Results_Actual/ diff --git a/inbuild/inbuild-module/Chapter 4/Kit Services.w b/inbuild/inbuild-module/Chapter 4/Kit Services.w index c713bf119..5236fa2d1 100644 --- a/inbuild/inbuild-module/Chapter 4/Kit Services.w +++ b/inbuild/inbuild-module/Chapter 4/Kit Services.w @@ -205,20 +205,22 @@ void Kits::construct_graph(inform_kit *K) { inbuild_copy *C = K->as_copy; pathname *P = C->location_if_path; build_vertex *KV = C->vertex; - text_stream *archs[4] = { I"16", I"32", I"16d", I"32d" }; - text_stream *binaries[4] = { I"arch-16.interb", I"arch-32.interb", I"arch-16d.interb", I"arch-32d.interb" }; - build_vertex *BV[4]; - for (int i=0; i<4; i++) { - filename *FV = Filenames::in_folder(P, binaries[i]); - BV[i] = Graphs::file_vertex(FV); - Graphs::need_this_to_build(KV, BV[i]); - build_step *BS = BuildSteps::new_step(ASSIMILATE_BSTEP, P, archs[i]); - BuildSteps::add_step(BV[i]->script, BS); + linked_list *BVL = NEW_LINKED_LIST(build_vertex); + inter_architecture *A; + LOOP_OVER(A, inter_architecture) { + build_vertex *BV = Graphs::file_vertex(Architectures::canonical_binary(P, A)); + Graphs::need_this_to_build(KV, BV); + build_step *BS = BuildSteps::new_step( + ASSIMILATE_BSTEP, P, Architectures::to_codename(A)); + BuildSteps::add_step(BV->script, BS); + ADD_TO_LINKED_LIST(BV, build_vertex, BVL); } filename *contents_page = Filenames::in_folder(C->location_if_path, I"Contents.w"); build_vertex *CV = Graphs::file_vertex(contents_page); - for (int i=0; i<4; i++) Graphs::need_this_to_build(BV[i], CV); + build_vertex *BV; + LOOP_OVER_LINKED_LIST(BV, build_vertex, BVL) + Graphs::need_this_to_build(BV, CV); kit_contents_section_state CSS; CSS.active = FALSE; @@ -229,7 +231,9 @@ void Kits::construct_graph(inform_kit *K) { filename *SF = Filenames::in_folder( Pathnames::subfolder(C->location_if_path, I"Sections"), segment); build_vertex *SV = Graphs::file_vertex(SF); - for (int i=0; i<4; i++) Graphs::need_this_to_build(BV[i], SV); + build_vertex *BV; + LOOP_OVER_LINKED_LIST(BV, build_vertex, BVL) + Graphs::need_this_to_build(BV, SV); } inbuild_requirement *req; diff --git a/inbuild/inbuild-module/Chapter 4/Project Services.w b/inbuild/inbuild-module/Chapter 4/Project Services.w index 8b0fa7124..00c95ef68 100644 --- a/inbuild/inbuild-module/Chapter 4/Project Services.w +++ b/inbuild/inbuild-module/Chapter 4/Project Services.w @@ -12,6 +12,7 @@ typedef struct inform_project { struct inform_language *language_of_play; struct inform_language *language_of_syntax; struct inform_language *language_of_index; + int next_resource_number; MEMORY_MANAGEMENT } inform_project; @@ -25,6 +26,7 @@ inform_project *Projects::new_ip(text_stream *name, filename *F, pathname *P) { project->language_of_play = NULL; project->language_of_syntax = NULL; project->language_of_index = NULL; + project->next_resource_number = 3; return project; } @@ -62,6 +64,22 @@ void Projects::not_necessarily_parser_IF(inform_project *project) { project->assumed_to_be_parser_IF = FALSE; } +@ Resources in a Blorb file have unique ID numbers which are positive integers, +but these are not required to start from 1, nor to be contiguous. For Inform, +ID number 1 is reserved for the cover image (whether or not any cover image +is provided: it is legal for there to be figures but no cover, and vice versa). +Other figures, and sound effects, then mix freely as needed from ID number 3 +on upwards. We skip 2 so that it can be guaranteed that no sound resource +has ID 1 or 2: this is to help people trying to play sounds in the Z-machine, +where operand 1 or 2 in the |@sound| opcode signifies not a sound resource +number but a long or short beep. If a genuine sound effect had resource ID +1 or 2, therefore, it would be unplayable on the Z-machine. + += +int Projects::get_next_free_blorb_resource_ID(inform_project *project) { + return project->next_resource_number++; +} + void Projects::set_source_filename(inform_project *project, pathname *P, filename *F) { if (P) { filename *manifest = Filenames::in_folder(P, I"Contents.txt"); diff --git a/inform7/Chapter 1/Main.w b/inform7/Chapter 1/Main.w index c1aa6b475..1050f3332 100755 --- a/inform7/Chapter 1/Main.w +++ b/inform7/Chapter 1/Main.w @@ -55,6 +55,7 @@ int Main::core_inform_main(int argc, char *argv[]) { IFModule::start(); MultimediaModule::start(); IndexModule::start(); + ArchModule::start(); InterModule::start(); BuildingModule::start(); CodegenModule::start(); @@ -73,6 +74,7 @@ int Main::core_inform_main(int argc, char *argv[]) { IFModule::end(); IndexModule::end(); InterModule::end(); + ArchModule::end(); BuildingModule::end(); CodegenModule::end(); InbuildModule::end(); diff --git a/inform7/Contents.w b/inform7/Contents.w index 8bd7936de..dd910acbd 100644 --- a/inform7/Contents.w +++ b/inform7/Contents.w @@ -16,6 +16,7 @@ Import: syntax Import: problems Import: linguistics Import: kinds +Import: inbuild/arch Import: inter/inter Import: inbuild/inbuild Import: core diff --git a/inform7/core-module/Chapter 26/Virtual Machines.w b/inform7/core-module/Chapter 26/Virtual Machines.w index 500f999eb..399182d19 100644 --- a/inform7/core-module/Chapter 26/Virtual Machines.w +++ b/inform7/core-module/Chapter 26/Virtual Machines.w @@ -645,22 +645,3 @@ int VirtualMachines::compare_usage(const void *ent1, const void *ent2) { if (v2->bytes_used != v1->bytes_used) return v2->bytes_used - v1->bytes_used; return Wordings::first_wn(v1->structure_name) - Wordings::first_wn(v2->structure_name); } - -@h Resource ID numbers. -Resources in a Blorb file have unique ID numbers which are positive integers, -but these are not required to start from 1, nor to be contiguous. For Inform, -ID number 1 is reserved for the cover image (whether or not any cover image -is provided: it is legal for there to be figures but no cover, and vice versa). -Other figures, and sound effects, then mix freely as needed from ID number 3 -on upwards. We skip 2 so that it can be guaranteed that no sound resource -has ID 1 or 2: this is to help people trying to play sounds in the Z-machine, -where operand 1 or 2 in the |@sound| opcode signifies not a sound resource -number but a long or short beep. If a genuine sound effect had resource ID -1 or 2, therefore, it would be unplayable on the Z-machine. - -= -int next_free_resource_ID = 3; - -int VirtualMachines::get_next_free_blorb_resource_ID(void) { - return next_free_resource_ID++; -} diff --git a/inform7/multimedia-module/Chapter 2/Figures.w b/inform7/multimedia-module/Chapter 2/Figures.w index 11c650054..a6356c154 100644 --- a/inform7/multimedia-module/Chapter 2/Figures.w +++ b/inform7/multimedia-module/Chapter 2/Figures.w @@ -160,7 +160,7 @@ void PL::Figures::register_figure(wording F, wording FN) { bf->name = F; if (wn >= 0) { - bf->figure_number = VirtualMachines::get_next_free_blorb_resource_ID(); + bf->figure_number = Projects::get_next_free_blorb_resource_ID(Inbuild::project()); TEMPORARY_TEXT(leaf); WRITE_TO(leaf, "%N", wn); bf->filename_of_image_file = Filenames::in_folder(pathname_of_materials_figures, leaf); diff --git a/inform7/multimedia-module/Chapter 2/Sound Effects.w b/inform7/multimedia-module/Chapter 2/Sound Effects.w index 1b9c8677c..16c4f7298 100644 --- a/inform7/multimedia-module/Chapter 2/Sound Effects.w +++ b/inform7/multimedia-module/Chapter 2/Sound Effects.w @@ -151,7 +151,7 @@ void PL::Sounds::register_sound(wording F, wording FN) { DISCARD_TEXT(leaf); bs->name = F; - bs->sound_number = VirtualMachines::get_next_free_blorb_resource_ID(); + bs->sound_number = Projects::get_next_free_blorb_resource_ID(Inbuild::project()); bs->alt_description = <>; LOGIF(FIGURE_CREATIONS, diff --git a/inter/Chapter 1/Main.w b/inter/Chapter 1/Main.w index 70cb2026c..33dd0bc89 100644 --- a/inter/Chapter 1/Main.w +++ b/inter/Chapter 1/Main.w @@ -32,6 +32,7 @@ linked_list *requirements_list = NULL; int main(int argc, char **argv) { Foundation::start(); + ArchModule::start(); InterModule::start(); BuildingModule::start(); CodegenModule::start(); @@ -70,22 +71,17 @@ int main(int argc, char **argv) { CommandLine::read(argc, argv, NULL, &Main::respond, &Main::add_file); if (template_action == ASSIMILATE_CLSW) { - text_stream *name = CodeGen::Architecture::leafname(); - if (Str::len(name) == 0) Errors::fatal("no -architecture given"); + inter_architecture *A = CodeGen::Architecture::current(); + if (A == NULL) Errors::fatal("no -architecture given"); + filename *assim = Architectures::canonical_binary(template_path, A); + filename *assim_t = Architectures::canonical_textual(template_path, A); pipeline_as_file = Filenames::in_folder(path_to_pipelines, I"assimilate.interpipeline"); - TEMPORARY_TEXT(leafname); - WRITE_TO(leafname, "%S.interb", name); - filename *assim = Filenames::in_folder(template_path, leafname); TEMPORARY_TEXT(fullname); WRITE_TO(fullname, "%f", assim); Str::copy(Dictionaries::create_text(pipeline_vars, I"*out"), fullname); - Str::clear(leafname); Str::clear(fullname); - WRITE_TO(leafname, "%S.intert", name); - filename *assim_t = Filenames::in_folder(template_path, leafname); WRITE_TO(fullname, "%f", assim_t); Str::copy(Dictionaries::create_text(pipeline_vars, I"*outt"), fullname); - DISCARD_TEXT(leafname); DISCARD_TEXT(fullname); match_results mr = Regexp::create_mr(); Str::copy(Dictionaries::create_text(pipeline_vars, I"*attach"), Pathnames::directory_name(template_path)); @@ -97,6 +93,7 @@ int main(int argc, char **argv) { InterModule::end(); BuildingModule::end(); CodegenModule::end(); + ArchModule::end(); Foundation::end(); if (Errors::have_occurred()) return 1; diff --git a/inter/Contents.w b/inter/Contents.w index 0a9828823..b83e10008 100644 --- a/inter/Contents.w +++ b/inter/Contents.w @@ -8,6 +8,7 @@ Version Name: Axion Import: foundation Import: inform7/words +Import: inbuild/arch Import: inter Import: building Import: codegen diff --git a/inter/codegen-module/Chapter 1/Architecture.w b/inter/codegen-module/Chapter 1/Architecture.w index cc2fd731d..e648fd43a 100644 --- a/inter/codegen-module/Chapter 1/Architecture.w +++ b/inter/codegen-module/Chapter 1/Architecture.w @@ -2,36 +2,18 @@ To deal with multiple inter architectures. -@h Architectures. -These are simply enumerated, for now. - -@e NO_ARCHITECTURE from 0 -@e A_16_ARCHITECTURE -@e A_16D_ARCHITECTURE -@e A_32_ARCHITECTURE -@e A_32D_ARCHITECTURE +@h Current architecture. = -int current_architecture = NO_ARCHITECTURE; +inter_architecture *current_architecture = NULL; int CodeGen::Architecture::set(text_stream *name) { - int setting = NO_ARCHITECTURE; - if (Str::eq_insensitive(name, I"16")) setting = A_16_ARCHITECTURE; - if (Str::eq_insensitive(name, I"32")) setting = A_32_ARCHITECTURE; - if (Str::eq_insensitive(name, I"16d")) setting = A_16D_ARCHITECTURE; - if (Str::eq_insensitive(name, I"32d")) setting = A_32D_ARCHITECTURE; - if (setting == NO_ARCHITECTURE) return FALSE; - current_architecture = setting; - return TRUE; + current_architecture = Architectures::from_codename(name); + if (current_architecture) return TRUE; + return FALSE; } -text_stream *CodeGen::Architecture::leafname(void) { - switch (current_architecture) { - case A_16_ARCHITECTURE: return I"arch-16"; - case A_16D_ARCHITECTURE: return I"arch-16d"; - case A_32_ARCHITECTURE: return I"arch-32"; - case A_32D_ARCHITECTURE: return I"arch-32d"; - } - return NULL; +inter_architecture *CodeGen::Architecture::current(void) { + return current_architecture; } @h Prepare stage. @@ -42,14 +24,10 @@ void CodeGen::Architecture::create_pipeline_stage(void) { } int CodeGen::Architecture::run_prepare_stage(pipeline_step *step) { - switch (current_architecture) { - case NO_ARCHITECTURE: internal_error("no architecture set"); - case A_16_ARCHITECTURE: return CodeGen::Architecture::run_prepare_stage_inner(step, TRUE, FALSE); - case A_16D_ARCHITECTURE: return CodeGen::Architecture::run_prepare_stage_inner(step, TRUE, TRUE); - case A_32_ARCHITECTURE: return CodeGen::Architecture::run_prepare_stage_inner(step, FALSE, FALSE); - case A_32D_ARCHITECTURE: return CodeGen::Architecture::run_prepare_stage_inner(step, FALSE, TRUE); - } - return FALSE; + if (current_architecture == NULL) internal_error("no architecture set"); + return CodeGen::Architecture::run_prepare_stage_inner(step, + Architectures::sixteen_bit(current_architecture), + Architectures::debug_enabled(current_architecture)); } int CodeGen::Architecture::run_prepare_stage_inner(pipeline_step *step, int Z, int D) { diff --git a/inter/codegen-module/Chapter 1/Link Instructions.w b/inter/codegen-module/Chapter 1/Link Instructions.w index f6797db91..f43fce00a 100644 --- a/inter/codegen-module/Chapter 1/Link Instructions.w +++ b/inter/codegen-module/Chapter 1/Link Instructions.w @@ -29,11 +29,10 @@ void CodeGen::LinkInstructions::create_pipeline_stage(void) { int CodeGen::LinkInstructions::run_link_stage(pipeline_step *step) { link_instruction *req; LOOP_OVER_LINKED_LIST(req, link_instruction, step->requirements_list) { - TEMPORARY_TEXT(leafname); - WRITE_TO(leafname, "%S.interb", CodeGen::Architecture::leafname()); - filename *arch_file = Filenames::in_folder(req->location, leafname); + inter_architecture *A = CodeGen::Architecture::current(); + if (A == NULL) Errors::fatal("no -architecture given"); + filename *arch_file = Architectures::canonical_binary(req->location, A); if (TextFiles::exists(arch_file) == FALSE) internal_error("no arch file for requirement"); - DISCARD_TEXT(leafname); inter_tree *sidecar = Inter::Tree::new(); if (Inter::Binary::test_file(arch_file)) Inter::Binary::read(sidecar, arch_file); diff --git a/scripts/makescript.txt b/scripts/makescript.txt index b6011cd87..d73113232 100644 --- a/scripts/makescript.txt +++ b/scripts/makescript.txt @@ -61,6 +61,7 @@ INBUILDX = inbuild/Tangled/inbuild {module} INTER inter inter/inter-module {module} BUILDING building inter/building-module {module} CODEGEN codegen inter/codegen-module +{module} ARCH arch inbuild/arch-module {module} INBUILD inbuild inbuild/inbuild-module # First, the tools we need to make, using the same declaration notation. @@ -87,6 +88,7 @@ INBUILDX = inbuild/Tangled/inbuild {dep} INFORM7 on IF {dep} INFORM7 on MULTIMEDIA {dep} INFORM7 on INDEX +{dep} INFORM7 on ARCH {dep} INFORM7 on INTER {dep} INFORM7 on BUILDING {dep} INFORM7 on CODEGEN @@ -101,10 +103,12 @@ INBUILDX = inbuild/Tangled/inbuild {tool} INBUILDTOOL inbuild inbuild {dep} INBUILDTOOL on FOUNDATION {dep} INBUILDTOOL on WORDS +{dep} INBUILDTOOL on ARCH {dep} INBUILDTOOL on INBUILD {tool} INTERTOOL inter inter {dep} INTERTOOL on FOUNDATION +{dep} INTERTOOL on ARCH {dep} INTERTOOL on INTER {dep} INTERTOOL on BUILDING {dep} INTERTOOL on CODEGEN