Command Parser Reference

This page is the reference for the command parser: lexer attributes, parser methods verbs use to read parsed arguments, the preposition synonym table, and the verb search order. For the conceptual overview (grammar, BNF, lexer behaviour, the $do_command hook), see How Command Parsing Works.

Command splitting and verb-head conventions

Before tokenisation, the lexer scans the raw input for two structural rules:

Input feature

Effect

; (unescaped, outside quotes)

Splits the line into multiple commands; each is parsed and dispatched in turn.

First token begins with @

Treated as part of the verb name. @dig, @npc, @edit etc. are ordinary verbs whose names happen to start with @.

Verb names, object names, and aliases are all matched case-insensitively. The player can type LOOK, look, or Look and the same verb dispatches.

A dead-object reference (e.g. #5 for an Object that has been recycled) raises NoSuchObjectError. The task runner classifies this as a player-visible UserError and shows a clean “There is no #5” message rather than a generic execution error.

Lexer

The lexer turns a raw command string into a structured Lexer instance. It is internal plumbing; verb code never constructs one directly. It’s described here for completeness — verbs interact with the Parser instance attached to context.parser.

Lexer.command: str

The full, unparsed command string the player typed.

Lexer.words: list[str]

The tokenised words from the command, preserving quoted spans.

Lexer.dobj_str: str | None

The direct-object substring, or None if the command had no direct object.

Lexer.dobj_spec_str: str | None

Any specifier on the direct object (my, the, a possessive like Bill's). Empty string if no specifier was used; None if there was no direct object at all.

Lexer.prepositions: dict

Dict mapping each preposition that appeared in the command to a list of [spec_str, obj_str, obj] triples. obj is None at the lexer phase; the parser fills it in during dispatch.

Parser

Parser consumes a Lexer plus the caller object and resolves names to Objects.

Parser.caller: object

The Object that issued the command (the player who typed it).

Parser.command: str

The full, unparsed command string. Inherited from the lexer.

Parser.words: list[str]

The tokenised words from the command. Inherited from the lexer.

Parser.dobj_str: str | None

The direct-object substring. Inherited from the lexer.

Parser.dobj_spec_str: str | None

Direct-object specifier. Inherited from the lexer.

Parser.dobj: object

The resolved direct object as an Object, or None if it could not be resolved or no direct object was given.

Parser.prepositions: dict

Dict mapping each preposition that appeared to [spec_str, obj_str, obj] triples. After parsing, obj is the resolved Object (or None if it could not be resolved).

Parser.verb: object

The Verb selected by dispatch, set after get_verb() runs.

Parser.this: object

The Object the verb was matched on (last-match-wins; see Command Parser Reference).

Most of these are read internally during dispatch. The two things verb code actually uses on context.parser are context.parser.command (the original command string) and the argument-extraction methods, listed next.

Parser methods

Parser.get_dobj(lookup=False)

Return the direct object as an Object. Use this when the argument refers to an existing game object.

Parameters:

lookup – if True, fall back to a global moo.sdk.lookup() by name when no local match is found. Local matches always take precedence — this prevents @obvious crate from resolving to a faraway “wooden crate” when the player has their own crate in the room.

Raises:

NoSuchObjectError – if the direct object string didn’t resolve to a real object.

Parser.get_dobj_str()

Return the direct object as a raw string. Use this when the argument is plain text (a message, a name to create, a code snippet) rather than a reference to an existing game object.

Raises:

NoSuchObjectError – if no direct object string was given.

Parser.has_dobj(lookup=False)

Return True if the parser resolved a direct object to a real Object.

Parser.has_dobj_str()

Return True if a direct object string was given on the command line, regardless of whether it resolved to an object.

Parser.get_pobj(prep, lookup=False)

Return the indirect object for prep as an Object. Synonym prepositions (e.g. using for with) are resolved to their canonical form automatically.

Parameters:
  • prep – the preposition (canonical form or any synonym).

  • lookup – if True, fall back to a global moo.sdk.lookup() by name when no local match is found.

Raises:
Parser.get_pobj_str(prep, return_list=False)

Return the indirect object for prep as a raw string. Use this when the argument is plain text rather than an object reference.

Parameters:
  • prep – the preposition (canonical form or any synonym).

  • return_list – if True and multiple matches were given, return all of them as a list. Default returns the first.

Raises:
Parser.get_pobj_spec_str(prep, return_list=False)

Return the specifier (my, the, possessive form) used with the indirect object for prep. Useful when a verb wants to behave differently for my X vs. plain X. Returns the empty string if no specifier was given.

Parameters:
  • prep – the preposition (canonical form or any synonym).

  • return_list – if True and multiple matches were given, return all specifiers as a list.

Raises:

NoSuchPrepositionError – if prep was not present in the command.

Parser.has_pobj(prep)

Return True if the parser resolved an indirect object for prep to a real Object. Synonym prepositions are resolved to their canonical form automatically.

Parser.has_pobj_str(prep)

Return True if an indirect object string was given for prep, regardless of whether it resolved to an object. Synonym prepositions are resolved to their canonical form automatically.

Use get_*_str() when the argument is plain text (a message, a name to create, etc.). Use get_*() when you expect the argument to refer to an existing game object — and let the exception propagate if it doesn’t. The task runner shows a clean error to the player; you don’t need a try/except just to report the failure. See Creating MOO Verbs for the canonical patterns.

Object resolution

When the parser encounters a name in the command, it resolves it to an Object using these rules in order:

Form

Resolution

me

The caller (the player who typed the command).

here

The caller’s location.

#N (e.g. #22)

The Object with that primary key. Raises NoSuchObjectError if no such Object exists.

my <name>

Search the caller’s inventory for <name>.

<player>'s <name>

Find <player> in the caller’s location, then search their inventory for <name>. Raises NoSuchObjectError for the player if they’re not in the room.

<name> (no specifier)

Search the caller’s location first; if no match, fall back to the caller’s inventory.

All name and alias matches are case-insensitive. Hidden-placement objects (placed under or behind something) are excluded from location searches by name. They can only be reached by look under <target> or look behind <target>, which read the placement table directly.

get_dobj(lookup=True) and get_pobj(prep, lookup=True) add a final fallback to a global lookup() if no local match exists. Local matches always win — @obvious crate matches the crate in your room even when a “wooden crate” exists elsewhere in the world.

Preposition synonym groups

settings.PREPOSITIONS defines preposition synonym groups. Words in the same group are interchangeable; the parser normalises every synonym to the first (canonical) word in the group when storing the parsed result.

Canonical

Synonyms

with

using

at

to

before

in front of

in

inside, into, within

on

onto, upon, above, on top of

from

out of, from inside

over

through

under

underneath, beneath, below

around

round

between

among

behind

past

beside

by, near, next to, along

for

about

is

as

off

off of

Verb authors should use the canonical (first) form in --ispec shebang options and in parser API calls such as get_pobj_str("with"). Synonyms also work transparently if passed directly to those methods, but staying canonical avoids surprises.