On this page:
Syntax
#%quotes
syntax_  is_  integer
syntax_  is_  boolean
syntax_  is_  symbol
syntax_  is_  string
syntax_  is_  list
syntax_  to_  integer
syntax_  to_  boolean
syntax_  to_  symbol
syntax_  to_  string
syntax_  to_  list
integer_  to_  syntax
boolean_  to_  syntax
symbol_  to_  syntax
string_  to_  syntax
list_  to_  syntax
syntax_  split
syntax_  join
syntax_  read

8 Syntax Objects, Patterns, and Templates🔗ℹ

See Syntax Objects for an overview of syntax objects.

A syntax object is a representation of source code. It is written as quoted term using single quotes, such as '1 + * 4 f()'. A syntax object is not a string, even though it uses quote marks. Instead, the usual shrubbery rules apply inside quotes, and shrubbery structure is preserved in a syntax object. That is, a string records a sequence of characters, but a syntax object represents structure that might be written in different ways; in particular, the printed form of a syntax object tends to use «» shrubbery notation instead of shrubbery notation’s whitespace-sensitive format.

When a syntax object is written using quotes, the #%quotes form is used implicitly, similar to the way that square brackets implicitly use #%brackets.

> 'apple'

- Syntax

'apple'

> #%quotes 'apple'

- Syntax

'apple'

> '1 + 2'

- Syntax

'1 + 2'

> 'fun (x):

     x + 1'

- Syntax

'fun (x):« x + 1 »'

An expression written with quotes is more generally a template, because it can include $ as an escape and an ellipsis (written as ...) to instantiate a repetition. Syntax patterns in match are also written with quotes, $ as an escape, and an ellipsis to match a repetition.

Rules for $ and ... in patterns:

When $ appears in a pattern, then it must be followed by either (1) an identifier, or (2) parentheses containing an identifier followed by :: Identifier.

In the simple case that the identifier is not annotated with :: Identifier and the pattern has no ellipses (written as ...), then the identifier is bound to a non-empty sequence of terms from the corresponding part of the input syntax object. Sequences are matched greedily, meaning that as many terms are matched to an identifier as possible to find a match for the pattern overall.

> match '1 2 3 4'

  | '1 $x 4': x

- Syntax

'2 3'

> match 'a b c d'

  | '$x $y': [x, y]

- Listof(Syntax)

['a b c', 'd']

An identifier annotated with :: Identifier after $ can only match an individual identifier in the input.

> match 'a b c d'

  | '$(x :: Identifier) $y': [x, y]

['a', 'b c d']

> match '1 2'

  | '$(x :: Identifier) $y': [x, y]

  | '$z': [z]

['1 2']

When an ellipsis ... appears in a pattern, then it greedily matches 0 or more repetitions of the preceding pattern element. If the preceding element contains a $ escape, then the escaped identifier is not bound to a single syntax object, but it is instead bound as a repetition that holds each matched term. A repetition can only be referenced through a corresponding escape in a template. Ellipses can be nested in a pattern, and a repettion must be used in a template with the same amount of nesting as in its pattern.

> match 'a a a b d'

  | 'a ... b c ... d': "matches"

- String

"matches"

> match 'a a a b'

  | '$x ... b': 'matches as $x ...'

- Syntax

'matches as a a a'

> match '(a 1) (b 2) (c 3)'

  | '($x $y) ...': ['$x ...', '$y ...']

- Listof(Syntax)

['a b c', '1 2 3']

> match '(a: 1) (b: 2 3 4) (c: 5 6)'

  | '($x: $y ...) ...': ['$x ...', '($y ...) ...']

- Listof(Syntax)

['a b c', '(1) (2 3 4) (5 6)']

When an ellipsis appears by itself in a shrubbery group, then the pattern matches 0 or more repetitions of the preceding group. If the group is an alternative written with |, then the pattern matches 0 or more alternatives.

> match 'a

         b c

         d'

  | '$x

     ...':

      '{$x, ...}'

- Syntax

'{a, b c, d}'

> match 'cases

         | a

         | b c

         | d'

  | 'cases

     | $x

     | ...':

      '{$x, ...}'

- Syntax

'{a, b c, d}'

Rules for $ and ... in templates:

When $ appears in a template, then it must be followed by an identifier or an expression that is written as a single term (e.g., a parenthesized expression).

If an identifier is provided, then it can refer to a repetition that is bound by a syntax-pattern match, as long as the $-escaped identifier in the template is under a number of ellipses that match the repetition binding. Each element of the repetition is put in the result syntax object in place of the escape. The rules for patterns above show several example templates that use repetitions.

If an escape does not refer to a repetition, then it must have an expression that produces a syntax object, and it must not be under any ellipses. The syntax object replaces the escape in the result syntax object.

> '1 $(if #true | '2' | 'oops') 3'

- Syntax

'1 2 3'

type

Syntax

The type for expressions that produce syntax objects.

expression

#%quotes 'term ...

          ...'

Produces a syntax object, quoting the terms literally instead of treating them as subexpressions. Usually, #%quotes is omitted, since it is implied by using quotes as an expression form.

See above for information about $ escapes within the quotes for a syntax object.

function

fun syntax_is_integer(stx :: Syntax) :: Boolean

 

function

fun syntax_is_boolean(stx :: Syntax) :: Boolean

 

function

fun syntax_is_symbol(stx :: Syntax) :: Boolean

 

function

fun syntax_is_string(stx :: Syntax) :: Boolean

 

function

fun syntax_is_list(stx :: Syntax) :: Boolean

The syntax_is_integer function checks whether a syntax object has a single term representing a number, returning #true if so and #false otherwise. Other functions check for different kinds of primitive values as representations.

The syntax_is_list function checks whether a syntax object would match the pattern '[$elem ..., ...]', returning #true if so and #false otherwise.

> syntax_is_integer('9')

- Boolean

#true

> syntax_is_integer('apple')

- Boolean

#false

> syntax_is_list('[w, x y, z]')

- Boolean

#true

> syntax_is_list('a b c')

- Boolean

#false

function

fun syntax_to_integer(stx :: Syntax) :: Int

 

function

fun syntax_to_boolean(stx :: Syntax) :: Boolean

 

function

fun syntax_to_symbol(stx :: Syntax) :: Symbol

 

function

fun syntax_to_string(stx :: Syntax) :: String

 

function

fun syntax_to_list(stx :: Syntax) :: Listof(Syntax)

The syntax_to_integer function extracts the number that a syntax object represents, but only if syntax_is_integer would return #false; otherwise an exception is raised. Other functions similarly extract values from syntax representations.

> syntax_to_integer('9')

- Int

9

> syntax_to_list('[w, x y, z]')

- Listof(Syntax)

['w', 'x y', 'z']

function

fun integer_to_syntax(n :: Int) :: Syntax

 

function

fun boolean_to_syntax(bool :: Boolean) :: Syntax

 

function

fun symbol_to_syntax(sym :: Symbol) :: Syntax

 

function

fun string_to_syntax(str :: String) :: Syntax

 

function

fun list_to_syntax(lst :: Listof(Syntax)) :: Syntax

The inverse of syntax_to_integer, etc., converting a value into a syntax representation.

> integer_to_syntax(9)

- Syntax

'9'

> list_to_syntax(['w', 'x y', 'z'])

- Syntax

'[w, x y, z]'

function

fun syntax_split(stx :: Syntax) :: Listof(Syntax)

 

function

fun syntax_join(stx :: Syntax) :: Listof(Syntax)

Functions for simple splitting and joining tasks. For more general and precise tasks, use match and template construction with #%quotes, potentially converting to and from form that list_to_syntax and syntax_to_list can handle.

The syntax_split function takes a single-group syntax object and splits it into a list of term syntax objects, or it takes a multi-group syntax object and splits it into a list of group syntax objects.

The syntax_join function combines a list of term syntax objects into one group syntax object, and it splices a list of multi-group syntax objects into a multi-group syntax object.

> syntax_split('1 2 3')

- Listof(Syntax)

['1', '2', '3']

> syntax_split('1 2 3

                4 5')

- Listof(Syntax)

['1 2 3', '4 5']

> syntax_join(['1', '2', '3'])

- Syntax

'1 2 3'

> syntax_join(['1', '2 3', '4'])

- Syntax

'1; 2 3; 4'

> syntax_join(['1', '2 3', '4

                            5'])

- Syntax

'1; 2 3; 4; 5'

function

fun syntax_read() :: Syntax

Reads shrubbery input from the program’s current input and produces a syntax object. Assuming no syntax errors, input is read until terminated by an end-of-file.