diff --git a/src/engine/parser.test.ts b/src/engine/parser.test.ts index 1ea48ff..754a64c 100644 --- a/src/engine/parser.test.ts +++ b/src/engine/parser.test.ts @@ -231,3 +231,40 @@ describe('parser — pronouns', () => { expect(result.kind).toBe('unknown') }) }) + +describe('stop-word stripping', () => { + const ctx: ParserContext = { + knownItems: ['lamp'], + knownEncounters: [], + visibleNouns: [{ id: 'lamp', aliases: ['lamp', 'oil lamp'] }], + inventoryItemIds: [], + lastNoun: null, + awaitingDisambiguation: null, + } + + it('strips a leading "at" from the noun phrase', () => { + const cmd = parse('look at lamp', ctx) + expect(cmd).toEqual({ + kind: 'verb-target', + verb: 'look', + target: { canonical: 'lamp', raw: 'lamp' }, + }) + }) + + it('strips a leading "the"', () => { + const cmd = parse('examine the lamp', ctx) + expect(cmd.kind).toBe('verb-target') + }) + + it('strips "a" and "an"', () => { + expect(parse('take a lamp', ctx).kind).toBe('verb-target') + expect(parse('take an oil lamp', ctx).kind).toBe('verb-target') + }) + + it('does not strip stop-words mid-phrase', () => { + // 'oil lamp' is the alias; 'oil at lamp' is not. Stop-words only strip from + // the head of the noun phrase, not anywhere in the middle. + const cmd = parse('take oil lamp', ctx) + expect(cmd.kind).toBe('verb-target') + }) +}) diff --git a/src/engine/parser.ts b/src/engine/parser.ts index bdab883..364e9ba 100644 --- a/src/engine/parser.ts +++ b/src/engine/parser.ts @@ -59,6 +59,9 @@ const VERB_ONLY_VERBS = new Set(['look', 'inventory', 'wait']) /** Two-word verb prefixes (e.g. "pick up X"). */ const TWO_WORD_VERBS = ['pick up'] +/** Leading stop-words stripped from the noun phrase before matching. */ +const STOP_WORDS = new Set(['at', 'the', 'a', 'an']) + function tokenize(input: string): string[] { return input.trim().toLowerCase().split(/\s+/).filter(Boolean) } @@ -126,6 +129,11 @@ export function parse(rawInput: string, ctx: ParserContext): ParsedCommand { return { kind: 'unknown', raw: trimmed, reason: 'unknown-verb' } } + // Strip leading stop-words from the noun phrase (e.g. "at", "the", "a", "an"). + while (rest.length > 0 && STOP_WORDS.has(rest[0]!)) { + rest = rest.slice(1) + } + if (rest.length === 0) { if (VERB_ONLY_VERBS.has(verb)) { return { kind: 'verb-only', verb: verb as 'look' | 'inventory' | 'wait' }