-
Notifications
You must be signed in to change notification settings - Fork 0
Parser
vCommands's main purpose is executing command strings.
For that, it needs to tokenize and parse them.
Tokenizing means analyzing a string and turning it into a sequence of tokens, which have a known meaning.
vCommands uses a single method to turn a string into tokens. Currently, it is an iterator method and works in linear time. It uses a few variables for state to establish clear syntactical precedence rules and to determine the token types accurately without ever having to look back, or forward.
The method also reports every syntactical error it picks up through System.FormatException.
Note that not all syntactical errors are picked up by the tokenizer.
Also, no semantic errors are picked up.
The tokenizer also makes the difference between command names and arguments because the order (command first, then arguments) is universal.
Escaping is also handled by the tokenizer, turnings strings like a\ space and "a space" into the same token, containing both words separated by a space, while normally a space would be two entirely different tokens.
Internally, tokens are structs which have a known type (of token) and an associated string.
Parsing means turning a sequence of tokens into a usable expression tree.
vCommands uses a single parsing method recursively, which only makes use of a token enumerator. It uses a stack and a few cached expressions to construct the result expression in linear time.
This method picks up all syntactic errors (including those that the tokenizer cannot pick up) and a few semantic errors which can only exist if the given tokens are not produced by the tokenizer provided by the vCommands.
Due to its nature, feeding the tokenizer's resulted enumeration to the parser will turn the string into an expression in linear time. Whenever the parser needs a token, the tokenizer will yield one. It will not loop through the sequence of tokens; it will ask for each token to be given.
For its output, the parser makes use of a few expression classes, encapsulating every supported syntactical feature.
4 types of expressions are employed, all of which derive from an abstract Expression class.
Every expression is also sealable, meaning that it will no longer be changeable in any way, shape or form after a specific method is called. This mechanism is introduced to ease the construction of expressions and to prevent accidental or purposely-malicious change.
These expressions denote basic command invocations: an optional toggler, a command name and a sequence of arbitrary expressions as arguments.
Evaluating this expression requires a non-null context with a host, from which to extract the right command to invoke.
The evaluation of this expression does not evaluate its arguments. Instead, they are fed directly to the command as arguments to do whatever is necessary. (this basically allows commands to act as control structures)
2. Conditional
The conditional expressions are an expressive way of controlling which command(s) get(s) executed under some circumstances.
They consist of a condition, a primary action and an optional secondary action. The truth value which determines which action is executed is also variable, depending on whether it is an "inclusive" conditional or an "exclusive" one.
The condition is evaluated first. If the status returned by it corresponds to the chosen truth value, the primary action is evaluated and its results are returned. Otherwise, if a secondary action is present, it is evaluated and its results are returned. If no secondary action is present, the condition's results are returned.
3. Series
These consist of a simple sequence of one or more expressions.
Each expression in the series is evaluated, and it returns the status of the last expression and the concatenated outputs of all expressions.
4. Constant
These expressions have a constant string value which never changes. They are sealed upon construction and always return status 0 and the constant string as output.
Even though compound arguments are a syntax feature, they do not have a specific expression.
Instead, the parser just finds whatever expression is inside the compound argument and provides that to the respective command invocation.
If there was an expression for compound arguments, it would simply contain one expression, so it is futile.
On a related note, every expression can be flawlessly turned back into a string (which will parse into the same expression).
Too much or not enough information?
Just give vCommands a try. Grab the latest release or clone it.
Every single public thing in vCommands is documented. Be sure to grab the .XML file associated with your release or reference the project directly to have the documentation available through IntelliSense.
Please feel free to contribute to the wiki and the code. If you do not want to but still want to make a contribution, please post an issue or contact the author directly.