Dealing with syntax results

When syntax is matched by a SyntaxElement or a Syntax object, a SyntaxEnvironment object is built up, containing information on what was matched to bound symbols, as well as where in the structure a given symbol was matched.

The simplest use of a SyntaxEnvironment is just to retrieve the values using the indexer, for instance to retrieve the value of the bound symbol 'a', use syntaxEnv["a"].Value. What the indexer actualler returns is a SyntaxNode, which represents a single matched element from the pattern.

SyntaxNodes contained by a SyntaxEnvironment form a tree with a structure similar to the structure of the SyntaxElement tree that was matched. There are four important differences: SyntaxNodes only have three types (List, Symbol and Value); a SyntaxNode is not created when a literal element is matched; items matched as part of an ellipsis generate zero or more nodes depending on how many items are matched; and bound symbols generate both a symbol node and a value node.

For example, the scheme pattern ((a b ...) literal 5) will produce the following SyntaxElement tree:

SyntaxElement tree built up from the scheme pattern ((a b ...) literal c)

When this pattern is matched against ((1 2 3 4) literal 5), it will produce the following SyntaxNode tree:

SyntaxNode tree built from matching the above pattern against ((1 2 3 4) literal 5)

List nodes are used for all the list and vector SyntaxElement type (from a syntactic point of view, these are all handled the same way: it's merely what is matched that changes). When you retrieve the SyntaxNode for the symbol b, you get the leftmost node in the tree that matched that symbol. This will be the node containing the symbol b, not the value node that is its child - or null if no matches were made against that symbol. You can also retrieve the root of the syntax tree from the syntax environment: this is syntaxEnv.SyntaxTree.Child - note that there is an extra node marking 'the point at which matching started'.

You can retrieve the other values matched for b by taking the Sibling of the returned node repeatedly. As ellipsises in scheme syntax can only occur at the end of a list, all the siblings until null is returned will be the repetitions of the symbol b.

The Value property of a Symbol node retrieves the value of the unlying Value node, for convieniences sake. Ie, syntaxEnv["a"].Value is equivalent to syntaxEnv["a"].Child.Value. It is not possible to take the value of a List node.

Things get a bit more complicated if ellipsises are nested - for example, the pattern ((b ...) ...). In these cases, knowing the tree structure is more important. The second ellipsis list appears in the node tree as the parent of the element b - or at the root of the tree, looking from the top down instead of from the bottom up. Once again syntaxEnv["b"] will retrieve the leftmost (ie, first) match for the symbol 'b', but secondary matches also appear under the parent of that node.

Caution must be exercised to take account of the possibility of no matches. The scheme (() (1 2) (3)) matched against the pattern ((b ...) ...) will produce the following tree. syntaxEnv["b"] will be the first match for the symbol b, which is in the second repetition:

SyntaxNode tree built from matching ((b ...) ...) against (() (1 2) (3))