Syntax-Browser: Graphical Syntax Display

_Syntax-Browser: Graphical Syntax Display_

By Ryan Culpepper (ryanc at ccs dot neu dot edu)

Keywords: _syntax_, _syntax-browser_, _hygiene_, 
          _referential transparency_, _lexical context_


There are two common ways to view syntax objects. One is to call
syntax-object->datum and inspect the underlying S-expression with all
additional information removed. The other is to use DrScheme's
built-in syntax viewer, which shows additional properties of the
syntax object. However, neither solution shows the different lexical
contexts of subterms and identifiers within the syntax object. This
library graphically displays this information, critical for debugging
macro expansions.

Syntax-Browser API

There is a single public module in the syntax-browser collection.


Use the following require form to use the library:

> (require (planet "" ("ryanc" "syntax-browser.plt" 1)))

This provides two procedures:

> (browse-syntax syntax) -> void

Creates a frame with the given syntax object shown. More information
on using the GUI is available below.

> (browse-syntaxes list-of-syntax) -> void

Like browse-syntax, but shows multiple syntax objects in the same
frame. The primary coloring partition is shared between the two,
showing the relationships between subterms in different syntax

> (make-syntax-browser) -> (is-a?/c syntax-controller<%>)

Creates a frame with an empty syntax browser control. The syntax
browser can be scripted using the methods of the syntax-browser<%>

> (syntax-snip syntax) -> (is-a?/c snip%)
> (syntaxes-snip list-of-syntax) -> (is-a?/c snip%)

Like 'browse-syntax' and 'browse-syntaxes' above, but creates a snip
that can be displayed in an editor. In particular, evaluating
  (syntax-snip (expand #'(lambda (x) x)))
in DrScheme's interactions window will insert a syntax browser into
the interactions window.

> syntax-browser<%> : interface

Contains the following methods:

>   add-syntax : syntax [(list-of syntaxes) string] -> void

      Adds the given syntax to the browser.

      If a list of syntax objects and a string are provided, then
      the display highlights every subterm of the first syntax object
      that is a member (eq?) of the list, using the color named by
      the string argument.

>   add-separator : -> void
      Adds a horizontal line to the syntax browser.

The User Interface

The syntax-browser contains a frame with a few controls and an editor
canvas for displaying syntax objects.

The *primary partitioning* always assigns two syntax subterms the same
color if they have the same marks. In the absence of unhygienic
macros, this means that subterms with the same foreground color were
either present in the original pre-expansion syntax or generated by
the same macro transcription step.

Note that syntax colored in black always corresponds to unmarked
syntax. Such syntax may be original, or it may be produced by the
expansion of a nonhygienic macro.

The drop-down list allows the user to select a *secondary
partitionin*, applied only to identifiers. When the user clicks on a
syntax subterm, that term is highlighted in grey, and all terms in the
same equivalence class as the selected term are highlighted in blue.

Clicking on a syntax object *selects* it. The clicked subterm is
highlighted in grey, and every identical (eq?) subterm in any syntax
object displayed in the same browser is also highlighted in
grey. Syntax objects in the same *secondary partition* as the selected
subterm are highlighted in light blue---see the next section for more

The "Clear" button clears the selection.

The "Properties" button displays a property window that shows
additional information about the selected syntax object. See the
Properties section for more information.

The Secondary Partitionings

* bound-identifier=?
* module-identifier=?
* module-or-top-identifier=?

See the documentation for these predicates in the MzScheme manual.

* symbolic-identifer=?

Two identifiers are symbolic-identifier=? if discarding all lexical
context information yields the same symbol.

* same marks

Two identifiers have the same marks iff using both as the first
argument to datum->syntax-object on the same symbol yields two
bound-identifier=? identifiers.

In other words, they are almost bound-identifier=?, but they may have
different symbolic names.

* same source module

The bindings of the two identifiers come from definitions in the same

* same nominal module

The bindings of the two identifiers were imported into the current
context by requiring the same module.


When the properties pane is shown, it displays properties of the
selected syntax object. The properties pane has three tabbed pages:

  - Binding

      If the selection is an identifier, shows the binding information
      associated with the syntax object.

      *Note: See the warning in the section below.

      For more information, look up 'identifier-binding',
      'identifier-transformer-binding', and
      'identifier-template-binding' in the Help Desk.

  - Source

      Displays source location information about the syntax object.

  - Properties

      Displays properties (see 'syntax-property') of the selection
      when it has properties it knows the keys for.

Warnings about interpreting syntax

* The binding information of a *syntax object* may not be the same as
  the binding structure of the *program* it represents. The binding
  structure of a *program* is only determined after macro expansion is

  Example: (browse-syntax #'(lambda (foo) foo))
  The syntax browser will report that the inner 'foo' is unbound, even
  though in the *program* that this syntax represents, the inner 'foo'
  is bound to the outer 'foo'.

Notes and Limitations

The syntax browser does not have a way of extending the set of
available secondary partitions.

The syntax browser does not have a way of extending the set of known

The syntax browser does not preserve the distinction between
parentheses and square brackets.