Special sentences for listing named rules in particular rulebooks.
§1. This section covers five forms of request to change the way rules are filed in rulebooks; the test group :placement exercises these.
First, this handles the special meaning "X is listed in...":
<listed-in-sentence-object> listed <np-unparsed> | not listed <np-unparsed>
int RulePlacement::listed_in_SMF(int task, parse_node *V, wording *NPs) { wording SW = (NPs)?(NPs[0]):EMPTY_WORDING; wording OW = (NPs)?(NPs[1]):EMPTY_WORDING; switch (task) { "The time passes rule is listed in the turn sequence rulebook." case ACCEPT_SMFT: if ((<nounphrase-rule-list>(SW)) && (<listed-in-sentence-object>(OW))) { Annotations::write_int(V, rule_placement_sense_ANNOT, <<r>>); parse_node *O = <<rp>>; <np-unparsed>(SW); V->next = <<rp>>; V->next->next = O; return TRUE; } break; case TRAVERSE_FOR_RULE_FILING_SMFT: RulePlacement::place_in_rulebook(V->next, V->next->next, Annotations::read_int(V, rule_placement_sense_ANNOT)); break; } return FALSE; }
§3. And this is where we parse lists of rule names. The verbs "to be listed", "to substitute for" and "to do nothing" are a little too common to accept them in all circumstances, so we require their subjects to be plausible as rule names. All rule names end in "rule", whereas other names mostly don't, so the following won't pick up many false positives.
<nounphrase-rule-list> ... | <nounphrase-rule> <np-rule-tail> | <nounphrase-rule> <np-rule-tail> , {_and} <nounphrase-rule-list> | {_,/and} <nounphrase-rule-list> <nounphrase-rule> ... rule
§4. This handles the special meaning "X substitutes for Y".
<substitutes-for-sentence-object> <nounphrase-rule> | <nounphrase-rule> if/when <np-unparsed> | <nounphrase-rule> unless <np-unparsed>
int RulePlacement::substitutes_for_SMF(int task, parse_node *V, wording *NPs) { wording SW = (NPs)?(NPs[0]):EMPTY_WORDING; wording OW = (NPs)?(NPs[1]):EMPTY_WORDING; switch (task) { "The time passes slowly rule substitutes for the time passes rule." case ACCEPT_SMFT: if ((<nounphrase-rule-list>(SW)) && (<substitutes-for-sentence-object>(OW))) { Annotations::write_int(V, rule_placement_sense_ANNOT, <<r>>); parse_node *O = <<rp>>; <np-unparsed>(SW); V->next = <<rp>>; V->next->next = O; return TRUE; } break; case TRAVERSE_FOR_RULE_FILING_SMFT: RulePlacement::request_substitute(V->next, V->next->next, V->next->next->next, Annotations::read_int(V, rule_placement_sense_ANNOT)); break; } return FALSE; }
The print fancy final score rule substitutes for the print final score rule.
It also exists in a form with a condition attached:
The print fancy final score rule substitutes for the print final score rule when ...
This optional tail is eventually required to match <spec-condition>, but that parsing is done later on. For now, we only parse for rules in both the subject and object NPs.
<substitutes-for-sentence-subject> <rule-name> | ... <substitutes-for-sentence-object-inner> <rule-name> | ...
§6.1. Issue PM_NoSuchRuleExists problem6.1 =
Problems::quote_source(1, current_sentence); Problems::quote_wording(2, W); StandardProblems::handmade_problem(Task::syntax_tree(), _p_(PM_NoSuchRuleExists)); Problems::issue_problem_segment( "In %1, you gave '%2' where a rule was required."); Problems::issue_problem_end(); ==> { FALSE, - };
void RulePlacement::request_substitute(parse_node *p1, parse_node *p2, parse_node *p3, int sense) { <substitutes-for-sentence-subject>(Node::get_text(p1)); if (<<r>> == FALSE) return; rule *new_rule = <<rp>>; <substitutes-for-sentence-object-inner>(Node::get_text(p2)); if (<<r>> == FALSE) return; rule *old_rule = <<rp>>; wording CW = EMPTY_WORDING; if (p3) CW = Node::get_text(p3); Rules::impose_constraint(new_rule, old_rule, CW, (sense)?FALSE:TRUE); }
The print final score rule does nothing.
The print final score rule does nothing unless ....
is parsed similarly. The subject NP is an articled list, each entry of which must be a rule, and the optional condition is put aside for later, but must eventually match <spec-condition>.
<does-nothing-sentence-object> nothing <does-nothing-sentence-subject> <rule-name> | ...
int RulePlacement::does_nothing_SMF(int task, parse_node *V, wording *NPs) { wording SW = (NPs)?(NPs[0]):EMPTY_WORDING; wording OW = (NPs)?(NPs[1]):EMPTY_WORDING; switch (task) { "The time passes rule does nothing." case ACCEPT_SMFT: if ((<nounphrase-rule-list>(SW)) && (<does-nothing-sentence-object>(OW))) { parse_node *O = <<rp>>; <np-unparsed>(SW); V->next = <<rp>>; V->next->next = O; return TRUE; } break; case TRAVERSE_FOR_RULE_FILING_SMFT: RulePlacement::constrain_effect(V->next, NULL, NOT_APPLICABLE); break; } return FALSE; }
int RulePlacement::does_nothing_if_SMF(int task, parse_node *V, wording *NPs) { wording SW = (NPs)?(NPs[0]):EMPTY_WORDING; wording OW = (NPs)?(NPs[2]):EMPTY_WORDING; wording CW = (NPs)?(NPs[1]):EMPTY_WORDING; switch (task) { "The time passes rule does nothing if ..." case ACCEPT_SMFT: if ((<nounphrase-rule-list>(SW)) && (<does-nothing-sentence-object>(OW))) { <np-unparsed>(SW); V->next = <<rp>>; <np-unparsed>(CW); parse_node *O = <<rp>>; V->next->next = O; return TRUE; } break; case TRAVERSE_FOR_RULE_FILING_SMFT: RulePlacement::constrain_effect(V->next, V->next->next, FALSE); break; } return FALSE; }
int RulePlacement::does_nothing_unless_SMF(int task, parse_node *V, wording *NPs) { wording SW = (NPs)?(NPs[0]):EMPTY_WORDING; wording OW = (NPs)?(NPs[2]):EMPTY_WORDING; wording CW = (NPs)?(NPs[1]):EMPTY_WORDING; switch (task) { "The time passes rule does nothing unless ..." case ACCEPT_SMFT: if ((<nounphrase-rule-list>(SW)) && (<does-nothing-sentence-object>(OW))) { <np-unparsed>(SW); V->next = <<rp>>; <np-unparsed>(CW); parse_node *O = <<rp>>; V->next->next = O; return TRUE; } break; case TRAVERSE_FOR_RULE_FILING_SMFT: RulePlacement::constrain_effect(V->next, V->next->next, TRUE); break; } return FALSE; }
void RulePlacement::constrain_effect(parse_node *p1, parse_node *p2, int sense) { if (Node::get_type(p1) == AND_NT) { RulePlacement::constrain_effect(p1->down, p2, sense); RulePlacement::constrain_effect(p1->down->next, p2, sense); return; } <does-nothing-sentence-subject>(Node::get_text(p1)); if (<<r>> == FALSE) return; rule *existing_rule = <<rp>>; if (p2) Rules::impose_constraint(NULL, existing_rule, Node::get_text(p2), sense); else Rules::impose_constraint(NULL, existing_rule, EMPTY_WORDING, FALSE); }
§13. Explicit listing sentences allow the source text to control which rulebook(s) a given rule appears in, and (within limits) where. A simple example:
The can't act in the dark rule is not listed in the visibility rules.
The subject noun phrase is an articled list, each entry of which must match:
<listed-in-sentence-subject> <rule-name> | ...
§14. The object NP is more flexible:
<listed-in-sentence-object-inner> in any rulebook | in <destination-rulebook> | first in <destination-rulebook> | last in <destination-rulebook> | very first in <destination-rulebook> | very last in <destination-rulebook> | instead of <rule-name> in <rulebook-name> | instead of <rule-name> in ... | instead of ... in ... | before <rule-name> in <rulebook-name> | before <rule-name> in ... | before ... in ... | after <rule-name> in <rulebook-name> | after <rule-name> in ... | after ... in ... | instead of ... | before ... | after ... | ... <destination-rulebook> <rulebook-name> | ...
define ANY_RULE_PLACEMENT 1000001 define BAD_RULE_PLACEMENT 1000000 @<Issue PM_CannotPlaceVeryFirst problem@> =
Issue PM_CannotPlaceVeryFirst problem14.1 =
Problems::quote_source(1, current_sentence); StandardProblems::handmade_problem(Task::syntax_tree(), _p_(PM_CannotPlaceVeryFirst)); Problems::issue_problem_segment( "In %1, you asked to change or impose a 'very first' or 'very last' " "rule for a rulebook. But those rules are restricted and can be written " "only alongside the rulebook itself, and cannot afterwards be changed " "with sentences like this one."); Problems::issue_problem_end(); ==> { BAD_RULE_PLACEMENT, - };
- This code is used in §14 (twice).
§14.2. Issue PM_UnspecifiedRulebookPlacement problem14.2 =
Problems::quote_source(1, current_sentence); StandardProblems::handmade_problem(Task::syntax_tree(), _p_(PM_UnspecifiedRulebookPlacement)); Problems::issue_problem_segment( "In %1, you didn't specify in which rulebook the rule was to " "be listed, only which existing rule it should go before or " "after."); Problems::issue_problem_end(); ==> { BAD_RULE_PLACEMENT, - };
- This code is used in §14 (three times).
§14.3. Issue PM_ImproperRulePlacement problem14.3 =
Actually issue PM_ImproperRulePlacement problem14.3.1; ==> { BAD_RULE_PLACEMENT, - };
- This code is used in §14.
§14.3.1. Actually issue PM_ImproperRulePlacement problem14.3.1 =
Problems::quote_source(1, current_sentence); StandardProblems::handmade_problem(Task::syntax_tree(), _p_(PM_ImproperRulePlacement)); Problems::issue_problem_segment( "In %1, you used the special verb 'to be listed' - which specifies " "how rules are listed in rulebooks - in a way I didn't recognise. " "The usual form is: 'The summer breeze rule is listed in the " "meadow noises rulebook'."); Problems::issue_problem_end();
§14.4. Issue PM_NoSuchRulebookPlacement problem14.4 =
Problems::quote_source(1, current_sentence); Problems::quote_wording(2, W); StandardProblems::handmade_problem(Task::syntax_tree(), _p_(PM_NoSuchRulebookPlacement)); Problems::issue_problem_segment( "In %1, you gave '%2' where a rulebook was required."); Problems::issue_problem_end();
- This code is used in §14 (four times).
void RulePlacement::place_in_rulebook(parse_node *p1, parse_node *p2, int sense) { if (Node::get_type(p1) == AND_NT) { RulePlacement::place_in_rulebook(p1->down, p2, sense); RulePlacement::place_in_rulebook(p1->down->next, p2, sense); return; } Make single placement15.1; }
§15.1. Make single placement15.1 =
LOGIF(RULE_ATTACHMENTS, "Placement sentence (%d):\np1=$T\np2=$T\n", sense, p1, p2); int any, side, new_rule_placement; rulebook *given_rulebook; rule *given_rule, *relative_rule; Parse the wording to find how to place15.1.1; if ((sense == FALSE) && ((new_rule_placement != MIDDLE_PLACEMENT) || (side != IN_SIDE))) Issue PM_BadRulePlacementNegation problem15.1.2; if (any) Detach from all rulebooks15.1.3; if (sense == FALSE) Detach only from this rulebook15.1.4; booking *new_rule_booking = RuleBookings::new(given_rule); Rules::set_kind_from(given_rule, given_rulebook); if (relative_rule) { LOGIF(RULE_ATTACHMENTS, "Relative to which = %W\n", relative_rule->name); RTRulebooks::affected_by_placement(given_rulebook, current_sentence); if (Rulebooks::rule_in_rulebook(relative_rule, given_rulebook) == FALSE) Issue PM_PlaceWithMissingRule problem15.1.5; } Rulebooks::attach_rule(given_rulebook, new_rule_booking, new_rule_placement, side, relative_rule);
- This code is used in §15.
§15.1.1. Parse the wording to find how to place15.1.1 =
int pc = problem_count; <<rule:rel>> = NULL; <listed-in-sentence-object-inner>(Node::get_text(p2)); if ((problem_count > pc) || (<<r>> == BAD_RULE_PLACEMENT)) return; given_rulebook = <<rp>>; relative_rule = <<rule:rel>>; int pair = <<r>>; any = FALSE; if (pair == BAD_RULE_PLACEMENT) return; if (pair == ANY_RULE_PLACEMENT) { any = TRUE; if (sense == TRUE) { Actually issue PM_ImproperRulePlacement problem14.3.1; return; } new_rule_placement = MIDDLE_PLACEMENT; side = IN_SIDE; } else { new_rule_placement = pair%1000; side = pair/1000; } <listed-in-sentence-subject>(Node::get_text(p1)); if (<<r>> == FALSE) return; given_rule = <<rp>>;
- This code is used in §15.1.
§15.1.2. Issue PM_BadRulePlacementNegation problem15.1.2 =
Problems::quote_source(1, current_sentence); StandardProblems::handmade_problem(Task::syntax_tree(), _p_(PM_BadRulePlacementNegation)); Problems::issue_problem_segment( "In %1, you used the special verb 'to be listed' - which specifies " "how rules are listed in rulebooks - in a way too complicated to " "be accompanied by 'not', so that the result was too vague. " "The usual form is: 'The summer breeze rule is not listed in the " "meadow noises rulebook'."); Problems::issue_problem_end(); return;
- This code is used in §15.1.
§15.1.3. Detach from all rulebooks15.1.3 =
rulebook *rb; LOOP_OVER(rb, rulebook) Rulebooks::detach_rule(rb, given_rule); return;
- This code is used in §15.1.
§15.1.4. Detach only from this rulebook15.1.4 =
RTRulebooks::affected_by_placement(given_rulebook, current_sentence); Rulebooks::detach_rule(given_rulebook, given_rule); return;
- This code is used in §15.1.
§15.1.5. Issue PM_PlaceWithMissingRule problem15.1.5 =
Problems::quote_source(1, current_sentence); Problems::quote_wording(2, given_rulebook->primary_name); Problems::quote_wording(3, relative_rule->name); StandardProblems::handmade_problem(Task::syntax_tree(), _p_(PM_PlaceWithMissingRule)); Problems::issue_problem_segment( "In %1, you talk about the position of the rule '%3' " "in the rulebook '%2', but in fact that rule isn't in this " "rulebook, so the placing instruction makes no sense."); Problems::issue_problem_end(); return;
- This code is used in §15.1.