From 8bb060c5765728e01d76b53b4ba879a8df6956d3 Mon Sep 17 00:00:00 2001
From: Graham Nelson
define XML_BIBTEXT_MODE 1 +define TRUNCATE_BIBTEXT_MODE 2 +define I6_BIBTEXT_MODE 3 +define HTML_BIBTEXT_MODE 4 +
-void BibliographicData::compile_bibliographic_text(OUTPUT_STREAM, wchar_t *p) { +void BibliographicData::compile_bibliographic_text(OUTPUT_STREAM, wchar_t *p, int mode) { if (p == NULL) return; - if (TEST_COMPILATION_MODE(COMPILE_TEXT_TO_XML_CMODE)) + if (mode == XML_BIBTEXT_MODE) Compile bibliographic text as XML respecting Treaty of Babel rules11.1; - if (TEST_COMPILATION_MODE(TRUNCATE_TEXT_CMODE)) + if (mode == TRUNCATE_BIBTEXT_MODE) Compile bibliographic text as a truncated filename11.4; - if (TEST_COMPILATION_MODE(COMPILE_TEXT_TO_I6_CMODE)) + if ((encode_constant_text_bibliographically) || (mode == I6_BIBTEXT_MODE)) Compile bibliographic text as an I6 string11.3 Compile bibliographic text as HTML11.2; } @@ -487,7 +492,7 @@ inside Inform. For instance, if a project is called-"St. Bartholemew's Fair: \'Etude for a Push-Me/Pull-You Machine"
+"St. Bartholemew's Fair: Etude for a Push-Me/Pull-You Machine"
then what would be a good filename for its released story file? diff --git a/docs/if-module/2-ri.html b/docs/if-module/2-ri.html index b51b5fff4..06e088f9c 100644 --- a/docs/if-module/2-ri.html +++ b/docs/if-module/2-ri.html @@ -465,10 +465,7 @@ of writing the same thing. filename *F = Task::ifiction_record_file(); if (STREAM_OPEN_TO_FILE(xf, F, UTF8_ENC) == FALSE) Problems::fatal_on_file("Can't open metadata file", F); - BEGIN_COMPILATION_MODE; - COMPILATION_MODE_ENTER(COMPILE_TEXT_TO_XML_CMODE); iFiction::write_ifiction_record(xf, rel); - END_COMPILATION_MODE; STREAM_CLOSE(xf);
if ((story_title_VAR != NULL) && (VariableSubjects::has_initial_value_set(story_title_VAR))) { - BEGIN_COMPILATION_MODE; - COMPILATION_MODE_ENTER(TRUNCATE_TEXT_CMODE); - BlurbFile::write_var_to_text(TEMP, story_title_VAR); - END_COMPILATION_MODE; + BlurbFile::write_var_to_text(TEMP, story_title_VAR, TRUNCATE_BIBTEXT_MODE); } else WRITE_TO(TEMP, "story"); WRITE_TO(TEMP, ".%S", TargetVMs::get_blorbed_extension(Task::vm()));@@ -226,41 +223,36 @@ brackets [THUS]. if (VariableSubjects::has_initial_value_set(story_release_number_VAR)) { WRITE("placeholder [RELEASE] = \""); - BlurbFile::write_var_to_text(OUT, story_release_number_VAR); + BlurbFile::write_var_to_text(OUT, story_release_number_VAR, XML_BIBTEXT_MODE); WRITE("\"\n"); } else WRITE("placeholder [RELEASE] = \"1\"\n"); - BEGIN_COMPILATION_MODE; - COMPILATION_MODE_ENTER(COMPILE_TEXT_TO_XML_CMODE); - if (VariableSubjects::has_initial_value_set(story_creation_year_VAR)) { WRITE("placeholder [YEAR] = \""); - BlurbFile::write_var_to_text(OUT, story_creation_year_VAR); + BlurbFile::write_var_to_text(OUT, story_creation_year_VAR, XML_BIBTEXT_MODE); WRITE("\"\n"); } else WRITE("placeholder [YEAR] = \"%d\"\n", (the_present->tm_year)+1900); if (VariableSubjects::has_initial_value_set(story_title_VAR)) { NonlocalVariables::initial_value_as_plain_text(story_title_VAR); WRITE("placeholder [TITLE] = \""); - BlurbFile::write_var_to_text(OUT, story_title_VAR); + BlurbFile::write_var_to_text(OUT, story_title_VAR, XML_BIBTEXT_MODE); WRITE("\"\n"); } else WRITE("placeholder [TITLE] = \"Untitled\"\n"); if (VariableSubjects::has_initial_value_set(story_author_VAR)) { NonlocalVariables::initial_value_as_plain_text(story_author_VAR); WRITE("placeholder [AUTHOR] = \""); - BlurbFile::write_var_to_text(OUT, story_author_VAR); + BlurbFile::write_var_to_text(OUT, story_author_VAR, XML_BIBTEXT_MODE); WRITE("\"\n"); } else WRITE("placeholder [AUTHOR] = \"Anonymous\"\n"); if (VariableSubjects::has_initial_value_set(story_description_VAR)) { NonlocalVariables::initial_value_as_plain_text(story_description_VAR); WRITE("placeholder [BLURB] = \""); - BlurbFile::write_var_to_text(OUT, story_description_VAR); + BlurbFile::write_var_to_text(OUT, story_description_VAR, XML_BIBTEXT_MODE); WRITE("\"\n"); } else WRITE("placeholder [BLURB] = \"A work of interactive fiction.\"\n"); - - END_COMPILATION_MODE;
§1.2.6. Give instructions about source text, solution and library card1.2.6 = @@ -465,7 +457,7 @@ Inblorb to copy out later.
-int BlurbFile::write_var_to_text(OUTPUT_STREAM, nonlocal_variable *nlv) { +int BlurbFile::write_var_to_text(OUTPUT_STREAM, nonlocal_variable *nlv, int mode) { if ((nlv) && (VariableSubjects::has_initial_value_set(nlv))) { parse_node *val = NonlocalVariables::substitute_constants( @@ -477,14 +469,14 @@ Inblorb to copy out later. } else { if (Kinds::eq(K, K_number)) { value_holster VH = Holsters::new(INTER_DATA_VHMODE); - Specifications::Compiler::compile_constant_to_kind_vh(&VH, val, K); + CompileSpecifications::holster_constant(&VH, val, K); inter_ti v1 = 0, v2 = 0; Holsters::unholster_pair(&VH, &v1, &v2); WRITE("%d", (inter_ti) v2); } else { wording W = Node::get_text(val); int w1 = Wordings::first_wn(W); - BibliographicData::compile_bibliographic_text(OUT, Lexer::word_text(w1)); + BibliographicData::compile_bibliographic_text(OUT, Lexer::word_text(w1), mode); } } return TRUE; diff --git a/docs/if-module/2-tir.html b/docs/if-module/2-tir.html index 643c109b9..fb2be94d7 100644 --- a/docs/if-module/2-tir.html +++ b/docs/if-module/2-tir.html @@ -341,14 +341,14 @@ LISP. } else { if (Kinds::eq(K, K_number)) { value_holster VH = Holsters::new(INTER_DATA_VHMODE); - Specifications::Compiler::compile_constant_to_kind_vh(&VH, val, K); + CompileSpecifications::holster_constant(&VH, val, K); inter_ti v1 = 0, v2 = 0; Holsters::unholster_pair(&VH, &v1, &v2); WRITE("%d", (inter_ti) v2); } else { wording W = Node::get_text(val); int w1 = Wordings::first_wn(W); - BibliographicData::compile_bibliographic_text(OUT, Lexer::word_text(w1)); + BibliographicData::compile_bibliographic_text(OUT, Lexer::word_text(w1), XML_BIBTEXT_MODE); } } return TRUE; diff --git a/docs/if-module/4-apc.html b/docs/if-module/4-apc.html index 0ca7c4d04..3617ae715 100644 --- a/docs/if-module/4-apc.html +++ b/docs/if-module/4-apc.html @@ -235,7 +235,7 @@ almost, because there could also be options set on it. } }-
§7. And this uses the Dash (in values) typechecker to validate that a specification +
§7. And this uses the Dash (in values) typechecker to validate that a specification makes sense in a given clause:
diff --git a/docs/imperative-module/3-cad.html b/docs/imperative-module/3-cad.html index 6360b5199..3f7771036 100644 --- a/docs/imperative-module/3-cad.html +++ b/docs/imperative-module/3-cad.html @@ -186,7 +186,7 @@ return the number of cinders made. if (pt->constant) { if (Calculus::Deferrals::Cinders::spec_needs_to_be_cindered(pt->constant)) { pt->cinder = cinder_number++; - Specifications::Compiler::emit_as_val(K_value, pt->constant); + CompileSpecifications::to_code_val(K_value, pt->constant); current_pdef->cinder_kinds[pt->cinder] = Specifications::to_kind(pt->constant); *started = TRUE; diff --git a/docs/imperative-module/3-cfs.html b/docs/imperative-module/3-cfs.html index b377f6e28..2a318a84f 100644 --- a/docs/imperative-module/3-cfs.html +++ b/docs/imperative-module/3-cfs.html @@ -72,7 +72,11 @@ function togglePopup(material_id) {To compile specifications into Inter values, conditions or void expressions.
-§1. In a more traditional compiler, the code-generator would be something of a +
§1. Specifications unite values, conditions and descriptions: see Specifications (in values). +They are stored as parse_node pointers. Here, we compile them to a +
+ +§2. In a more traditional compiler, the code-generator would be something of a landmark — one of the three or four most important stations. Here it's something of an anticlimax, partly because traditional "code" — values and statements — are only a small part of the I6 we have to generate, @@ -84,7 +88,7 @@ specifications — phrases to do something, or to decide things; constants; variables; conditions — finally convert into I6 code.
-§2. For the most part this is "modeless" — that is, the I6 code generated +
§3. For the most part this is "modeless" — that is, the I6 code generated by a specification does not depend on any context. But not entirely so, and we have a small set of "C-modes", each of which slightly alters the result to fit some particular need. @@ -110,21 +114,14 @@ enter or exit macros to switch a particular mode on or off. define DEREFERENCE_POINTERS_CMODE 0x00000001 make an independent copy of the result if on the heap define IMPLY_NEWLINES_IN_SAY_CMODE 0x00000010 at the end, that is define PERMIT_LOCALS_IN_TEXT_CMODE 0x00000020 unless casting to text -define COMPILE_TEXT_TO_QUOT_CMODE 0x00000080 for the idiosyncratic I6 box statement -define COMPILE_TEXT_TO_XML_CMODE 0x00000100 use XML escapes and UTF-8 encoding -define TRUNCATE_TEXT_CMODE 0x00000200 into a plausible filename length -define COMPILE_TEXT_TO_I6_CMODE 0x00001000 for bibliographic text to I6 constants define CONSTANT_CMODE 0x00002000 compiling values in a constant context -define SPECIFICATIONS_CMODE 0x00004000 compiling specifications at all -define BLANK_OUT_CMODE 0x00008000 blank out table references -define TREAT_AS_LVALUE_CMODE 0x00010000 similarly affects table references -define JUST_ROUTINE_CMODE 0x00020000 similarly affects table references -define TABLE_EXISTENCE_CMODE 0x00040000 test table references for existence +define TREAT_AS_LVALUE_CMODE 0x00010000 compile storage as lvalue not rvalue +define JUST_ROUTINE_CMODE 0x00020000 compile storage to Inter function handling it
int compilation_mode = DEREFERENCE_POINTERS_CMODE + IMPLY_NEWLINES_IN_SAY_CMODE; default-
§3. These modes are all explained where they are used. The one used right here +
§4. These modes are all explained where they are used. The one used right here is DEREFERENCE_POINTERS_CMODE. This applies only when compiling a specification which generates a pointer value — an I6 value which is a pointer to a larger block of data on the heap, such as a list or text. @@ -145,34 +142,85 @@ therefore exists as a way of temporarily turning off dereferencing — by default, it is always on.
-§4. The outer shell here has two purposes. One is to copy the specification -onto the local stack frame and then compile that copy — useful since -compilation may alter its contents. The other purpose, and this is not to -be dismissed lightly, is to ensure correct indentation in the log when -we exit unexpectedly, for instance due to a problem. +
§5. And the same in a constant context:
- --void Specifications::Compiler::compile_inner(value_holster *VH, parse_node *spec) { - LOGIF(EXPRESSIONS, "Compiling: $P\n", spec); - spec = NonlocalVariables::substitute_constants(spec); +void CompileSpecifications::to_array_entry(parse_node *spec) { + value_holster VH = Holsters::new(INTER_DATA_VHMODE); + CompileSpecifications::to_holster(&VH, spec, TRUE); + inter_ti v1 = 0, v2 = 0; + Holsters::unholster_pair(&VH, &v1, &v2); + Emit::array_generic_entry(v1, v2); +} - BEGIN_COMPILATION_MODE; - COMPILATION_MODE_ENTER(SPECIFICATIONS_CMODE); - LOG_INDENT; - parse_node breakable_copy = *spec; - Specifications::Compiler::spec_compile_primitive(VH, &breakable_copy); - LOG_OUTDENT; - END_COMPILATION_MODE; +void CompileSpecifications::to_array_entry_promoting(parse_node *value, kind *K_wanted) { + CompileSpecifications::to_array_entry( + CompileSpecifications::cast(value, K_wanted)); +} + +void CompileSpecifications::to_code_val(kind *K, parse_node *spec) { + value_holster VH = Holsters::new(INTER_VAL_VHMODE); + CompileSpecifications::to_holster(&VH, spec, FALSE); }-
§6. So this is where the compilation is done, or rather, delegated: +
§6. A variation on this is to compile a specification which represents +a value in a context where a particular kind of value is expected:
-void Specifications::Compiler::spec_compile_primitive(value_holster *VH, parse_node *spec) { +void CompileSpecifications::to_code_val_promoting(parse_node *value, kind *K_wanted) { + RTKinds::notify_of_use(K_wanted); + kind *K_found = Specifications::to_kind(value); + RTKinds::notify_of_use(K_found); + + if ((K_understanding) && (Kinds::eq(K_wanted, K_understanding)) && (Kinds::eq(K_found, K_text))) { + Node::set_kind_of_value(value, K_understanding); + K_found = K_understanding; + } + + int down = FALSE; + RTKinds::emit_cast_call(K_found, K_wanted, &down); + BEGIN_COMPILATION_MODE; + COMPILATION_MODE_ENTER(PERMIT_LOCALS_IN_TEXT_CMODE); + CompileSpecifications::to_code_val(K_value, value); + END_COMPILATION_MODE; + if (down) Produce::up(Emit::tree()); +} + + + + +void CompileSpecifications::holster_constant(value_holster *VH, parse_node *value, kind *K_wanted) { + CompileSpecifications::to_holster(VH, + CompileSpecifications::cast(value, K_wanted), TRUE); +} + +parse_node *CompileSpecifications::cast(parse_node *value, kind *K_wanted) { + RTKinds::notify_of_use(K_wanted); + value = LiteralReals::promote_number_if_necessary(value, K_wanted); + return value; +} + +void CompileSpecifications::to_pair(inter_ti *v1, inter_ti *v2, parse_node *spec) { + BEGIN_COMPILATION_MODE; + COMPILATION_MODE_EXIT(DEREFERENCE_POINTERS_CMODE); + value_holster VH = Holsters::new(INTER_DATA_VHMODE); + CompileSpecifications::to_holster(&VH, spec, FALSE); + Holsters::unholster_pair(&VH, v1, v2); + END_COMPILATION_MODE; +} + +void CompileSpecifications::to_holster(value_holster *VH, parse_node *spec, int c) { + LOGIF(EXPRESSIONS, "Compiling: $P\n", spec); + BEGIN_COMPILATION_MODE; + if (c) { + COMPILATION_MODE_EXIT(DEREFERENCE_POINTERS_CMODE); + COMPILATION_MODE_ENTER(CONSTANT_CMODE); + } + spec = NonlocalVariables::substitute_constants(spec); + + LOG_INDENT; kind *K_found = Specifications::to_kind(spec); RTKinds::notify_of_use(K_found); @@ -190,8 +238,9 @@ we exit unexpectedly, for instance due to a problem. Lvalues::compile(VH, spec); } else if (Rvalues::is_rvalue(spec)) { Rvalues::compile(VH, spec); - if ((VH->vhmode_provided == INTER_DATA_VHMODE) && (VH->vhmode_wanted == INTER_VAL_VHMODE)) { - Holsters::to_val_mode(Emit::tree(), VH); + if ((VH->vhmode_provided == INTER_DATA_VHMODE) && + (VH->vhmode_wanted == INTER_VAL_VHMODE)) { + Holsters::unholster_to_code_val(Emit::tree(), VH); } } else if (Specifications::is_condition(spec)) { Conditions::compile(VH, spec); @@ -199,92 +248,8 @@ we exit unexpectedly, for instance due to a problem. if (dereffed) { Produce::up(Emit::tree()); } -} --
§7. A variation on this is to compile a specification which represents -a value in a context where a particular kind of value is expected: -
- --void Specifications::Compiler::emit_to_kind(parse_node *value, kind *K_wanted) { - RTKinds::notify_of_use(K_wanted); - kind *K_found = Specifications::to_kind(value); - RTKinds::notify_of_use(K_found); - - if ((K_understanding) && (Kinds::eq(K_wanted, K_understanding)) && (Kinds::eq(K_found, K_text))) { - Node::set_kind_of_value(value, K_understanding); - K_found = K_understanding; - } - - int down = FALSE; - RTKinds::emit_cast_call(K_found, K_wanted, &down); - BEGIN_COMPILATION_MODE; - COMPILATION_MODE_ENTER(PERMIT_LOCALS_IN_TEXT_CMODE); - Specifications::Compiler::emit_as_val(K_value, value); + LOG_OUTDENT; END_COMPILATION_MODE; - if (down) Produce::up(Emit::tree()); -} --
§8. And the same in a constant context: -
- --void Specifications::Compiler::compile_constant_to_kind_vh(value_holster *VH, parse_node *value, kind *K_wanted) { - RTKinds::notify_of_use(K_wanted); - BEGIN_COMPILATION_MODE; - COMPILATION_MODE_EXIT(DEREFERENCE_POINTERS_CMODE); - COMPILATION_MODE_ENTER(CONSTANT_CMODE); - Specifications::Compiler::compile_inner(VH, Specifications::Compiler::cast_constant(value, K_wanted)); - END_COMPILATION_MODE; -} - -void Specifications::Compiler::emit_constant_to_kind(parse_node *value, kind *K_wanted) { - RTKinds::notify_of_use(K_wanted); - BEGIN_COMPILATION_MODE; - COMPILATION_MODE_EXIT(DEREFERENCE_POINTERS_CMODE); - COMPILATION_MODE_ENTER(CONSTANT_CMODE); - parse_node *casted = Specifications::Compiler::cast_constant(value, K_wanted); - END_COMPILATION_MODE; - Specifications::Compiler::emit(casted); -} - -void Specifications::Compiler::emit_constant_to_kind_as_val(parse_node *value, kind *K_wanted) { - RTKinds::notify_of_use(K_wanted); - BEGIN_COMPILATION_MODE; - COMPILATION_MODE_EXIT(DEREFERENCE_POINTERS_CMODE); - COMPILATION_MODE_ENTER(CONSTANT_CMODE); - parse_node *casted = Specifications::Compiler::cast_constant(value, K_wanted); - END_COMPILATION_MODE; - Specifications::Compiler::emit_as_val(K_value, casted); -} - -parse_node *Specifications::Compiler::cast_constant(parse_node *value, kind *to) { - kind *from = Specifications::to_kind(value); - if ((Kinds::eq(from, K_number)) && (Kinds::eq(to, K_real_number))) { - wording W = Node::get_text(value); - if (<s-literal-real-number>(W)) value = <<rp>>; - else internal_error("can't parse integer as real"); - } - return value; -} - -void Specifications::Compiler::emit(parse_node *spec) { - value_holster VH = Holsters::new(INTER_DATA_VHMODE); - - BEGIN_COMPILATION_MODE; - COMPILATION_MODE_EXIT(DEREFERENCE_POINTERS_CMODE); - COMPILATION_MODE_ENTER(CONSTANT_CMODE); - Specifications::Compiler::compile_inner(&VH, spec); - END_COMPILATION_MODE; - - inter_ti v1 = 0, v2 = 0; - Holsters::unholster_pair(&VH, &v1, &v2); - Emit::array_generic_entry(v1, v2); -} - -void Specifications::Compiler::emit_as_val(kind *K, parse_node *spec) { - value_holster VH = Holsters::new(INTER_VAL_VHMODE); - Specifications::Compiler::compile_inner(&VH, spec); }