1
0
Fork 0
mirror of https://github.com/ganelson/inform.git synced 2024-06-26 04:00:43 +03:00

Progress towards earlier extension-checking

This commit is contained in:
Graham Nelson 2020-03-08 11:33:57 +00:00
parent 3fef66aaf0
commit 4c1757a7ed
15 changed files with 291 additions and 252 deletions

View file

@ -253,6 +253,20 @@ void Copies::write_problem(OUTPUT_STREAM, copy_error *CE) {
WRITE("unrecognised stipulation about Inform language elements"); break;
case UnknownVirtualMachine_SYNERROR:
WRITE("unrecognised stipulation about virtual machine"); break;
case UseElementWithdrawn_SYNERROR:
WRITE("use language element is no longer supported"); break;
case IncludeExtQuoted_SYNERROR:
WRITE("extension name should not be double-quoted"); break;
case BogusExtension_SYNERROR:
WRITE("can't find this extension"); break;
case ExtVersionTooLow_SYNERROR:
WRITE("extension version too low"); break;
case ExtVersionMalformed_SYNERROR:
WRITE("extension version is malformed"); break;
case ExtInadequateVM_SYNERROR:
WRITE("extension is not compatible with the target virtual machine"); break;
case ExtMisidentifiedEnds_SYNERROR:
WRITE("extension has an 'ends here' but it does not match the 'begins here'"); break;
default:
WRITE("syntax error"); break;
}

View file

@ -10,7 +10,6 @@ typedef struct inform_extension {
struct wording body_text; /* Body of source text supplied in extension, if any */
int body_text_unbroken; /* Does this contain text waiting to be sentence-broken? */
struct wording documentation_text; /* Documentation supplied in extension, if any */
struct wording VM_restriction_text; /* Restricting use to certain VMs */
int standard; /* the (or perhaps just a) Standard Rules extension */
int authorial_modesty; /* Do not credit in the compiled game */
struct text_stream *rubric_as_lexed; /* brief description found in opening lines */
@ -19,9 +18,7 @@ typedef struct inform_extension {
struct inbuild_requirement *must_satisfy;
int loaded_from_built_in_area; /* Located within Inform application */
struct parse_node_tree *syntax_tree;
#ifdef CORE_MODULE
struct parse_node *inclusion_sentence; /* Where the source called for this */
#endif
MEMORY_MANAGEMENT
} inform_extension;
@ -32,7 +29,6 @@ void Extensions::scan(inbuild_genre *G, inbuild_copy *C) {
E->body_text = EMPTY_WORDING;
E->body_text_unbroken = FALSE;
E->documentation_text = EMPTY_WORDING;
E->VM_restriction_text = EMPTY_WORDING;
E->standard = FALSE;
E->authorial_modesty = FALSE;
E->read_into_file = NULL;
@ -41,9 +37,7 @@ void Extensions::scan(inbuild_genre *G, inbuild_copy *C) {
E->must_satisfy = NULL;
E->loaded_from_built_in_area = FALSE;
E->syntax_tree = ParseTree::new_tree();
#ifdef CORE_MODULE
E->inclusion_sentence = NULL;
#endif
TEMPORARY_TEXT(claimed_author_name);
TEMPORARY_TEXT(claimed_title);
@ -256,7 +250,6 @@ void Extensions::set_authorial_modesty(inform_extension *E) {
}
void Extensions::set_general_authorial_modesty(void) { general_authorial_modesty = TRUE; }
#ifdef CORE_MODULE
void Extensions::set_inclusion_sentence(inform_extension *E, parse_node *N) {
E->inclusion_sentence = N;
}
@ -264,14 +257,6 @@ parse_node *Extensions::get_inclusion_sentence(inform_extension *E) {
if (E == NULL) return NULL;
return E->inclusion_sentence;
}
#endif
void Extensions::set_VM_text(inform_extension *E, wording W) {
E->VM_restriction_text = W;
}
wording Extensions::get_VM_text(inform_extension *E) {
return E->VM_restriction_text;
}
int Extensions::is_standard(inform_extension *E) {
if (E == NULL) return FALSE;
@ -312,7 +297,8 @@ void Extensions::read_source_text_for(inform_extension *E) {
wording EXW = E->read_into_file->text_read;
if (Wordings::nonempty(EXW)) @<Break the extension's text into body and documentation@>;
#ifdef CORE_MODULE
E->syntax_tree = Task::syntax_tree();
inform_project *project = Inbuild::project();
if (project) E->syntax_tree = project->syntax_tree;
#endif
Sentences::break(E->syntax_tree, E->body_text, TRUE, E->as_copy, -1);
E->body_text_unbroken = FALSE;

View file

@ -389,6 +389,8 @@ LOG("Running rstf\n");
ParseTree::pop_attachment_point(project->syntax_tree, l);
ParseTree::push_attachment_point(project->syntax_tree, implicit_heading);
// Inclusions::traverse(project->syntax_tree);
}
@ It might seem sensible to parse the opening sentence of the source text,

View file

@ -1,4 +1,4 @@
[Extensions::Inclusion::] Including Extensions.
[Inclusions::] Inclusions.
To fulfill requests to include extensions, adding their material
to the parse tree as needed, and removing INCLUDE nodes.
@ -22,17 +22,20 @@ At the end of this routine, provided no Problems have been issued, there are
guaranteed to be no INCLUDE nodes remaining in the parse tree.
=
void Extensions::Inclusion::traverse(void) {
inbuild_copy *inclusions_errors_to = NULL;
void Inclusions::traverse(inbuild_copy *C, parse_node_tree *T) {
inclusions_errors_to = C;
int includes_cleared;
do {
includes_cleared = TRUE;
if (problem_count > 0) return;
if (problem_count > 0) break;
parse_node *elder = NULL;
ParseTree::traverse_ppni(Task::syntax_tree(), Extensions::Inclusion::visit, &elder, &includes_cleared);
ParseTree::traverse_ppni(T, Inclusions::visit, &elder, &includes_cleared);
} while (includes_cleared == FALSE);
inclusions_errors_to = NULL;
}
void Extensions::Inclusion::visit(parse_node *pn, parse_node **elder, int *includes_cleared) {
void Inclusions::visit(parse_node_tree *T, parse_node *pn, parse_node **elder, int *includes_cleared) {
if (ParseTree::get_type(pn) == INCLUDE_NT) {
@<Replace INCLUDE node with sentence nodes for any extensions required@>;
*includes_cleared = FALSE;
@ -45,21 +48,20 @@ void Extensions::Inclusion::visit(parse_node *pn, parse_node **elder, int *inclu
@<Replace INCLUDE node with sentence nodes for any extensions required@> =
parse_node *title = pn->down, *author = pn->down->next;
int l = ParseTree::begin_inclusion(Task::syntax_tree(), pn);
Extensions::Inclusion::fulfill_request_to_include_extension(title, author);
ParseTree::end_inclusion(Task::syntax_tree(), l);
int l = ParseTree::begin_inclusion(T, pn);
Inclusions::fulfill_request_to_include_extension(title, author);
ParseTree::end_inclusion(T, l);
@ Here we parse requests to include one or more extensions. People mostly
don't avail themselves of the opportunity, but it is legal to include
several at once, with a line like:
@
>> Include Carrots by Peter Rabbit and Green Lettuce by Flopsy Bunny.
@e IncludeExtQuoted_SYNERROR
@e BogusExtension_SYNERROR
@e ExtVersionTooLow_SYNERROR
@e ExtVersionMalformed_SYNERROR
@e ExtInadequateVM_SYNERROR
@e ExtMisidentifiedEnds_SYNERROR
A consequence of this convention is that "and" is not permitted in the
name of an extension. We might change this some day.
Here's how an individual title is described. The bracketed text is later
parsed by <platform-qualifier>.
@ Here we parse requests to include extensions.
=
<extension-title-and-version> ::=
@ -69,8 +71,8 @@ parsed by <platform-qualifier>.
<extension-unversioned> ==> -1
<extension-unversioned> ::=
<extension-unversioned-inner> ( ... ) | ==> 0; <<rest1>> = Wordings::first_wn(WR[1]); <<rest2>> = Wordings::last_wn(WR[1])
<extension-unversioned-inner> ==> 0; <<rest1>> = -1; <<rest2>> = -1
<extension-unversioned-inner> ( ... ) | ==> 0
<extension-unversioned-inner> ==> 0
<extension-unversioned-inner> ::=
<quoted-text> *** | ==> @<Issue PM_IncludeExtQuoted problem@>
@ -80,11 +82,11 @@ parsed by <platform-qualifier>.
@<Issue PM_IncludeExtQuoted problem@> =
<<t1>> = -1; <<t2>> = -1;
Problems::Issue::sentence_problem(Task::syntax_tree(), _p_(PM_IncludeExtQuoted),
"the name of an included extension should be given without double "
"quotes in an Include sentence",
"so for instance 'Include Oh My God by Janice Bing.' rather than "
"'Include \"Oh My God\" by Janice Bing.')");
copy_error *CE = Copies::new_error(SYNTAX_CE, NULL);
CE->error_subcategory = IncludeExtQuoted_SYNERROR;
CE->details_node = current_sentence;
Copies::attach(inclusions_errors_to, CE);
WRITE_TO(STDERR, "Listen %X!\n", inclusions_errors_to->edition->work);
@ This internal parses version text such as "12/110410".
@ -95,19 +97,11 @@ parsed by <platform-qualifier>.
}
@ =
void Extensions::Inclusion::fulfill_request_to_include_extension(parse_node *p, parse_node *auth_p) {
if (ParseTree::get_type(p) == AND_NT) {
Extensions::Inclusion::fulfill_request_to_include_extension(p->down, auth_p);
Extensions::Inclusion::fulfill_request_to_include_extension(p->down->next, auth_p);
return;
}
<<rest1>> = -1; <<rest2>> = -1;
void Inclusions::fulfill_request_to_include_extension(parse_node *p, parse_node *auth_p) {
<<t1>> = -1; <<t2>> = -1;
<extension-title-and-version>(ParseTree::get_text(p));
wording W = Wordings::new(<<t1>>, <<t2>>);
wording AW = ParseTree::get_text(auth_p);
wording RW = Wordings::new(<<rest1>>, <<rest2>>);
int version_word = <<r>>;
if (Wordings::nonempty(W)) @<Fulfill request to include a single extension@>;
@ -123,7 +117,7 @@ parse tree.
@<Fulfill request to include a single extension@> =
if (version_word >= 0)
Extensions::Inclusion::parse_version(version_word); /* this checks the formatting of the version number */
Inclusions::parse_version(version_word); /* this checks the formatting of the version number */
TEMPORARY_TEXT(exft);
TEMPORARY_TEXT(exfa);
@ -132,7 +126,7 @@ parse tree.
inbuild_work *work = Works::new(extension_genre, exft, exfa);
Works::add_to_database(work, LOADED_WDBC);
semantic_version_number V = VersionNumbers::null();
if (version_word >= 0) V = Extensions::Inclusion::parse_version(version_word);
if (version_word >= 0) V = Inclusions::parse_version(version_word);
semver_range *R = NULL;
if (VersionNumbers::is_null(V)) R = VersionNumbers::any_range();
else R = VersionNumbers::compatibility_range(V);
@ -140,19 +134,13 @@ parse tree.
DISCARD_TEXT(exft);
DISCARD_TEXT(exfa);
parse_node *at = current_sentence;
inform_extension *E = Extensions::Inclusion::load(req);
if (E) {
Extensions::set_inclusion_sentence(E, at);
Extensions::set_VM_text(E, RW);
}
Inclusions::load(current_sentence, req);
@h Extension loading.
Extensions are loaded here.
=
inform_extension *Extensions::Inclusion::load(inbuild_requirement *req) {
NaturalLanguages::scan(); /* to avoid wording from those interleaving with extension wording */
inform_extension *Inclusions::load(parse_node *at, inbuild_requirement *req) {
@<Do not load the same extension work twice@>;
inform_extension *E = NULL;
@ -185,31 +173,47 @@ can't know at load time what we will ultimately require.)
inbuild_search_result *search_result = Nests::first_found(req, Inbuild::nest_list());
if (search_result) {
E = ExtensionManager::from_copy(search_result->copy);
Extensions::set_inclusion_sentence(E, at);
if (Nests::get_tag(search_result->nest) == INTERNAL_NEST_TAG)
E->loaded_from_built_in_area = TRUE;
compatibility_specification *C = E->as_copy->edition->compatibility;
if (Compatibility::with(C, Inbuild::current_vm()) == FALSE)
@<Issue a problem message saying that the VM does not meet requirements@>;
if (LinkedLists::len(search_result->copy->errors_reading_source_text) > 0) {
E = NULL;
} else {
Copies::read_source_text_for(search_result->copy);
}
#ifdef CORE_MODULE
SourceProblems::issue_problems_arising(search_result->copy);
#endif
#ifndef CORE_MODULE
Copies::list_problems_arising(STDERR, search_result->copy);
#endif
} else @<Issue a cannot-find problem@>;
@ Here the problem is not that the extension is broken in some way: it's
just not what we can currently use. Therefore the correction should be a
matter of removing the inclusion, not of altering the extension, so we
report this problem at the inclusion line.
@<Issue a problem message saying that the VM does not meet requirements@> =
copy_error *CE = Copies::new_error(SYNTAX_CE, NULL);
CE->error_subcategory = ExtInadequateVM_SYNERROR;
CE->details_node = Extensions::get_inclusion_sentence(E);
CE->details = C->parsed_from;
Copies::attach(inclusions_errors_to, CE);
@<Issue a cannot-find problem@> =
inbuild_requirement *req2 = Requirements::any_version_of(req->work);
linked_list *L = NEW_LINKED_LIST(inbuild_search_result);
Nests::search_for(req2, Inbuild::nest_list(), L);
if (LinkedLists::len(L) == 0) {
LOG("Author: %W\n", req->work->author_name);
LOG("Title: %W\n", req->work->title);
Problems::quote_source(1, current_sentence);
Problems::Issue::handmade_problem(Task::syntax_tree(), _p_(PM_BogusExtension));
Problems::issue_problem_segment(
"I can't find the extension requested by: %1. %P"
"You can get hold of extensions which people have made public at "
"the Inform website, www.inform7.com, or by using the Public "
"Library in the Extensions panel.");
Problems::issue_problem_end();
copy_error *CE = Copies::new_error(SYNTAX_CE, NULL);
CE->error_subcategory = BogusExtension_SYNERROR;
CE->details_node = current_sentence;
Copies::attach(inclusions_errors_to, CE);
} else {
TEMPORARY_TEXT(versions);
inbuild_search_result *search_result;
@ -219,22 +223,17 @@ can't know at load time what we will ultimately require.)
if (VersionNumbers::is_null(V)) WRITE_TO(versions, "an unnumbered version");
else WRITE_TO(versions, "version %v", &V);
}
Problems::quote_source(1, current_sentence);
Problems::quote_stream(2, versions);
Problems::Issue::handmade_problem(Task::syntax_tree(), _p_(PM_ExtVersionTooLow));
Problems::issue_problem_segment(
"I can't find the right version of the extension requested by %1 - "
"I can only find %2. %P"
"You can get hold of extensions which people have made public at "
"the Inform website, www.inform7.com, or by using the Public "
"Library in the Extensions panel.");
Problems::issue_problem_end();
copy_error *CE = Copies::new_error(SYNTAX_CE, NULL);
CE->error_subcategory = ExtVersionTooLow_SYNERROR;
CE->details_node = at;
CE->details = Str::duplicate(versions);
Copies::attach(inclusions_errors_to, CE);
DISCARD_TEXT(versions);
}
@ =
int last_PM_ExtVersionMalformed_at = -1;
semantic_version_number Extensions::Inclusion::parse_version(int vwn) {
semantic_version_number Inclusions::parse_version(int vwn) {
semantic_version_number V = VersionNumbers::null();
wording W = Wordings::one_word(vwn);
if (<version-number>(W)) {
@ -246,7 +245,7 @@ semantic_version_number Extensions::Inclusion::parse_version(int vwn) {
return V;
}
@ Because we tend to call |Extensions::Inclusion::parse_version| repeatedly on
@ Because we tend to call |Inclusions::parse_version| repeatedly on
the same word, we want to recover tidily from this problem, and not report it
over and over. We do this by altering the text to |1|, the lowest well-formed
version number text.
@ -255,11 +254,10 @@ version number text.
if (last_PM_ExtVersionMalformed_at != vwn) {
last_PM_ExtVersionMalformed_at = vwn;
LOG("Offending word number %d <%N>\n", vwn, vwn);
Problems::Issue::sentence_problem(Task::syntax_tree(), _p_(PM_ExtVersionMalformed),
"a version number must have the form N/DDDDDD",
"as in the example '2/040426' for release 2 made on 26 April 2004. "
"(The DDDDDD part is optional, so '3' is a legal version number too. "
"N must be between 1 and 999: in particular, there is no version 0.)");
copy_error *CE = Copies::new_error(SYNTAX_CE, NULL);
CE->error_subcategory = ExtVersionMalformed_SYNERROR;
CE->details_node = current_sentence;
Copies::attach(inclusions_errors_to, CE);
}
@h Checking the begins here and ends here sentences.
@ -287,60 +285,23 @@ problem messages if it is malformed.
=
<begins-here-sentence-subject> ::=
<extension-title-and-version> by ... | ==> R[1]; <<auth1>> = Wordings::first_wn(WR[1]); <<auth2>> = Wordings::last_wn(WR[1]);
<extension-title-and-version> by ... |
... ==> @<Issue problem@>
@<Issue problem@> =
<<auth1>> = -1; <<auth2>> = -1;
Problems::Issue::handmade_problem(Task::syntax_tree(), _p_(BelievedImpossible)); // since inbuild's scan catches this first
Problems::issue_problem_segment(
"has a misworded 'begins here' sentence ('%2'), which contains "
"no 'by'. Recall that every extension should begin with a "
"sentence such as 'Quantum Mechanics by Max Planck begins "
"here.', and end with a matching 'Quantum Mechanics ends "
"here.', perhaps with documentation to follow.");
Problems::issue_problem_end();
copy_error *CE = Copies::new_error(SYNTAX_CE, NULL);
CE->error_subcategory = ExtNoBeginsHere_SYNERROR;
CE->details_node = current_sentence;
Copies::attach(inclusions_errors_to, CE);
@ =
void Extensions::Inclusion::check_begins_here(parse_node *PN, inform_extension *E) {
current_sentence = PN; /* in case problem messages need to be issued */
Problems::quote_extension(1, E);
Problems::quote_wording(2, ParseTree::get_text(PN));
void Inclusions::check_begins_here(parse_node *PN, inform_extension *E) {
inbuild_copy *S = inclusions_errors_to;
inclusions_errors_to = E->as_copy;
<begins-here-sentence-subject>(ParseTree::get_text(PN));
Extensions::set_VM_text(E, Wordings::new(<<rest1>>, <<rest2>>));
@<Check that the extension's stipulation about the virtual machine can be met@>;
inclusions_errors_to = S;
}
@ On the other hand, we do already know what virtual machine we are compiling
for, so we can immediately object if the loaded extension cannot be used
with our VM de jour.
@<Check that the extension's stipulation about the virtual machine can be met@> =
compatibility_specification *C = E->as_copy->edition->compatibility;
if (Compatibility::with(C, Task::vm()) == FALSE)
@<Issue a problem message saying that the VM does not meet requirements@>;
@ Here the problem is not that the extension is broken in some way: it's
just not what we can currently use. Therefore the correction should be a
matter of removing the inclusion, not of altering the extension, so we
report this problem at the inclusion line.
@<Issue a problem message saying that the VM does not meet requirements@> =
current_sentence = Extensions::get_inclusion_sentence(E);
Problems::quote_source(1, current_sentence);
Problems::quote_copy(2, E->as_copy);
Problems::quote_stream(3, C->parsed_from);
Problems::Issue::handmade_problem(Task::syntax_tree(), _p_(PM_ExtInadequateVM));
Problems::issue_problem_segment(
"You wrote %1: but my copy of %2 stipulates that it "
"is '%3'. That means it can only be used with certain of "
"the possible compiled story file formats, and at the "
"moment, we don't fit the requirements. (You can change "
"the format used for this project on the Settings panel.)");
Problems::issue_problem_end();
@ Similarly, we check the "ends here" sentence. Here there are no
side-effects: we merely verify that the name matches the one quoted in
the "begins here". We only check this if the problem count is still 0,
@ -348,48 +309,21 @@ since we don't want to keep on nagging somebody who has already been told
that the extension isn't the one he thinks it is.
=
void Extensions::Inclusion::check_ends_here(parse_node *PN, inform_extension *E) {
wording W = Articles::remove_the(ParseTree::get_text(PN));
<the-prefix-for-extensions> ::=
the ...
void Inclusions::check_ends_here(parse_node *PN, inform_extension *E) {
inbuild_copy *S = inclusions_errors_to;
inclusions_errors_to = E->as_copy;
wording W = ParseTree::get_text(PN);
if (<the-prefix-for-extensions>(W)) W = GET_RW(<the-prefix-for-extensions>, 1);
wording T = Feeds::feed_stream(E->as_copy->edition->work->title);
if ((problem_count == 0) && (Wordings::match(T, W) == FALSE)) {
current_sentence = PN;
Problems::quote_extension(1, E);
Problems::quote_wording(2, ParseTree::get_text(PN));
Problems::Issue::handmade_problem(Task::syntax_tree(), _p_(PM_ExtMisidentifiedEnds));
Problems::issue_problem_segment(
"The extension %1, which your source text makes use of, seems to be "
"malformed: its 'begins here' sentence correctly identifies it, but "
"then the 'ends here' sentence calls it '%2' instead. (They need "
"to be a matching pair except that the end does not name the "
"author: for instance, 'Hocus Pocus by Jan Ackerman begins here.' "
"would match with 'Hocus Pocus ends here.')");
Problems::issue_problem_end();
return;
copy_error *CE = Copies::new_error(SYNTAX_CE, NULL);
CE->error_subcategory = ExtMisidentifiedEnds_SYNERROR;
CE->details_node = PN;
CE->details_W = ParseTree::get_text(PN);
Copies::attach(inclusions_errors_to, CE);
}
}
@h Sentence handlers for begins here and ends here.
The main traverses of the assertions are handled by code which calls
"sentence handler" routines on each node in turn, depending on type.
Here are the handlers for BEGINHERE and ENDHERE. As can be seen, all
we really do is start again from a clean piece of paper.
Note that, because one extension can include another, these nodes may
well be interleaved: we might find the sequence A begins, B begins,
B ends, A ends. The careful checking done so far ensures that these
will always properly nest. We don't at present make use of this, but
we might in future.
=
sentence_handler BEGINHERE_SH_handler =
{ BEGINHERE_NT, -1, 0, Extensions::Inclusion::handle_extension_begins };
sentence_handler ENDHERE_SH_handler =
{ ENDHERE_NT, -1, 0, Extensions::Inclusion::handle_extension_ends };
void Extensions::Inclusion::handle_extension_begins(parse_node *PN) {
Assertions::Traverse::new_discussion(); near_start_of_extension = 1;
}
void Extensions::Inclusion::handle_extension_ends(parse_node *PN) {
near_start_of_extension = 0;
inclusions_errors_to = S;
}

View file

@ -232,3 +232,53 @@ sentences. Whereas other nonstructural sentences can wait, these can't.
<language-modifying-sentence> ::=
include (- ### in the preform grammar | ==> -2; ssnt = INFORM6CODE_NT;
use ... language element/elements ==> -1
@h Sentence division.
Sentence division can happen either early in Inform's run, when the vast bulk
of the source text is read, or at intermittent periods later when fresh text
is generated internally. New sentences need to be parsed as they arise, not
saved up to be parsed later, so we will use the following:
@d SENTENCE_ANNOTATION_FUNCTION SourceText::annotate_new_sentence
=
int text_loaded_from_source = FALSE;
void SourceText::declare_source_loaded(void) {
text_loaded_from_source = TRUE;
}
void SourceText::annotate_new_sentence(parse_node *new) {
if (text_loaded_from_source) {
ParseTree::annotate_int(new, sentence_unparsed_ANNOT, FALSE);
#ifdef CORE_MODULE
Sentences::VPs::seek(new);
#endif
}
}
@
@d NEW_BEGINEND_HANDLER SourceText::new_beginend
=
void SourceText::new_beginend(parse_node *new, inbuild_copy *C) {
inform_extension *E = ExtensionManager::from_copy(C);
if (ParseTree::get_type(new) == BEGINHERE_NT)
Inclusions::check_begins_here(new, E);
if (ParseTree::get_type(new) == ENDHERE_NT)
Inclusions::check_ends_here(new, E);
}
@
@d NEW_LANGUAGE_HANDLER SourceText::new_language
@e UseElementWithdrawn_SYNERROR
=
void SourceText::new_language(wording W) {
copy_error *CE = Copies::new_error(SYNTAX_CE, NULL);
CE->error_subcategory = UseElementWithdrawn_SYNERROR;
CE->details_node = current_sentence;
Copies::attach(sfsm_copy, CE);
}

View file

@ -49,5 +49,6 @@ Chapter 5: Services for the Inform Compiler
Chapter 6: Handling Inform Source Text
Source Text
Headings
Inclusions
Control Structures
Virtual Machine Grammar

View file

@ -22,3 +22,10 @@ PM_ExtMultipleBeginsHere
PM_ExtBeginsAfterEndsHere
PM_UnknownLanguageElement
PM_UnknownVirtualMachine
PM_UseElementWithdrawn
PM_IncludeExtQuoted
PM_BogusExtension
PM_ExtVersionTooLow
PM_ExtVersionMalformed
PM_ExtInadequateVM
PM_ExtMisidentifiedEnds

View file

@ -1,14 +1,14 @@
Inform 7.10.1 build 6Q21 has started.
I've now read your source text, which is 10 words long.
I've also read Basic Inform by Graham Nelson, which is 7645 words long.
I've also read English Language by Graham Nelson, which is 2328 words long.
I've also read Standard Rules by Graham Nelson, which is 32123 words long.
I've also read Extinadequatevm Extension by Araminta Intest, which is 14 words long.
I've also read Basic Inform by Graham Nelson, which is 7645 words long.
I've also read English Language by Graham Nelson, which is 2328 words long.
I've also read Standard Rules by Graham Nelson, which is 32123 words long.
I've also read Extinadequatevm Extension by Araminta Intest, which is 14 words long.
Problem__ PM_ExtInadequateVM
>--> You wrote 'Include Extinadequatevm Extension by Araminta Intest' (source
text, line 1): but my copy of Extinadequatevm Extension by Araminta Intest
stipulates that it is '(For Glulx Only)'. That means it can only be used
with certain of the possible compiled story file formats, and at the
moment, we don't fit the requirements. (You can change the format used for
this project on the Settings panel.)
Inform 7 has finished: 12 centiseconds used.
text, line 1): but my copy of that extension stipulates that it is '(For
Glulx Only)'. That means it can only be used with certain of the possible
compiled story file formats, and at the moment, we don't fit the
requirements. (You can change the format used for this project on the
Settings panel.)
Inform 7 has finished.

View file

@ -107,7 +107,10 @@ most of these worker functions are in the |core| module, some are not.
@<Perform textual analysis@> =
Task::advance_stage_to(LEXICAL_CSEQ, I"Textual analysis", 0);
BENCH(Task::activate_language_elements)
BENCH(Extensions::Inclusion::traverse)
Inclusions::traverse(Task::project()->as_copy, Task::syntax_tree());
SourceProblems::issue_problems_arising(Task::project()->as_copy);
// BENCH(Inclusions::traverse)
BENCH(Sentences::Headings::satisfy_dependencies)
Task::advance_stage_to(SEMANTIC_LANGUAGE_CSEQ, I"Initialise language semantics", -1);
@ -120,7 +123,7 @@ most of these worker functions are in the |core| module, some are not.
BENCH(Sentences::VPs::traverse)
BENCH(Sentences::Rearrangement::tidy_up_ofs_and_froms)
BENCH(Sentences::RuleSubtrees::register_recently_lexed_phrases)
BENCH(StructuralSentences::declare_source_loaded)
BENCH(SourceText::declare_source_loaded)
BENCH(Kinds::Knowledge::include_templates_for_kinds)
Task::advance_stage_to(SEMANTIC_II_CSEQ, I"Semantic analysis II", -1);

View file

@ -284,6 +284,84 @@ void SourceProblems::issue_problems_arising(inbuild_copy *C) {
"and should be something like '(for Z-machine version 5 "
"or 8 only)' or '(for Glulx only)'.");
break;
case UseElementWithdrawn_SYNERROR:
current_sentence = CE->details_node;
Problems::Issue::sentence_problem(
Task::syntax_tree(), _p_(PM_UseElementWithdrawn),
"the ability to activate or deactivate compiler elements "
"in source text has been withdrawn",
"in favour of a new system with Inform kits.");
break;
case IncludeExtQuoted_SYNERROR:
current_sentence = CE->details_node;
Problems::Issue::sentence_problem(
Task::syntax_tree(), _p_(PM_IncludeExtQuoted),
"the name of an included extension should be given without double "
"quotes in an Include sentence",
"so for instance 'Include Oh My God by Janice Bing.' rather than "
"'Include \"Oh My God\" by Janice Bing.')");
break;
case BogusExtension_SYNERROR:
current_sentence = CE->details_node;
Problems::quote_source(1, current_sentence);
Problems::Issue::handmade_problem(Task::syntax_tree(), _p_(PM_BogusExtension));
Problems::issue_problem_segment(
"I can't find the extension requested by: %1. %P"
"You can get hold of extensions which people have made public at "
"the Inform website, www.inform7.com, or by using the Public "
"Library in the Extensions panel.");
Problems::issue_problem_end();
break;
case ExtVersionTooLow_SYNERROR:
current_sentence = CE->details_node;
Problems::quote_source(1, current_sentence);
Problems::quote_stream(2, CE->details);
Problems::Issue::handmade_problem(Task::syntax_tree(), _p_(PM_ExtVersionTooLow));
Problems::issue_problem_segment(
"I can't find the right version of the extension requested by %1 - "
"I can only find %2. %P"
"You can get hold of extensions which people have made public at "
"the Inform website, www.inform7.com, or by using the Public "
"Library in the Extensions panel.");
Problems::issue_problem_end();
break;
case ExtVersionMalformed_SYNERROR:
current_sentence = CE->details_node;
Problems::Issue::sentence_problem(
Task::syntax_tree(), _p_(PM_ExtVersionMalformed),
"a version number must have the form N/DDDDDD",
"as in the example '2/040426' for release 2 made on 26 April 2004. "
"(The DDDDDD part is optional, so '3' is a legal version number too. "
"N must be between 1 and 999: in particular, there is no version 0.)");
break;
case ExtInadequateVM_SYNERROR:
current_sentence = CE->details_node;
Problems::quote_source(1, current_sentence);
Problems::quote_stream(2, CE->details);
Problems::Issue::handmade_problem(Task::syntax_tree(), _p_(PM_ExtInadequateVM));
Problems::issue_problem_segment(
"You wrote %1: but my copy of that extension stipulates that it "
"is '%2'. That means it can only be used with certain of "
"the possible compiled story file formats, and at the "
"moment, we don't fit the requirements. (You can change "
"the format used for this project on the Settings panel.)");
Problems::issue_problem_end();
break;
case ExtMisidentifiedEnds_SYNERROR:
current_sentence = CE->details_node;
Problems::quote_extension(1, ExtensionManager::from_copy(C));
Problems::quote_wording(2, CE->details_W);
Problems::Issue::handmade_problem(Task::syntax_tree(), _p_(PM_ExtMisidentifiedEnds));
Problems::issue_problem_segment(
"The extension %1, which your source text makes use of, seems to be "
"malformed: its 'begins here' sentence correctly identifies it, but "
"then the 'ends here' sentence calls it '%2' instead. (They need "
"to be a matching pair except that the end does not name the "
"author: for instance, 'Hocus Pocus by Jan Ackerman begins here.' "
"would match with 'Hocus Pocus ends here.')");
Problems::issue_problem_end();
break;
default:
internal_error("unknown syntax error");
}

View file

@ -3,61 +3,3 @@
To parse structurally important sentences.
@
@h Sentence division.
Sentence division can happen either early in Inform's run, when the vast bulk
of the source text is read, or at intermittent periods later when fresh text
is generated internally. New sentences need to be treated slightly differently
in these cases, so this seems as good a point as any to define the routine
which the |.i6t| interpreter calls when it wants to signal that the source
text has now officially been read.
@d SENTENCE_ANNOTATION_FUNCTION StructuralSentences::annotate_new_sentence
=
int text_loaded_from_source = FALSE;
void StructuralSentences::declare_source_loaded(void) {
text_loaded_from_source = TRUE;
}
void StructuralSentences::annotate_new_sentence(parse_node *new) {
if (text_loaded_from_source) {
ParseTree::annotate_int(new, sentence_unparsed_ANNOT, FALSE);
Sentences::VPs::seek(new);
}
}
@
@d NEW_BEGINEND_HANDLER StructuralSentences::new_beginend
=
void StructuralSentences::new_beginend(parse_node *new, inbuild_copy *C) {
inform_extension *E = ExtensionManager::from_copy(C);
if (ParseTree::get_type(new) == BEGINHERE_NT)
Extensions::Inclusion::check_begins_here(new, E);
if (ParseTree::get_type(new) == ENDHERE_NT)
Extensions::Inclusion::check_ends_here(new, E);
}
@
@d NEW_LANGUAGE_HANDLER StructuralSentences::new_language
=
void StructuralSentences::new_language(wording W) {
parse_node_tree *T = NULL;
inform_project *project = ProjectBundleManager::from_copy(sfsm_copy);
if (project == NULL) project = ProjectFileManager::from_copy(sfsm_copy);
if (project) T = project->syntax_tree;
inform_extension *ext = ExtensionManager::from_copy(sfsm_copy);
if (ext) T = ext->syntax_tree;
if (T == NULL) internal_error("unable to locate syntax tree");
Problems::Issue::sentence_problem(T, _p_(PM_UseElementWithdrawn),
"the ability to activate or deactivate compiler elements in source text has been withdrawn",
"in favour of a new system with Inform kits.");
}

View file

@ -533,5 +533,28 @@ int Extensions::Files::document_headword(OUTPUT_STREAM, int kc, inform_extension
return kc;
}
@ And that at last brings us to a milestone: the end of the Land of Extensions.
We can return to Inform's more usual concerns.
@h Sentence handlers for begins here and ends here.
The main traverses of the assertions are handled by code which calls
"sentence handler" routines on each node in turn, depending on type.
Here are the handlers for BEGINHERE and ENDHERE. As can be seen, all
we really do is start again from a clean piece of paper.
Note that, because one extension can include another, these nodes may
well be interleaved: we might find the sequence A begins, B begins,
B ends, A ends. The careful checking done so far ensures that these
will always properly nest. We don't at present make use of this, but
we might in future.
=
sentence_handler BEGINHERE_SH_handler =
{ BEGINHERE_NT, -1, 0, Extensions::Files::handle_extension_begins };
sentence_handler ENDHERE_SH_handler =
{ ENDHERE_NT, -1, 0, Extensions::Files::handle_extension_ends };
void Extensions::Files::handle_extension_begins(parse_node *PN) {
Assertions::Traverse::new_discussion(); near_start_of_extension = 1;
}
void Extensions::Files::handle_extension_ends(parse_node *PN) {
near_start_of_extension = 0;
}

View file

@ -68,7 +68,6 @@ Chapter 8: Extensions
which, we also handle extension installation, uninstallation and
documentation here."
Extension Files
Including Extensions
Chapter 9: The A-Parser
"We work through the assertion sentences in the parse tree one by one, and

View file

@ -296,7 +296,7 @@ void Problems::issue_problem_begin(parse_node_tree *T, char *message) {
} else if (strcmp(message, "**") == 0) {
shorten_problem_message = FALSE;
} else {
Problems::show_problem_location(T);
if (T) Problems::show_problem_location(T);
problem_count++;
WRITE_TO(PBUFF, ">--> ");
shorten_problem_message = Problems::explained_before(message);

View file

@ -993,16 +993,16 @@ void ParseTree::traverse_from_ppn(parse_node *pn, void (*visitor)(parse_node *,
}
current_sentence = SCS;
}
void ParseTree::traverse_ppni(parse_node_tree *T, void (*visitor)(parse_node *, parse_node **, int *), parse_node **X, int *N) {
ParseTree::traverse_from_ppni(T->root_node, visitor, X, N);
void ParseTree::traverse_ppni(parse_node_tree *T, void (*visitor)(parse_node_tree *, parse_node *, parse_node **, int *), parse_node **X, int *N) {
ParseTree::traverse_from_ppni(T, T->root_node, visitor, X, N);
}
void ParseTree::traverse_from_ppni(parse_node *pn, void (*visitor)(parse_node *, parse_node **, int *), parse_node **X, int *N) {
void ParseTree::traverse_from_ppni(parse_node_tree *T, parse_node *pn, void (*visitor)(parse_node_tree *, parse_node *, parse_node **, int *), parse_node **X, int *N) {
parse_node *SCS = current_sentence;
for (; pn; pn = pn->next) {
if (ParseTree::top_level(pn->node_type)) ParseTree::traverse_from_ppni(pn->down, visitor, X, N);
if (ParseTree::top_level(pn->node_type)) ParseTree::traverse_from_ppni(T, pn->down, visitor, X, N);
if (ParseTree::visitable(pn->node_type)) {
if (SENTENCE_NODE(pn->node_type)) current_sentence = pn;
(*visitor)(pn, X, N);
(*visitor)(T, pn, X, N);
}
}
current_sentence = SCS;