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.
SyntaxNode
s 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))