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 The Sharpee Blog

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