Previous: Verb Methods, Up: Verbs



4.2 Verb Record Structure

Please note that this first section is largely not something you need to use: the addVerb method allows you to avoid most of the technical details. The section on Parse Records, on the other hand, is quite important.

Verb records are used to associate particular types of user input with methods on objects. This means that when you type "list languages", a verb record somewhere (on your Player object, in fact) is used to compare against that to find out what method to call (in this case, the 'languagesVerb' method).

Verb records are stored in the verbs attribute. The verbs record has features for each language that the object has verbs on, like so:

     verb: allVerbs(
         en: <verb records>
         lb: <verb records>
     )

The label of the record, in this case allVerbs, is irrelevant, as are the labels of all records in this section, unless specificially mentioned otherwise.

The verb records themselves contain one feature for each verb word (that is, the first word of input) that the object wants to accept, like so:

     en: verbs(
         help: <verb record>
         languages: <verb record>
     )

Each actual verb record contains the language the verb was called in1, and the parsing structure:

     help: help(
         language: en
         parses: [
     	helpVerbParseName(
     	    method: helpVerb
     	    endOfInput: nil
     	)
         ]
     )

The parses feature and its list are both complicated and unusual, and are discussed in the next section.

4.2.1 Parse Records

The parses list is something that is very unusual for a MUD: it allows each verb to define how its arguments are parsed, and in fact requires that each verb do so.

Normally, a MUD understand some basic linguistic structures of one language, and attempts to shoe-horn whatever the player says into what it understands. For example, it might understand the English concepts of subject, preposition, and object, and will attempt to understand all input in those terms.

MOZ, on the other hand, allows each verb in each language to define how it wishes its input to be broken up. It attempts to do this in a way that requires as little programming knowledge as possible, but it's still not exactly simple.

The parses feature is, in fact, a list of records. This is used so that one verb word can access different methods, depending on how the rest of the line is parsed.

Important: the label of the individual parse records, such as helpVerbParseName above, must be unique within the verb in question on whatever object the parse record is being added, as addVerb uses that label to decide what to override when you update the verb.

The record structure for the records inside the parses list is as follows: the method feature contains the name of the method, whatever feature is left after that feature is removed (there should be only one) is used as the first parsing directive.

In this example:

     help: verb(
         language: en
         parses: [
     	playerHelpVerb(
     	    method: helpVerb
     	    endOfInput: nil
     	)
         ]
     )

the first, and only, parsing directive is endOfInput, which sees if the end of the user input has been reached2. This means that nothing, other than whitespace, can follow the verb word "help" for this parsing structure to match.

On the other hand, we have:

     list: verb(
         language: en
         parses: [
             playerListLanguagesVerb(
                 method: languagesVerb
                 matchWord: matchWord(
                     word: "languages"
                     rest: rest(
                         endOfInput: nil
                     )
                 )
             )
             playerListHelpVerb(
                 method: helpVerb
                 matchWord: matchWord(
                     word: "help"
                     rest: rest(
                         endOfInput: nil
                     )
                 )
             )
         ]
     )

which matches either the word languages, then end of input, or the word help followed by end of input. In the two cases, different verbs are called.

In some cases, there will be parse records inside a parse directive; in this case, matchWord has a feature, rest, which is used to match everything after whatever word matchWord is being used to match. These parse sub-records work just like the general parse records described here, except they cannot be lists, the must be single records, and they should not include a method feature.

4.2.1.1 Parsing Directives

Directive Name Arguments Effect


endOfInput nil Matches end of character input.


string any 1 atom Bind the longest string (i.e. series of space-seperated words) it can find to the atom passed to it, which is passed to the verb's method. A word is a list of anything that Char.isGraph returns true for. Because of this, string pretty much always matches the entire rest of the line. So, for example, "string: inputString" will pass the argument inputString to the verb's method containing the rest of the line.


stringUntil until string rest Fills string with words until it reaches a word that matches the word (or list of words) stored in until.


matchWord word rest The word argument should contain a string with the word that needs to be matched in the input. rest contains a full parse tree.


getWord word rest The word is filled with the next word in the input. rest contains a full parse tree.


plus first second This is the choice operator. Evaluates first as a full parse tree. If the parsing of first succeeds, returns that. Otherwise, tries to parse with second, returning that if succesful. Otherwise fails.


multiMatchWord words wordFound rest Attempts to match anything from the list of strings in words. Whichever word is actually matched is given to the method in the atom named by wordFound. rest is the parse tree for everything after that word.


article wordFound rest Same as multiMatchWord with words set to the contents of the articles attribute on the Parser object.


mayHaveArticle wordFound rest Same as article, but accepts strings that don't start with an article as well.


bracket left right rest Matches anything entirely inside the brackets defined by left and right. Works if both left and right are words or if both are single characters, but not for a mix of the two. Note that it does not deal with nesting in any real way, and will only succeed if the first word or character in that part of the parse matches left and the last matches right, regardless of what's in the middle.


Footnotes

[1] Yes, this is redundant, but there are parts of the internal code that only get to see the verb record, not the entire verbs structure

[2] this is equivalent to the end of the line entered by the user at this time