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[];
}
Related ADRs
- 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