From e56b4cdb7165d10b888c1007d436bc8740db75c9 Mon Sep 17 00:00:00 2001 From: Ryan Culpepper Date: Tue, 5 Feb 2008 17:38:58 +0000 Subject: [PATCH] scribbled macro-debugger docs svn: r8542 original commit: 6fa6ea3bb327755509b3d9de8f3e219c28f323d0 --- collects/macro-debugger/info.ss | 1 + collects/macro-debugger/macro-debugger.scrbl | 307 +++++++++++++++++++ 2 files changed, 308 insertions(+) create mode 100644 collects/macro-debugger/macro-debugger.scrbl diff --git a/collects/macro-debugger/info.ss b/collects/macro-debugger/info.ss index daf5f05..cd94c97 100644 --- a/collects/macro-debugger/info.ss +++ b/collects/macro-debugger/info.ss @@ -3,3 +3,4 @@ (define name "Macro Debugger") (define tools '(["tool.ss"])) (define tool-names '("Macro Stepper")) +(define scribblings '(("macro-debugger.scrbl"))) diff --git a/collects/macro-debugger/macro-debugger.scrbl b/collects/macro-debugger/macro-debugger.scrbl new file mode 100644 index 0000000..0a409c0 --- /dev/null +++ b/collects/macro-debugger/macro-debugger.scrbl @@ -0,0 +1,307 @@ +#lang scribble/doc +@(require scribble/manual + scribble/struct + scribble/eval + (for-label scheme/base + macro-debugger/expand + macro-debugger/stepper + macro-debugger/stepper-text + macro-debugger/syntax-browser + (rename-in scheme (free-identifier=? module-identifier=?)))) + +@(define the-eval + (let ([the-eval (make-base-eval)]) + (the-eval '(require macro-debugger/expand + macro-debugger/stepper-text)) + the-eval)) + +@title{Macro debugger} + +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. + +@section{Macro stepper} + +@defmodule[macro-debugger/stepper] + +@defproc[(expand/step [stx any/c]) + (is-a/c macro-stepper<%>)]{ + + Expands the syntax (or S-expression) and opens a macro stepper frame + for stepping through the expansion. +} + +@definterface[macro-stepper<%> ()]{ + +@defmethod[(at-start?) boolean?] +@defmethod[(at-end?) boolean?] +@defmethod[(navigate-to-start) void?] +@defmethod[(navigate-to-end) void?] +@defmethod[(navigate-previous) void?] +@defmethod[(navigate-next) void?] +@defmethod[(at-top?) boolean?] +@defmethod[(at-bottom?) boolean?] +@defmethod[(navigate-up) void?] +@defmethod[(navigate-down) void?] +} + +@section{Macro expansion tools} + +@defmodule[macro-debugger/expand] + +@defproc[(expand-only [stx any/c] [transparent-macros (listof identifier?)]) + syntax?]{ + + Expands the given syntax @scheme[stx], but only shows the expansion + of macros whose names occur in @scheme[transparent-macros]. + + @(examples #:eval the-eval + (syntax->datum + (expand-only #'(let ([x 1] [y 2]) (or (even? x) (even? y))) + (list #'or)))) + + Warning: because of limitations in syntax, expansion, and hiding, + the resulting syntax may not evaluate to the same thing as the + original syntax. +} + +@defproc[(expand/hide [stx any/c] [hidden-macros (listof identifier?)]) + syntax?]{ + + Expands the given syntax @scheme[stx], but hides the expansion of macros in the + given identifier list (conceptually, the complement of expand-only). + + @(examples #:eval the-eval + (syntax->datum + (expand/hide #'(let ([x 1] [y 2]) (or (even? x) (even? y))) + (list #'or)))) + + Warning: because of limitations in syntax, expansion, and hiding, + the resulting syntax may not evaluate to the same thing as the + original syntax. +} + +@section{Macro stepper text interface} + +@defmodule[macro-debugger/stepper-text] + +@defproc[(expand/step-text [stx any/c] + [macro-policy (or/c (-> identifier? boolean?) + (listof identifier?)) + null]) + void?]{ + + 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. + + @(examples #:eval the-eval + (expand/step-text #'(let ([x 1]) (even? x))) + #;(expand/step-text #'(let ([x 1] [y 2]) (or (even? x) (even? y))) + (lambda (id) (eq? (syntax-e id) 'or)))) +} + +@defproc[(stepper-text [stx any/c] + [macro-policy (or/c (-> identifier? boolean?) + (listof identifier?))]) + (symbol? -> void?)]{ + + Returns a procedure that can be called on the symbol + @scheme['next] to print the next step or on the symbol + @scheme['all] to print out all remaining steps. +} + +@section{Syntax browser} + +@defmodule[macro-debugger/syntax-browser] + +@defproc[(browse-syntax [stx syntax?]) + void?]{ + + Creates a frame with the given syntax object shown. More information + on using the GUI is available below. +} + +@defproc[(browse-syntaxes [stxs (listof syntax?)]) + void?]{ + + Like @scheme[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. +} + +@;{ +@defproc[(syntax-snip [stx syntax?]) + (is-a/c snip%)]{ + + Like @scheme[browse-syntax], but creates a snip that can be + displayed in an editor. +} +} + +@section{Using the macro stepper} + +@subsection{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. + +@subsection{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. + +@section{Using the syntax browser} + +@subsection{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). + +@subsection{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. + +@subsection{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: +@itemize{ +@item{@scheme[bound-identifier=?]} +@item{@scheme[module-identifier=?]} +@item{@scheme[module-or-top-identifier=?]} +@item{@bold{symbolic-identifier=?}: + Two identifiers are symbolic-identifier=? if discarding all lexical + context information yields the same symbol. +} +@item{@bold{same marks}: + Two identifiers have the same marks if (barring nonhygienic macros) + they were produced by the same macro transformation step. +} +@item{@bold{same source module}: + The bindings of the two identifiers come from definitions in the + same module. +} +@item{@bold{same nominal module}: + The bindings of the two identifiers were imported into the current + context by requiring the same module. +} +} + +@subsection{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. + +@subsection{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. + +For example, in @schemeblock[(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'. + +@subsection{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. + + +@section{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.