Adds IS NOT to the Part II parser and a resolution pass (negation, then
identity lock) that turns parsed rules into the rules in force; harness
gains activeRules() and hasProperty(). A leading NOT now breaks the
sentence instead of being ignored (carried from M6 review). Nouns say
which objects they name ("selects"), so the ALL Expansion Drop is one
line of data. Corrects lesson 06's NOT wording; harness.md M7 details.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
5.1 KiB
Module 7 scenarios: Resolving rules (NOT, identity, meta-nouns)
Each heading is a test name. The Rust test lives in tests/rust/test_07.rs and the TypeScript test in tests/ts/test_07.test.ts; both state exactly what is written here.
The level format, place, rules() and the way a test writes a sentence (BABA (0,0) IS (1,0) YOU (2,0) is three text objects) are those of Module 6. This module adds the operator NOT to the grammar, and two harness functions:
rules()is still everything the text spells, before resolution, and now includes negated rules, written"BABA IS NOT YOU".activeRules()is the rule set after the resolution pass: sorted, normalised strings, each distinct rule once. A ruleX IS NOT Ycancels everyX IS Y, wherever each is written; the negated rule itself stays in the set, because it keeps overriding. A ruleX IS Xthat survives cancels everyX IS YwhoseYis a noun other thanX(Baba can't convert). The base ruleTEXT IS PUSHis in it unlessTEXT IS NOT PUSHcancels it.hasProperty(id, prop)asks whether one object has a property under the active rules. A thing is named by its noun (ababaobject byBABA); a text object is named byTEXT. The object has the property if an active rule gives it to one of its names and no active negated rule takes it away from one of its names.
X IS NOT X is decided here and acted on later. It cancels X IS X (it is the negation of that rule, like any other), so other X IS Y conversions work again, and it stays in activeRules() as the record that every X is to vanish. Removing the objects is part of the turn, in Module 9. The tests check the cancellation and the unlocked conversion, which the sources state; they do not check that "BABA IS NOT BABA" is listed in activeRules(), which is this course's way of recording the deletion, not something the sources describe.
NOT in front of a complement negates that complement only: BABA IS NOT YOU AND WIN is BABA IS NOT YOU and BABA IS WIN. NOT in front of a subject is not part of the course's grammar: the sentence it stands in spells nothing.
Words used: the nouns BABA, ROCK; the properties YOU, PUSH; the operators IS, NOT; the meta-noun TEXT.
test_07_not_overrides
- Setup:
newBabawith an empty level 4 wide and 5 high. PlaceBABA (0,0) IS (1,0) YOU (2,0)and an objectbabaat (0,4). - Assertions 1:
hasProperty(baba, "YOU")is true. - Action: place
BABA (0,2) IS (1,2) NOT (2,2) YOU (3,2). - Assertions 2:
rules()is exactly["BABA IS NOT YOU", "BABA IS YOU", "TEXT IS PUSH"]: both sentences are still on the board.activeRules()is exactly["BABA IS NOT YOU", "TEXT IS PUSH"]: the negation overridesBABA IS YOU, although that rule is written above it.hasProperty(baba, "YOU")is false.
test_07_x_is_x_blocks_conversion
- Setup:
newBabawith an empty level 3 wide and 5 high. PlaceBABA (0,0) IS (1,0) BABA (2,0),BABA (0,2) IS (1,2) ROCK (2,2)andROCK (0,4) IS (1,4) BABA (2,4). - Assertions:
rules()is exactly["BABA IS BABA", "BABA IS ROCK", "ROCK IS BABA", "TEXT IS PUSH"].activeRules()is exactly["BABA IS BABA", "ROCK IS BABA", "TEXT IS PUSH"].BABA IS BABAblocks Baba from converting into anything, soBABA IS ROCKis not active. It doesn't block other things from converting into Baba, soROCK IS BABAis.
test_07_x_is_not_x_deletes_and_unlocks
- Setup:
newBabawith an empty level 4 wide and 5 high. PlaceBABA (0,0) IS (1,0) NOT (2,0) BABA (3,0),BABA (0,2) IS (1,2) BABA (2,2)andBABA (0,4) IS (1,4) ROCK (2,4). - Assertions:
rules()is exactly["BABA IS BABA", "BABA IS NOT BABA", "BABA IS ROCK", "TEXT IS PUSH"].activeRules()contains"BABA IS ROCK"and does not contain"BABA IS BABA".BABA IS NOT BABAcancels the lock, so the conversion is active again. (Baba is also flagged to vanish; see the note above on what the test leaves open.)
test_07_text_is_not_push
- Setup:
newBabawith an empty level 4 wide and 3 high. Place a texttext:ROCKat (0,2) and an objectrockat (3,2). - Assertions 1:
activeRules()is exactly["TEXT IS PUSH"].hasProperty(rockText, "PUSH")is true: the base rule applies to every text object.hasProperty(rock, "PUSH")is false:TEXTnames text, not the rock the text names.
- Action: place
TEXT (0,0) IS (1,0) NOT (2,0) PUSH (3,0). - Assertions 2:
rules()is exactly["TEXT IS NOT PUSH", "TEXT IS PUSH"].activeRules()is exactly["TEXT IS NOT PUSH"]: the base rule is a rule like any other and NOT cancels it.hasProperty(rockText, "PUSH")is false, and so ishasPropertyof theTEXTtext at (0,0).
test_07_leading_not_breaks_sentence
- Setup:
newBabawith an empty level 4 wide and 2 high. PlaceNOT (0,0) BABA (1,0) IS (2,0) YOU (3,0)and an objectbabaat (0,1). - Assertions:
rules()andactiveRules()are both exactly["TEXT IS PUSH"]. ANOTin front of the subject is not in the course's grammar, and the parser must not read the rest of the sentence asBABA IS YOU: theNOTis there, and dropping it would change the meaning.hasProperty(baba, "YOU")is false.