syntax-switch (macro)
Package: CURL.LANGUAGE.COMPILER

Switches execution to a block of code based on a pattern match of a source code object with a sequence of patterns.

Syntax

            {syntax-switch source-object
                       [, index:ParseIndex = BOS]
                       [, must-match?:bool = false]
                       [case pattern do statements]
                       [case pattern do statements]...
                       [else statements]
                   } 
            
source-object: An object of type CurlSource to be the target of the syntax pattern matching.
index: The optional index argument allows advanced users to start parsing source-object from somewhere other than the beginning.
must-match?: If true, a SyntaxError exception will be thrown if none of the patterns matches.
pattern: One of a number of possible syntax patterns, as described below.
statements: a sequence of expressions to be evaluated if a pattern match is successful.

Description

syntax-switch is a control construct whose syntax is similar to that of switch, but with a syntax pattern at each case statement.

It serves as a convenient form for pattern-matching and destructuring CurlSource objects into sub-pieces. It was designed specifically to assist users in writing macros; however, it need not be used only within macros definitions.

source-object is matched against each pattern in order. For the first pattern that matches, the corresponding statements are executed, with local variables defined for each named sub-pattern. If no case expression matches, the statements following else are executed if such a clause is present.

If must-match? is specified as true, and no pattern matches, then syntax-switch throws a SyntaxError. No else clause is allowed if must-match? is true. syntax-switch uses heuristics to try to generate a good syntax error, such as seeing how far the farthest pattern match got before it failed. This is sufficient to catch easy cases like a missing do. However, the quality of the default heuristics may not provide good enough error messages for all purposes, especially in the face of multiple alternatives.

A pattern consists of either an identifier naming a simple pattern, or a prefix expression describing a compound pattern.

A pattern template consists of a sequence of literal source code escaped with question marks (?). This will be explained below.

Here are the simple pattern choices:



Here are the compound patterns:



A pattern template is a sequence of normal code that must be matched exactly, interspersed with patterns escaped with question marks (?).

For example, the contents of this pattern:

{pattern alpha ?id:identifier beta}

will match the identifier alpha followed by any identifier followed by the identifier beta.

This pattern matches the same thing, but allows any number of identifiers (including zero) between alpha and beta:

{pattern alpha ?ids:{sequence ?:identifier} beta}

Note how the first pattern template said ?id:identifier. In this example, id names the pattern, so that subsequent code can access the source code that matched the pattern. Similarly, in the second example ?ids:{sequence ?:identifier} will produce an array of matches.

Named patterns are specified like this:

    {syntax-switch source
     case {pattern alpha ?id:identifier beta} do
        {output "I matched identifier ", id.name}
     else
        {error "no match"}
    }


In the body of the case, note how id is bound to the matching source code.

Typically named patterns are passed to expand-template to produce a new source code object, but advanced code might analyze them further using the methods on CurlSource and its subclasses.

When matching any of the sequence patterns, the variable is bound to a container containing a sequence of all the matches. This container can be looped through with for.

    {syntax-switch source
     case {pattern alpha ?ids:identifiers beta} do
        {output "I matched ", ids.size, " identifiers"}
     case {pattern whoops} do
        {output "someone said whoops!"}
     else
        {error "no match"}
    }


Note how this example uses the identifiers shorthand for the {sequence ?:identifier} used in the previous example; they are equivalent.

Naming a pattern is optional. If you don't need to name the matching source, just omit the name:

{pattern alpha ?:identifier beta}

Named patterns may not appear inside sequence, optional, or other constructs where it is not guaranteed to get exactly one match.

To match a literal question mark, simply double the ? character, as in {pattern ??}. Note that question marks that are part of an identifier, such as some-function?, are considered part of that identifier and are not separately matchable.

Notes

One of the goals of syntax-switch is to make it unnecessary for macro writers to know anything about the CurlSource API. However, advanced users may need to fall back on direct CurlSource calls for some operations.