mirror of
https://github.com/ganelson/inform.git
synced 2024-06-17 07:40:47 +03:00
Further dialogue beat parsing
This commit is contained in:
parent
0d6eba5bfd
commit
5003ba316d
|
@ -1,6 +1,6 @@
|
|||
# Inform 7
|
||||
|
||||
[Version](notes/versioning.md): 10.2.0-beta+6V52 'Krypton' (6 September 2022)
|
||||
[Version](notes/versioning.md): 10.2.0-beta+6V53 'Krypton' (7 September 2022)
|
||||
|
||||
## About Inform
|
||||
|
||||
|
|
|
@ -1,3 +1,3 @@
|
|||
Prerelease: beta
|
||||
Build Date: 6 September 2022
|
||||
Build Number: 6V52
|
||||
Build Date: 7 September 2022
|
||||
Build Number: 6V53
|
||||
|
|
|
@ -523,11 +523,8 @@ on //WorldModelKit//, through the if-this-then-that mechanism.
|
|||
inform_language *L = project->language_of_play;
|
||||
if (L) Languages::add_kit_dependencies_to_project(L, project);
|
||||
else internal_error("no language of play");
|
||||
if ((no_word_from_JSON) && (forcible_basic_mode == FALSE)) {
|
||||
if ((no_word_from_JSON) && (forcible_basic_mode == FALSE))
|
||||
Projects::add_kit_dependency(project, I"CommandParserKit", NULL, NULL, NULL);
|
||||
if (project->syntax_tree->contains_dialogue)
|
||||
Projects::add_kit_dependency(project, I"DialogueKit", NULL, NULL, NULL);
|
||||
}
|
||||
|
||||
@ We perform this first with |parity| being |TRUE|, then |FALSE|.
|
||||
|
||||
|
@ -712,6 +709,8 @@ void Projects::construct_graph(inform_project *proj) {
|
|||
if (proj->chosen_build_target == NULL) {
|
||||
Projects::finalise_kit_dependencies(proj);
|
||||
Copies::get_source_text(proj->as_copy);
|
||||
if (proj->syntax_tree->contains_dialogue)
|
||||
Projects::add_kit_dependency(proj, I"DialogueKit", NULL, NULL, NULL);
|
||||
build_vertex *V = proj->as_copy->vertex;
|
||||
@<Construct the graph upstream of V@>;
|
||||
@<Construct the graph downstream of V@>;
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
"is": {
|
||||
"type": "kit",
|
||||
"title": "BasicInformExtrasKit",
|
||||
"version": "10.2.0-beta+6V52"
|
||||
"version": "10.2.0-beta+6V53"
|
||||
},
|
||||
"kit-details": {
|
||||
"has-priority": 1
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
"is": {
|
||||
"type": "kit",
|
||||
"title": "BasicInformKit",
|
||||
"version": "10.2.0-beta+6V52"
|
||||
"version": "10.2.0-beta+6V53"
|
||||
},
|
||||
"needs": [ {
|
||||
"unless": {
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
"is": {
|
||||
"type": "kit",
|
||||
"title": "CommandParserKit",
|
||||
"version": "10.2.0-beta+6V52"
|
||||
"version": "10.2.0-beta+6V53"
|
||||
},
|
||||
"needs": [ {
|
||||
"need": {
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
"is": {
|
||||
"type": "kit",
|
||||
"title": "EnglishLanguageKit",
|
||||
"version": "10.2.0-beta+6V52"
|
||||
"version": "10.2.0-beta+6V53"
|
||||
},
|
||||
"needs": [ {
|
||||
"need": {
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
"is": {
|
||||
"type": "kit",
|
||||
"title": "WorldModelKit",
|
||||
"version": "10.2.0-beta+6V52"
|
||||
"version": "10.2.0-beta+6V53"
|
||||
},
|
||||
"needs": [ {
|
||||
"need": {
|
||||
|
|
17
inform7/Tests/Groups/dialogue.testgroup
Normal file
17
inform7/Tests/Groups/dialogue.testgroup
Normal file
|
@ -0,0 +1,17 @@
|
|||
PM_NotABeat
|
||||
PM_UnrecognisedBeat
|
||||
PM_DoubleImmediateBeat
|
||||
PM_NoPreviousBeat
|
||||
PM_LineNamedTwice
|
||||
PM_BeatNamedTwice
|
||||
PM_LineWithoutBeat
|
||||
PM_OrphanLine
|
||||
PM_OvernestedLine
|
||||
PM_IndentedBeat
|
||||
PM_MisbracketedDialogueClause
|
||||
PM_EmptyDialogueClause
|
||||
PM_UnquotedDialogue
|
||||
PM_UnexpectedDialogue
|
||||
PM_DialogueOnSectionsOnly
|
||||
PM_NotAnAboutTopic
|
||||
PM_UnrecognisedAboutTopic
|
11
inform7/Tests/Test Problems/PM_DoubleImmediateBeat.txt
Normal file
11
inform7/Tests/Test Problems/PM_DoubleImmediateBeat.txt
Normal file
|
@ -0,0 +1,11 @@
|
|||
Elsinore is a room.
|
||||
|
||||
Section 1 - Meeting (dialogue)
|
||||
|
||||
(This is the okay beat.)
|
||||
|
||||
Marcellus: "OK."
|
||||
|
||||
(Next, immediately after the okay beat.)
|
||||
|
||||
Marcellus: "What, has this thing appear'd again to-night?"
|
13
inform7/Tests/Test Problems/PM_NoPreviousBeat.txt
Normal file
13
inform7/Tests/Test Problems/PM_NoPreviousBeat.txt
Normal file
|
@ -0,0 +1,13 @@
|
|||
Elsinore is a room.
|
||||
|
||||
Section 1 - Meeting (dialogue)
|
||||
|
||||
(Later.)
|
||||
|
||||
Marcellus: "What, has this thing appear'd again to-night?"
|
||||
|
||||
Section 2 - Meeting Again (dialogue)
|
||||
|
||||
(Next.)
|
||||
|
||||
Marcellus: "What, has this thing appear'd again to-night?"
|
19
inform7/Tests/Test Problems/PM_NotABeat.txt
Normal file
19
inform7/Tests/Test Problems/PM_NotABeat.txt
Normal file
|
@ -0,0 +1,19 @@
|
|||
Elsinore is a room.
|
||||
|
||||
Section 1 - Meeting (dialogue)
|
||||
|
||||
(This is the okay beat.)
|
||||
|
||||
Marcellus: "OK."
|
||||
|
||||
(After the okay beat.)
|
||||
|
||||
Marcellus: "What, has this thing appear'd again to-night?"
|
||||
|
||||
(After a dialogue beat.)
|
||||
|
||||
Marcellus: "What, has this thing appear'd again to-night?"
|
||||
|
||||
(After 456.)
|
||||
|
||||
Marcellus: "What, has this thing appear'd again to-night?"
|
7
inform7/Tests/Test Problems/PM_NotAnAboutTopic.txt
Normal file
7
inform7/Tests/Test Problems/PM_NotAnAboutTopic.txt
Normal file
|
@ -0,0 +1,7 @@
|
|||
Elsinore is a room.
|
||||
|
||||
Section 1 - Meeting (dialogue)
|
||||
|
||||
(About "fish".)
|
||||
|
||||
Marcellus: "OK."
|
|
@ -0,0 +1,7 @@
|
|||
Elsinore is a room.
|
||||
|
||||
Section 1 - Meeting (dialogue)
|
||||
|
||||
(About total nonsense.)
|
||||
|
||||
Marcellus: "OK."
|
19
inform7/Tests/Test Problems/PM_UnrecognisedBeat.txt
Normal file
19
inform7/Tests/Test Problems/PM_UnrecognisedBeat.txt
Normal file
|
@ -0,0 +1,19 @@
|
|||
Elsinore is a room.
|
||||
|
||||
Section 1 - Meeting (dialogue)
|
||||
|
||||
(This is the okay beat.)
|
||||
|
||||
Marcellus: "OK."
|
||||
|
||||
(After the okay beat.)
|
||||
|
||||
Marcellus: "What, has this thing appear'd again to-night?"
|
||||
|
||||
(After a dialogue beat.)
|
||||
|
||||
Marcellus: "What, has this thing appear'd again to-night?"
|
||||
|
||||
(After sdfgsfgsfg sdfgsfgs.)
|
||||
|
||||
Marcellus: "What, has this thing appear'd again to-night?"
|
|
@ -0,0 +1,11 @@
|
|||
Inform 7 v10.2.0 has started.
|
||||
I've now read your source text, which is 30 words long.
|
||||
I've also read Basic Inform by Graham Nelson, which is 7691 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 32187 words long.
|
||||
Problem__ PM_DoubleImmediateBeat
|
||||
In Section 1 - Meeting:
|
||||
>--> You wrote '(Next, immediately after the okay beat .)' (source text, line 9):
|
||||
but this dialogue beat asks to be immediately after two or more other
|
||||
beats, either with 'next' or 'immediately after'. It can only give one.
|
||||
Inform 7 has finished.
|
|
@ -0,0 +1,15 @@
|
|||
Inform 7 v10.2.0 has started.
|
||||
I've now read your source text, which is 33 words long.
|
||||
I've also read Basic Inform by Graham Nelson, which is 7691 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 32187 words long.
|
||||
Problem__ PM_NoPreviousBeat
|
||||
In Section 1 - Meeting:
|
||||
>--> You wrote '(Later .)' (source text, line 5): but this dialogue beat asks
|
||||
to be performed after the previous one, but in this dialogue section, there
|
||||
is no previous one.
|
||||
Problem__ PM_NoPreviousBeat
|
||||
In Section 2 - Meeting Again:
|
||||
>--> You wrote '(Next .)' (source text, line 11): again, this dialogue beat
|
||||
asks to be performed after the previous one.
|
||||
Inform 7 has finished.
|
10
inform7/Tests/Test Problems/_Results_Ideal/PM_NotABeat.txt
Normal file
10
inform7/Tests/Test Problems/_Results_Ideal/PM_NotABeat.txt
Normal file
|
@ -0,0 +1,10 @@
|
|||
Inform 7 v10.2.0 has started.
|
||||
I've now read your source text, which is 50 words long.
|
||||
I've also read Basic Inform by Graham Nelson, which is 7691 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 32187 words long.
|
||||
Problem__ PM_NotABeat
|
||||
In Section 1 - Meeting:
|
||||
>--> The dialogue beat '(After 456 .)' (source text, line 17) refers to
|
||||
another beat with '456', but that seems to describe a number.
|
||||
Inform 7 has finished.
|
|
@ -0,0 +1,11 @@
|
|||
Inform 7 v10.2.0 has started.
|
||||
I've now read your source text, which is 13 words long.
|
||||
I've also read Basic Inform by Graham Nelson, which is 7691 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 32187 words long.
|
||||
Problem__ PM_NotAnAboutTopic
|
||||
In Section 1 - Meeting:
|
||||
>--> The dialogue beat '(About "fish" .)' (source text, line 5) is apparently
|
||||
about '"fish"', but that seems to be a text. (Dialogue can only be about
|
||||
objects: people, things, rooms, that sort of stuff.)
|
||||
Inform 7 has finished.
|
|
@ -0,0 +1,12 @@
|
|||
Inform 7 v10.2.0 has started.
|
||||
I've now read your source text, which is 14 words long.
|
||||
I've also read Basic Inform by Graham Nelson, which is 7691 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 32187 words long.
|
||||
Problem__ PM_UnrecognisedAboutTopic
|
||||
In Section 1 - Meeting:
|
||||
>--> The dialogue beat '(About total nonsense .)' (source text, line 5) is
|
||||
apparently about 'total nonsense', but that isn't something I recognise as
|
||||
an object. (Dialogue can only be about objects: people, things, rooms, that
|
||||
sort of stuff.)
|
||||
Inform 7 has finished.
|
|
@ -0,0 +1,11 @@
|
|||
Inform 7 v10.2.0 has started.
|
||||
I've now read your source text, which is 51 words long.
|
||||
I've also read Basic Inform by Graham Nelson, which is 7691 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 32187 words long.
|
||||
Problem__ PM_UnrecognisedBeat
|
||||
In Section 1 - Meeting:
|
||||
>--> The dialogue beat '(After sdfgsfgsfg sdfgsfgs .)' (source text, line 17)
|
||||
refers to another beat with 'sdfgsfgsfg sdfgsfgs', but that isn't something
|
||||
I recognise as a description.
|
||||
Inform 7 has finished.
|
|
@ -2,7 +2,7 @@
|
|||
|
||||
To manage dialogue beats and lines.
|
||||
|
||||
@
|
||||
@ See the test group |:dialogue|.
|
||||
|
||||
@d MAX_DIALOGUE_LINE_NESTING 25
|
||||
|
||||
|
@ -30,10 +30,12 @@ typedef struct dialogue_beat {
|
|||
struct parse_node *cue_at;
|
||||
struct heading *under_heading;
|
||||
struct instance *as_instance;
|
||||
struct scene *as_scene;
|
||||
|
||||
struct dialogue_beat *immediately_after;
|
||||
struct linked_list *some_time_after; /* of |dialogue_beat| */
|
||||
struct linked_list *some_time_before; /* of |dialogue_beat| */
|
||||
struct parse_node *immediately_after;
|
||||
struct linked_list *some_time_after; /* of |parse_node| */
|
||||
struct linked_list *some_time_before; /* of |parse_node| */
|
||||
struct linked_list *about_list; /* of |parse_node| */
|
||||
|
||||
struct dialogue_line *opening_line;
|
||||
struct dialogue_beat_compilation_data compilation_data;
|
||||
|
@ -72,10 +74,12 @@ dialogue_beat *Dialogue::create_cue(parse_node *PN) {
|
|||
db->cue_at = PN;
|
||||
db->under_heading = dialogue_section_being_scanned;
|
||||
db->immediately_after = NULL;
|
||||
db->some_time_after = NEW_LINKED_LIST(dialogue_beat);
|
||||
db->some_time_before = NEW_LINKED_LIST(dialogue_beat);
|
||||
db->some_time_after = NEW_LINKED_LIST(parse_node);
|
||||
db->some_time_before = NEW_LINKED_LIST(parse_node);
|
||||
db->about_list = NEW_LINKED_LIST(parse_node);
|
||||
db->opening_line = NULL;
|
||||
db->compilation_data = RTDialogue::new_beat(PN, db);
|
||||
db->as_scene = NULL;
|
||||
previous_dialogue_beat = current_dialogue_beat;
|
||||
current_dialogue_beat = db;
|
||||
for (int i=0; i<MAX_DIALOGUE_LINE_NESTING; i++)
|
||||
|
@ -188,9 +192,162 @@ void Dialogue::write_dbc(OUTPUT_STREAM, int c) {
|
|||
... beat |
|
||||
... scene
|
||||
|
||||
@
|
||||
|
||||
=
|
||||
void Dialogue::decide_cue_sequencing(void) {
|
||||
dialogue_beat *db, *previous = NULL;
|
||||
LOOP_OVER(db, dialogue_beat) {
|
||||
current_sentence = db->cue_at;
|
||||
int iac = 0;
|
||||
for (parse_node *clause = db->cue_at->down; clause; clause = clause->next) {
|
||||
wording CW = Node::get_text(clause);
|
||||
switch (Annotations::read_int(clause, dialogue_beat_clause_ANNOT)) {
|
||||
case NEXT_DBC:
|
||||
if ((previous) && (previous->under_heading == db->under_heading)) {
|
||||
iac++;
|
||||
db->immediately_after = Rvalues::from_dialogue_beat(previous);
|
||||
} else @<Issue PM_NoPreviousBeat problem@>;
|
||||
break;
|
||||
case IMMEDIATELY_AFTER_DBC: {
|
||||
<dialogue-beat-clause>(CW);
|
||||
wording B = GET_RW(<dialogue-beat-clause>, 1);
|
||||
parse_node *desc = Dialogue::parse_beat_name(B);
|
||||
if (desc) {
|
||||
iac++;
|
||||
db->immediately_after = desc;
|
||||
}
|
||||
break;
|
||||
}
|
||||
case LATER_DBC:
|
||||
if ((previous) && (previous->under_heading == db->under_heading)) {
|
||||
parse_node *desc = Rvalues::from_dialogue_beat(previous);
|
||||
ADD_TO_LINKED_LIST(desc, parse_node, db->some_time_after);
|
||||
} else @<Issue PM_NoPreviousBeat problem@>;
|
||||
break;
|
||||
case AFTER_DBC: {
|
||||
<dialogue-beat-clause>(CW);
|
||||
wording B = GET_RW(<dialogue-beat-clause>, 1);
|
||||
parse_node *desc = Dialogue::parse_beat_name(B);
|
||||
if (desc) ADD_TO_LINKED_LIST(desc, parse_node, db->some_time_after);
|
||||
break;
|
||||
}
|
||||
case BEFORE_DBC: {
|
||||
<dialogue-beat-clause>(CW);
|
||||
wording B = GET_RW(<dialogue-beat-clause>, 1);
|
||||
parse_node *desc = Dialogue::parse_beat_name(B);
|
||||
if (desc) ADD_TO_LINKED_LIST(desc, parse_node, db->some_time_before);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
if (Wordings::nonempty(db->scene_name)) {
|
||||
pcalc_prop *prop = Propositions::Abstract::to_create_something(K_scene, db->scene_name);
|
||||
Assert::true(prop, CERTAIN_CE);
|
||||
db->as_scene = Scenes::from_named_constant(Instances::latest());
|
||||
}
|
||||
previous = db;
|
||||
if (iac > 1)
|
||||
StandardProblems::sentence_problem(Task::syntax_tree(), _p_(PM_DoubleImmediateBeat),
|
||||
"this dialogue beat asks to be immediately after two or more other beats",
|
||||
"either with 'next' or 'immediately after'. It can only give one.");
|
||||
}
|
||||
}
|
||||
|
||||
@<Issue PM_NoPreviousBeat problem@> =
|
||||
StandardProblems::sentence_problem(Task::syntax_tree(), _p_(PM_NoPreviousBeat),
|
||||
"this dialogue beat asks to be performed after the previous one",
|
||||
"but in this dialogue section, there is no previous one.");
|
||||
|
||||
@ =
|
||||
parse_node *Dialogue::parse_beat_name(wording CW) {
|
||||
if (<s-type-expression-uncached>(CW)) {
|
||||
parse_node *desc = <<rp>>;
|
||||
kind *K = Specifications::to_kind(desc);
|
||||
if (Kinds::ne(K, K_dialogue_beat)) {
|
||||
Problems::quote_source(1, current_sentence);
|
||||
Problems::quote_wording(2, CW);
|
||||
Problems::quote_kind(3, K);
|
||||
StandardProblems::handmade_problem(Task::syntax_tree(), _p_(PM_NotABeat));
|
||||
Problems::issue_problem_segment(
|
||||
"The dialogue beat %1 refers to another beat with '%2', but that "
|
||||
"seems to describe %3.");
|
||||
Problems::issue_problem_end();
|
||||
return NULL;
|
||||
}
|
||||
return desc;
|
||||
} else {
|
||||
Problems::quote_source(1, current_sentence);
|
||||
Problems::quote_wording(2, CW);
|
||||
StandardProblems::handmade_problem(Task::syntax_tree(), _p_(PM_UnrecognisedBeat));
|
||||
Problems::issue_problem_segment(
|
||||
"The dialogue beat %1 refers to another beat with '%2', but that "
|
||||
"isn't something I recognise as a description.");
|
||||
Problems::issue_problem_end();
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
@
|
||||
|
||||
=
|
||||
void Dialogue::decide_cue_topics(void) {
|
||||
dialogue_beat *db;
|
||||
LOOP_OVER(db, dialogue_beat) {
|
||||
current_sentence = db->cue_at;
|
||||
for (parse_node *clause = db->cue_at->down; clause; clause = clause->next) {
|
||||
wording CW = Node::get_text(clause);
|
||||
switch (Annotations::read_int(clause, dialogue_beat_clause_ANNOT)) {
|
||||
case ABOUT_DBC: {
|
||||
<dialogue-beat-clause>(CW);
|
||||
wording A = GET_RW(<dialogue-beat-clause>, 1);
|
||||
<np-articled-list>(A);
|
||||
parse_node *AL = <<rp>>;
|
||||
Dialogue::parse_topic(db->about_list, AL);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void Dialogue::parse_topic(linked_list *about_list, parse_node *AL) {
|
||||
if (Node::is(AL, AND_NT)) {
|
||||
Dialogue::parse_topic(about_list, AL->down);
|
||||
Dialogue::parse_topic(about_list, AL->down->next);
|
||||
} else if (Node::is(AL, UNPARSED_NOUN_NT)) {
|
||||
wording A = Node::get_text(AL);
|
||||
LOG("Text: %W\n", A);
|
||||
if (<s-constant-value>(A)) {
|
||||
parse_node *desc = <<rp>>;
|
||||
kind *K = Specifications::to_kind(desc);
|
||||
if (Kinds::Behaviour::is_subkind_of_object(K)) {
|
||||
ADD_TO_LINKED_LIST(desc, parse_node, about_list);
|
||||
} else {
|
||||
Problems::quote_source(1, current_sentence);
|
||||
Problems::quote_wording(2, A);
|
||||
Problems::quote_kind(3, K);
|
||||
StandardProblems::handmade_problem(Task::syntax_tree(), _p_(PM_NotAnAboutTopic));
|
||||
Problems::issue_problem_segment(
|
||||
"The dialogue beat %1 is apparently about '%2', but that "
|
||||
"seems to be %3. (Dialogue can only be about objects: "
|
||||
"people, things, rooms, that sort of stuff.)");
|
||||
Problems::issue_problem_end();
|
||||
}
|
||||
} else {
|
||||
Problems::quote_source(1, current_sentence);
|
||||
Problems::quote_wording(2, A);
|
||||
StandardProblems::handmade_problem(Task::syntax_tree(), _p_(PM_UnrecognisedAboutTopic));
|
||||
Problems::issue_problem_segment(
|
||||
"The dialogue beat %1 is apparently about '%2', but that "
|
||||
"isn't something I recognise as an object. (Dialogue can "
|
||||
"only be about objects: people, things, rooms, that sort of stuff.)");
|
||||
Problems::issue_problem_end();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@<Add a scene name to the beat@> =
|
||||
current_dialogue_beat->beat_name = WR[1];
|
||||
|
||||
@
|
||||
|
||||
|
|
|
@ -140,9 +140,11 @@ so on. Those absolute basics are made here.
|
|||
2, debugging, sequence_timer);
|
||||
BENCH(MajorNodes::pass_1)
|
||||
BENCH(Tables::traverse_to_stock)
|
||||
BENCH(Dialogue::decide_cue_sequencing)
|
||||
Task::advance_stage_to(ASSERTIONS_PASS_2_CSEQ, I"Second pass through major nodes",
|
||||
-1, debugging, sequence_timer);
|
||||
BENCH(MajorNodes::pass_2)
|
||||
BENCH(Dialogue::decide_cue_topics)
|
||||
|
||||
@<Make the model world@> =
|
||||
Task::advance_stage_to(MODEL_CSEQ, I"Making the model world",
|
||||
|
|
Loading…
Reference in a new issue