Take All and More

Updated: Jan 2, 2026

Even though I had designed and implemented a robust grammar and parser system for Sharpee, many standard use cases were not implemented. In the process of porting mainframe Zork, the grammar for INCANT x y (raw text in both cases) exposed a severe weakness in my alpha grammar definitions.

Note: for the uninitiated, INCANT was an old mainframe Zork cheat that allowed you to jump to the end game.

So ADR-080 was created to address this issue and take a pause on the DUNGEO work. ADR-082 added typed slots and slotted types to expand parsing capabilities.

We implemented some features like replacement variables using colons (:argument) and greedy parsing using an ellipse (:start... to :end).

Sharpee Grammar Reference

Pattern Action Notes
go :direction going With direction constraint
north, south, east, west going Cardinal directions
northeast, northwest, southeast, southwest going Diagonal directions
up, down, in, out going Vertical/portal directions
n, s, e, w, ne, nw, se, sw, u, d going Abbreviations
look looking Intransitive
l looking Abbreviation
look [around] looking Optional word
examine :target examining Visible scope
x :target examining Abbreviation
look at :target examining
look [carefully] at :target examining_carefully Optional modifier
search [carefully] searching Optional modifier
search :target searching Visible scope
look in|inside :target searching Alternation
look through :target searching
rummage in|through :target searching
take :item taking Portable visible items
get :item taking Synonym
pick up :item taking Two-word verb
take all taking All portable items
take all but :item taking Excludes specified
take :item and :item taking Multiple items
drop :item dropping Carried scope
put down :item dropping Two-word verb
drop all dropping All carried items
drop all but :item dropping Excludes specified
put :item in|into|inside :container inserting Multiple prepositions
insert :item in|into :container inserting
put all in :container inserting All carried items
put :item on|onto :supporter putting Supporter scope
hang :item on :hook putting Higher priority
put all on :supporter putting All carried items
remove :item from :container removing
remove all from :container removing All from container
open :door opening Openable constraint
close :door closing Openable constraint
open :container with :tool opening_with With instrument
turn on :device switching_on Switchable constraint
switch on :device switching_on
turn off :device switching_off
switch off :device switching_off
lock :door with :key locking With instrument
unlock :door with :key unlocking With instrument
push :target pushing Touchable scope
shove :target pushing Synonym
move :target pushing
pull :target pulling
drag :target pulling Synonym
give :item to :recipient giving Animate constraint
give :recipient :item giving Inverted order
offer :item to :recipient giving Synonym
show :item to :recipient showing
show :recipient :item showing Inverted order
throw :item at :target throwing
throw :item to :recipient throwing
attack :target attacking
attack :target with :weapon attacking With instrument
cut :object with :tool cutting
dig :location with :tool digging
take :item from :container with :tool taking_with Triple slot
say :message... saying Greedy text slot
say :message to :recipient saying_to
shout :message... shouting Greedy text slot
whisper :message to :recipient whispering
tell :recipient about :topic telling
ask :recipient about :topic asking
write :message... writing Greedy text slot
write :message... on :surface writing_on Bounded greedy
touch :target touching Touchable scope
feel :target touching
rub :target touching
pat :target touching
stroke :target touching
poke :target touching
prod :target touching
smell :target smelling
listen listening Intransitive
listen to :target listening
read :target reading Visible scope
peruse :target reading
study :target reading
eat :item eating
drink :item drinking
wear :item wearing
put on :item wearing
take off :item taking_off
remove :item taking_off When worn
enter :target entering
get in|into|on :target entering
exit exiting Intransitive
get out|off exiting
climb :target climbing
sleep sleeping
inventory inventory
inv, i inventory Abbreviations
wait waiting
z waiting Abbreviation
save saving
restore restoring
restart restarting
quit, q quitting
score score
version version
help help
about about
trace author.trace Debug command
trace on|off author.trace
trace parser on|off author.trace
trace validation on|off author.trace
trace system on|off author.trace
trace all on|off author.trace

Pattern Syntax Legend

Syntax Meaning
:slot Entity slot (noun phrase)
:slot... Greedy text slot (captures rest of input)
[optional] Optional word
word1|word2 Alternation (either word)
visible() Must be visible to player
carried() Must be in player inventory
touchable() Must be reachable
matching({...}) Must have specific traits

Slot Types (ADR-080, ADR-082)

Entity Slots (Default)

Standard slots resolve to game entities via scope constraints.

grammar.define('take :item')
  .where('item', scope => scope.visible().matching({ portable: true }))
  .mapsTo('if.action.taking')
  .build();

Text Slots (ADR-080)

For commands that take raw text instead of entity references.

Method Syntax Behavior
.text(slot) :slot Captures single token as text
(greedy) :slot... Captures all remaining tokens as text
// Single text tokens
grammar.define('incant :word1 :word2')
  .text('word1')
  .text('word2')
  .mapsTo('dungeo.action.incanting')
  .build();

// Greedy text capture
grammar.define('say :message...')
  .mapsTo('if.action.saying')
  .build();

// Access in action:
const message = context.command.parsed.textSlots?.get('message');

Instrument Slots (ADR-080)

Mark a slot as a tool/weapon for the action. The resolved entity is available via context.command.instrument.

grammar.define('attack :target with :weapon')
  .where('target', scope => scope.visible())
  .instrument('weapon')
  .mapsTo('if.action.attacking')
  .build();

// In action code:
const weapon = context.command.instrument?.entity;

Typed Slots (ADR-082)

Built-in slot types for common value types. These are universal and always active.

Slot Type Builder Method Example Output
NUMBER .number(slot) turn dial to 29 { type: 'number', value: 29 }
ORDINAL .ordinal(slot) take first key { type: 'ordinal', value: 1 }
TIME .time(slot) wait until 10:40 { type: 'time', hours: 10, minutes: 40 }
DIRECTION .direction(slot) go north { type: 'direction', canonical: 'north' }
MANNER .manner(slot) carefully open { type: 'manner', word: 'carefully' }
QUOTED_TEXT .quotedText(slot) say "hello" { type: 'quoted_text', text: 'hello' }
TOPIC .topic(slot) ask about the war { type: 'topic', words: ['the', 'war'] }
// Number slot
grammar.define('turn dial to :n')
  .number('n')
  .mapsTo('dungeo.action.set_dial')
  .build();

// Access in action:
const dialValue = context.command.parsed?.typedSlots?.get('n');
if (dialValue?.type === 'number') {
  const position = dialValue.value;
}

Vocabulary Slots (ADR-082)

Context-aware vocabulary categories for story-specific words. Only active when context predicate passes.

// Define vocabulary (story initialization)
const vocab = world.getVocabularyProvider();

vocab.define('panel-colors', {
  words: ['red', 'yellow', 'mahogany', 'pine'],
  when: (ctx) => ctx.currentLocation === insideMirrorId
});

// Use in grammar pattern
grammar.define('push :color panel')
  .fromVocabulary('color', 'panel-colors')
  .mapsTo('dungeo.action.push_panel')
  .build();

// Access in action:
const colorMatch = context.command.parsed?.vocabularySlots?.get('color');
const color = colorMatch?.word;

Multi-Object Commands (ADR-080)

The parser detects "all", "but", and "and" patterns automatically in entity slots.

// "take all"
{ directObject: { text: "all", isAll: true } }

// "take all but sword"
{ directObject: { text: "all", isAll: true }, excluded: [{ text: "sword", entity: ... }] }

// "take knife and lamp"
{ directObject: { text: "knife and lamp", isList: true, items: [...] } }

Consecutive Slots

For patterns like give :recipient :item where slots are adjacent, the parser uses constraint-aware consumption to find entity boundaries.

Pattern Type Example Strategy
Literal delimiter put :item in :container Greedy until delimiter
Consecutive slots give :recipient :item Constraint-aware, shortest match

Command Chaining (ADR-080)

Commands can be chained with periods:

> take sword. go north. drop sword.

Commas split only when followed by a known verb:

> take knife, lamp, sword     → List: take [knife, lamp, sword]
> take knife, drop it         → Chain: take knife; drop it

MANNER Slot and Intention (ADR-082)

The MANNER slot captures adverbs that affect how actions are performed.

Built-in manner adverbs: carefully, quietly, quickly, slowly, forcefully, gently, loudly, softly, cautiously, boldly, stealthily

// Pattern with optional manner
grammar.define(':manner? open :target')
  .manner('manner')
  .entity('target')
  .mapsTo('if.action.opening')
  .build();

// In action:
const manner = context.command.intention?.manner;
if (manner === 'carefully') { /* less noise */ }

IParsedCommand Interface

interface IParsedCommand {
  actionId: string;
  structure: CommandStructure;
  directObject?: INounPhrase;
  indirectObject?: INounPhrase;
  textSlots?: Map<string, string>;
  instrument?: INounPhrase;
  excluded?: INounPhrase[];
  typedSlots?: Map<string, TypedSlotValue>;
  vocabularySlots?: Map<string, VocabularyMatch>;
}

interface INounPhrase {
  text: string;
  entity?: IFEntity;
  isAll?: boolean;
  isList?: boolean;
  items?: INounPhrase[];
}

  • ADR-080: Grammar Enhancements for Classic IF Patterns
  • ADR-082: Context-Aware Vocabulary and Extended Grammar Slots
  • ADR-054: Semantic Grammar
  • ADR-036: Parser Contracts
  • ADR-043: Scope and Implied Indirect Objects

Subscribe to My So Called Interactive Fiction Life

Don’t miss out on the latest issues. Sign up now to get access to the library of members-only issues.
jamie@example.com
Subscribe