2.2 Syntax Objects🔗ℹ

A syntax object combines a simpler Rhombus value, such as a symbol or list, with lexical information, source-location information, and syntax properties. The underlying value within a syntax object represents a shrubbery form (see Parsed Representation), so it is symbols for identifiers, lists to hold parenthesized group sequences, and so on. The lexical information of a syntax object comprises a set of scope sets, one for each phase level. In particular, an identifier is represented as a syntax object containing a symbol, and its lexical information can be combined with the global table of bindings to determine its binding (if any) at each phase level. Different components within a compound syntax object, such as one that represents a block or parenthesized sequence, can have different lexical information.

For example, a List identifier might have lexical information that designates it as the List from the rhombus language (i.e., the built-in List). Similarly, a fun identifier’s lexical information may indicate that it represents a function form. Some other identifier’s lexical information may indicate that it references a top-level variable.

When a syntax object represents a more complex expression than an identifier or simple constant, its internal components can be extracted. Even for extracted identifiers, detailed information about binding is available mostly indirectly; two identifiers can be compared to determine whether they refer to the same binding (i.e., syntax_meta.equal_binding), or whether the identifiers have the same scope set so that each identifier would bind the other if one were in a binding position and the other in an expression position (i.e., syntax_meta.equal_name_and_scopes).

For example, when the program written as

fun (x):

  x + 6

is represented as a syntax object, then two syntax objects can be extracted for the two xs. Both the syntax_meta.equal_binding and syntax_meta.equal_name_and_scopes predicates will indicate that the xs are the same. In contrast, the fun identifier is not syntax_meta.equal_binding or syntax_meta.equal_name_and_scopes to either x.

The lexical information in a syntax object is independent of the rest of the syntax object, and it can be copied to a new syntax object in combination with an arbitrary other Rhombus value. Thus, identifier-binding information in a syntax object is predicated on the symbolic name of the identifier as well as the identifier’s lexical information; the same question with the same lexical information but different base value can produce a different answer.

For example, combining the lexical information from fun in the program above to #'x would not produce an identifier that is syntax_meta.equal_binding to either x, since it does not appear in the scope of the x binding. Combining the lexical context of the 6 with #'x, in contrast, would produce an identifier that is syntax_meta.equal_name_and_scopes to both xs.

The Syntax.literal_local form bridges the evaluation of a program and the representation of a program. Specifically, Syntax.literal_local'datum' produces a syntax object that preserves all of the lexical information that datum had when it was parsed as part of the Syntax.literal_local form. Note that the Syntax.literal form is similar, but it removes certain scopes from the datum’s scope sets. Just using quotes, as in 'datum', is similar to using Syntax.literal, except that an escaping $ is recognized within datum.