Sprache Command Flow
Commands
A single command is encapsulated in a
Command object. It can be created from either a string or an array of tokens, and both forms are always stored internally. When created from a string, the constructor automatically parses it into tokens. When created from a list of tokens, it assembles them into a single string, quoting tokens as necessary so that the result could be successfully re-parsed. Any time a command is sent, a
Command object is passed to the Switchboard. The parser then examines the tokens, consults its list of valid commands, and performs the appropriate actions. If the command is printed out or sent over the network, it is first converted to a string.
Command flow
Commands are read and
Command objects are created by the
Feeder, which passes them to the
Switchboard. The
Switchboard first checks if it can handle the command itself, and then sends it to each attached
ViewControl (usually only one). Some commands are not parsed completely by the
ViewControl; instead a certain prefix in the command triggers it to send the command to another object for further processing. This process of partial parsing and forwarding continues until the entire command is processed.
As an example, consider the command
function Camera3D set location 1 2 3. When it enters the
ViewControl, the first thing the parser examines is the first token,
function. Upon seeing this, it delegates the command to the root
FunctionGroup object, which handles all of the function-related commands.
FunctionGroup starts parsing where
ViewControl left off, after
function. When it sees that the next token is a string,
Camera3D, it looks up the function with that name, and passes the command to it. The
Camera3D, then, sees that the next tokens are
set location. This is a command it can handle itself, so it reads the next three tokens to determine the coordinates, and moves accordingly to position (1, 2, 3).
Code generation
The parser is called from in a method named
handleCommand in each class that can accept commands, which takes a single
Command argument. This method calls a
SpracheParser object to parse the command based on the command definitions that were specified during creation. If the command is parsed successfully, it returns normally. Otherwise it throws either an
UnknownCommandException if it could not find a matching command, or a
SyntaxException if the command was found but the arguments were invalid. The parser considers each command in order until it finds one that matches. Then the method specified for the command is called, passing it as arguments the
Command object followed by each of the command's variable arguments. Alternatively, the method can take an array of
Objects, for methods that can handle multiple commands (i.e.
Function.onSetParam()).
The
Command has a built-in iterator, so that as the command passes through the hierarchical parsing the index of the current token is stored by the previous parsing stage and then retrieved by the next stage. This shields downstream stages from having to know at what token index to start parsing. As the parser reads the arguments of the command before executing it, the iterator is advanced accordingly, leaving the iterator just after the last parsed component. When the command method returns, the iterator must be returned to this state. The parser then rewinds the iterator to the position it was at before the command was parsed, so that this condition is also satisfied by parsers of sub-commands. This property is useful when a command is sent to multiple sub-parsers, because the iterator remains in the proper position without having to manually rewind it before each parsing.
--
TimPeterson - 12 Jun 2006