racket/collects/macro-debugger/doc.txt
2007-09-14 18:45:14 +00:00

313 lines
10 KiB
Plaintext

_Macro Debugger_
================
Keywords: _syntax_, _syntax-browser_, _hygiene_,
_referential transparency_, _lexical context_,
_macro_, _expansion_, _macro-debugger_, _macro-stepper_
OUTLINE
=======
* Introduction
* APIs
- expand.ss
- syntax-browser.ss
* Using the macro stepper
* Using the syntax browser
* Enabling the macro stepper in other languages
* Notes for DrScheme language implementors
Introduction
============
The macro-debugger collection contains two tools: a stepper for macro
expansion and a standalone syntax browser. The macro stepper shows the
programmer the expansion of a program as a sequence of rewriting
steps, using the syntax browser to display the individual terms. The
syntax browser uses colors and a properties panel to show the term's
syntax properties, such as lexical binding information and source
location.
_stepper.ss_
============
> (require (lib "stepper.ss" "macro-debugger"))
This module provides a single procedure:
> (expand/step syntax-or-sexpr)
Expands the syntax (or S-expression) and opens a macro stepper frame
for stepping through the expansion. Returns an object of
macro-stepper<%> with the following methods:
> (send a-macro-stepper at-start?) -> boolean
> (send a-macro-stepper at-end?) -> boolean
> (send a-macro-stepper navigate-to-start) -> void
> (send a-macro-stepper navigate-to-end) -> void
> (send a-macro-stepper navigate-previous) -> void
> (send a-macro-stepper navigate-next) -> void
> (send a-macro-stepper navigate-forward/count n) -> void
> (send a-macro-stepper navigate-forward/pred pred) -> void
pred : syntax -> boolean
Navigate forward to an expansion with redex (focus) matching pred.
> (send a-macro-stepper at-top?) -> boolean
> (send a-macro-stepper at-bottom?) -> boolean
> (send a-macro-stepper navigate-up) -> void
> (send a-macro-stepper navigate-down) -> void
> (send a-macro-stepper navigate-down/pred pred) -> void
pred : syntax -> boolean
Navigate down to an expansion with initial syntax satisfying pred.
_expand.ss_
===========
> (require (lib "expand.ss" "macro-debugger"))
This module provides the following procedures:
> (expand-only syntax list-of-identifiers)
Expands the given syntax, but only shows the expansion of macros in
the given identifier list.
Warning: because of limitations in syntax, expansion, and hiding, the
resulting syntax may not evaluate to the same thing as the original
syntax.
> (expand/hide syntax list-of-identifier)
Expands the given syntax, but hides the expansion of macros in the
given identifier list (conceptually, the complement of expand-only).
Warning: because of limitations in syntax, expansion, and hiding, the
resulting syntax may not evaluate to the same thing as the original
syntax.
_stepper-text.ss_
=================
> (require (lib "stepper-text.ss" "macro-debugger"))
This module provides two procedures for stepping through macro
expansion in text-only environments.
> (expand/step-text syntax [identifier-predicate])
Expands the syntax and prints the macro expansion steps. If the
identifier predicate is given, it determines which macros are shown
(if absent, no macros are hidden). A list of identifiers is also
accepted.
> (stepper-text syntax [identifier-predicate])
Returns a procedure P that:
- when called with no arguments (or on the symbol 'next),
prints out individual steps until macro expansion finishes
- when called on the symbol 'all,
prints out all of the remaining steps
_syntax-browser.ss_
===================
> (require (lib "syntax-browser.ss" "macro-debugger"))
This module provides the following 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 coloring partitions are shared between the two,
showing the relationships between subterms in different syntax
objects.
> (syntax-snip syntax) -> (is-a?/c snip%)
Like 'browse-syntax', but creates a snip that can be displayed in an
editor. In particular, evaluating
(syntax-snip <stx>)
in DrScheme's interactions window will insert a syntax browser into
the interactions window.
Using the Macro Stepper
=======================
Navigation
----------
The stepper presents expansion as a linear sequence of rewriting
process, and it gives the user controls to step forward or backwards
as well as to jump to the beginning or end of the expansion process.
If the macro stepper is showing multiple expansions, then it also
provides "Previous term" and "Next term" buttons to go up and down in
the list of expansions. Horizontal lines delimit the current expansion
from the others.
Macro hiding
------------
Macro hiding lets one see how expansion would look if certain macros
were actually primitive syntactic forms. The macro stepper skips over
the expansion of the macros you designate as opaque, but it still
shows the expansion of their subterms.
The bottom panel of the macro stepper controls the macro hiding
policy. The user changes the policy by selecting an identifier in the
syntax browser pane and then clicking one of "Hide module", "Hide
macro", or "Show macro". The new rule appears in the policy display,
and the user may later remove it using the "Delete" button.
The stepper also offers coarser-grained options that can hide
collections of modules at once. These options have lower precedence
than the rules above.
Macro hiding, even with no macros marked opaque, also hides certain
other kinds of steps: internal defines are not rewritten to letrecs,
begin forms are not spliced into module or block bodies, etc.
Using the Syntax Browser
========================
Selection (bold)
----------------
The user can click on any part of a subterm to *select* it. To select
a parenthesized subterm, click on either of the parentheses. The
selected syntax is bolded. Since one syntax object may occur
inside of multiple other syntax objects, clicking on one occurrence
will cause all occurrences to be bolded.
The syntax browser displays information about the selected syntax
object in the properties panel on the right, when that panel is
shown. The selected syntax also determines the highlighting done by
the secondary partitioning (see below).
Primary partition (foreground color)
------------------------------------
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 transformation step.
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.
Secondary partitioning (highlight)
----------------------------------
The user may select a *secondary partitioning* from a drop-down box
(or in the macro stepper, through the Syntax menu). This partitioning
applies only to identifiers. When the user selects an identifier, all
terms in the same equivalence class as the selected term are
highlighted in yellow.
The available secondary partitionings are:
* 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 if (barring nonhygienic macros)
they were produced by the same macro transformation step.
* same source module
The bindings of the two identifiers come from definitions in the
same module.
* same nominal module
The bindings of the two identifiers were imported into the current
context by requiring the same module.
Properties
----------
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
complete.
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
properties.
The syntax browser does not preserve the distinction between
parentheses and square brackets.
Notes for DrScheme language implementors
========================================
The macro stepper works "out of the box" only with certain languages
out of all the languages available from the DrScheme languages
menu. For example, the macro stepper is disabled for the teaching
languages.
An implementor of a new DrScheme language can designate their language
"macro-steppable" by overriding the 'enable-macro-stepper?' method of
their implementation of 'drscheme:language:language<%>'. The default
implementation in the mixin provided by
'drscheme:language:get-default-mixin' returns false; override this
method to return true if the macro stepper button should be shown for
this language.
Note: There is currently no way to customize the behavior of the macro
stepper for different languages. When enabled, the macro stepper sees
exactly those terms that pass through the 'current-eval' handler.