diff --git a/collects/scribble/latex-render.ss b/collects/scribble/latex-render.ss index c171c0d10f..00e7a5945c 100644 --- a/collects/scribble/latex-render.ss +++ b/collects/scribble/latex-render.ss @@ -62,6 +62,7 @@ (printf "\\definecolor{LightGray}{rgb}{0.90,0.90,0.90}\n") (printf "\\newcommand{\\schemeinput}[1]{\\colorbox{LightGray}{\\hspace{-0.5ex}\\schemeinputcol{#1}\\hspace{-0.5ex}}}\n") (printf "\\newcommand{\\highlighted}[1]{\\colorbox{PaleBlue}{\\hspace{-0.5ex}\\schemeinputcol{#1}\\hspace{-0.5ex}}}\n") + (printf "\\newcommand{\\techlink}[1]{#1}\n") (printf "\\begin{document}\n") (when (part-title-content d) (printf "\\title{") diff --git a/collects/scribble/manual.ss b/collects/scribble/manual.ss index b8ad7a586c..aebaaa9b84 100644 --- a/collects/scribble/manual.ss +++ b/collects/scribble/manual.ss @@ -151,6 +151,28 @@ ;; ---------------------------------------- + (provide deftech tech) + + (define (*tech make-elem style s) + (let* ([c (decode-content s)] + [s (regexp-replace* #px"[-\\s]+" + (regexp-replace + #rx"s$" + (string-foldcase (content->string c)) + "") + " ")]) + (make-elem style + c + (format "tech-term:~a" s)))) + + (define/kw (deftech #:body s) + (*tech make-target-element #f (list (apply defterm s)))) + + (define/kw (tech #:body s) + (*tech make-link-element "techlink" s)) + + ;; ---------------------------------------- + (provide defproc defproc* defstruct defthing defform defform* defform/subs defform*/subs defform/none specform specform/subs specsubform specspecsubform specsubform/inline diff --git a/collects/scribble/scribble.css b/collects/scribble/scribble.css index 748d3b194e..04ba33ec7c 100644 --- a/collects/scribble/scribble.css +++ b/collects/scribble/scribble.css @@ -246,6 +246,15 @@ color: red; } + .techlink { + text-decoration: none; + color: black; + } + .techlink:hover { + text-decoration: underline; + color: blue; + } + .schemeresult { color: #0000af; font-family: Courier; font-size: 80%; diff --git a/collects/scribblings/reference/macros.scrbl b/collects/scribblings/reference/macros.scrbl index 14f3796e5c..7dc4c19a2b 100644 --- a/collects/scribblings/reference/macros.scrbl +++ b/collects/scribblings/reference/macros.scrbl @@ -1,202 +1,4 @@ #reader(lib "docreader.ss" "scribble") @require["mz.ss"] -@title[#:tag "mz:expansion"]{Syntax Expansion} - -Expansion recursively processes a syntax object to parse it. In -general, the parsing of a datum depends on its outermost shape: - -@itemize{ - - @item{If it is a syntax-object symbol, also known as an - @defterm{identifier}, then a binding is determined using symbol - along with the lexical information in the identifier. The - binding determines the next parsing step.} - - @item{If it is a syntax-object pair whose first element is an - identifier, then the identifier's binding is used (as in the - preceding case).} - - @item{If it is a syntax-object pair, then a new syntax-object symbol - @scheme['#%app] is created using the lexical context of the - pair. If the resulting @scheme[#%app] identifier has no - binding, parsing fails with an @scheme[exn:fail:syntax] - exception. Otherwise, the new identifier is combined with the - original pair to form a new syntax-object pair (using the same - context as the original pair), and parsing starts again (i.e., - it continues with the preceding case).} - - @item{If it is any other syntax object, then a new syntax-object - symbol @scheme['#%datum] is created using the lexical context - of the original syntax object. If the resulting - @scheme[#%datum] identifier has no binding, parsing fails with - an @scheme[exn:fail:syntax] exception. Otherwise, the new - identifier is combined with the original syntax object in a new - syntax-object pair (using the same context as the original - pair), and parsing starts again (i.e., it continues with the - second case above).} - -} - -For either of the first two steps, if the identifier has no binding, -then a new syntax-object symbol @scheme['#%top] is created using the -lexical context of the identifier; if this @scheme[#%top] identifier -has no binding, then parsing fails with an @scheme[exn:fail:syntax] -exception. Otherwise, the new identifier is combined with the -original identifier in a new syntax-object pair (using the same -context as the original identifier), and parsing starts again. - -Thus, the possibilities that do not fail lead to an identifier with a -particular binding. This binding refers to one of three things: - -@itemize{ - - @item{A transformer binding, such as introduced by - @scheme[define-syntax] or @scheme[let-syntax]. If the - associated value is to a procedure of one argument, the - procedure is called as a syntax transformer (see - @secref["transformers"]), and parsing starts again with the - syntax-object result. If the transformer binding is to any - other kind of value, parsing fails with an - @scheme[exn:fail:syntax] exception.} - - @item{A variable binding, such as introduced by a module-level - @scheme[define] or by @scheme[let]. In this case, if the form - being parsed is just an identifier, then it is parsed as a - run-time reference to the location of the corersponding - variable. If the form being parsed is a syntax-object list, - then an @scheme[#%app] is added to the front of the - syntax-object list in the same way as when the first item in - the syntax-object list is not an identifier (third case in the - previous enumeration), and parsing continues.} - - @item{Core syntax, which is parsed as described in - @secref["mz:syntax"]. Parsing core syntactic forms typically - involves recursive parsing of sub-forms, and may introduce - bindings that control the parsing of sub-forms.} - -} - -Each expansion step occurs in a particular context, and transformers -and core-syntax parsing can depend on the context. For example, a -@scheme[module] form is allowed only in a top-level context. The -possible contexts are as follows: - -@itemize{ - - @item{@defterm{top level} : outside of any module, definition, or - expression, except that sub-expressions of a top-level - @scheme[begin] form are also expanded as top-level forms.} - - @item{@defterm{module begin} : inside the body of a module, as the - only form within the module.} - - @item{@defterm{module body} : in the body of a module (inside the - moudule-begin layer).} - - @item{@defterm{internal definition} : in a nested context that allows - both definitions and expressions.} - - @item{@defterm{expression} : in a context where only expressions are - allowed.} - -} - -Different core syntax forms parse sub-forms in different contexts. For -example, a @scheme[let] form always parses the right-hand expressions -of a binding in an expression context, but it starts parsing the body -in an internal-definition context. - -@section[#:tag "mz:intdef-body"]{Internal Definitions} - -An internal-definition context corresponds to a partial expansion -step. A form that supports internal definitions starts by expanding -its first form in an internal-definition context, but only -partially. That is, it recursively expands only until the form becomes -one of the following: - -@itemize{ - - @item{A @scheme[define-values] or @scheme[define-syntaxes] form: The - definition form is not expanded further. Instead, the next form - is expanded partially, and so on. As soon as an expression form - is found, the accumulated definition forms are converted to a - @scheme[letrec-values] (if no @scheme[define-syntaxes] forms - were found) or @scheme[letrec-syntaxes+values] form, moving the - expression forms to the body to be expanded in expression - context. - - When a @scheme[define-values] form is discovered, the lexical - context of all syntax objects for the body sequence is - immediately enriched with bindings for the - @scheme[define-values] form before expansion continues. When a - @scheme[define-syntaxes] form is discovered, the right-hand - side is executed and a transformer binding is installed before - expansion continues.} - - @item{A primitive expression form other than @scheme[begin]: The - expression will be further expanded in an expression context, - along with all remaining body forms. If any definitions were - found, this expansion takes place after conversion to a - @scheme[letrec-values] or @scheme[letrec-syntaxes+values] - form. Otherwise, the expressions are expanded immediately in an - expression context.} - - @item{A @scheme[begin] form: The sub-forms of the @scheme[begin] are - spliced into the internal-definition sequence, and partial - expansion continues with the first of the newly-spliced forms - (or the next form, if the @scheme[begin] had no sub-forms).} - -} - -@section[#:tag "mz:fully-expanded"]{Fully Expanded Programs} - -A fully expanded program---that is, a parsed program---is represented -in the same way as an unparsed program: as a syntax-object. However, a -fully expanded program fits a specific grammar. - -@schemegrammar*[ -#:literals (#%expression module #%plain-module-begin begin provide - define-values define-syntaxes define-values-for-syntax - require require-for-syntax require-for-template - #%plain-lambda case-lambda if begin begin0 let-values letrec-values - set! quote-syntax quote with-continuation-mark - #%plain-app #%datum #%top #%variable-reference) -[top-level-form general-top-level-form - (#%expression expr) - (module id name-id - (#%plain-module-begin - module-level-form ...)) - (begin top-level-form ...)] -[module-level-form general-top-level-form - (provide provide-spec ...)] -[general-top-level-form expr - (define-values (id ...) expr) - (define-syntaxes (id ...) expr) - (define-values-for-syntax (id ...) expr) - (require require-spec ...) - (require-for-syntax require-spec ...) - (require-for-template require-spec ...)] -[expr id - (#%plain-lambda formals expr ...+) - (case-lambda (formals expr ...+) ...) - (if expr expr) - (if expr expr expr) - (begin expr ...+) - (begin0 expr expr ...) - (let-values (((id ...) expr) ...) - expr ...+) - (letrec-values (((id ...) expr) ...) - expr ...+) - (set! id expr) - (#, @scheme[quote] datum) - (quote-syntax datum) - (with-continuation-mark expr expr expr) - (#%plain-app expr ...+) - (#%datum . datum) - (#%top . id) - (#%variable-reference id) - (#%variable-reference (#%top . id))] -[formals (id ...) - (id ...+ . id) - id]] +@title{Macros} diff --git a/collects/scribblings/reference/model.scrbl b/collects/scribblings/reference/model.scrbl index eade9abedb..fec30e7de8 100644 --- a/collects/scribblings/reference/model.scrbl +++ b/collects/scribblings/reference/model.scrbl @@ -23,9 +23,11 @@ @define[(*state c e) (make-element #f (list langle c comma e rangle))] @define-syntax[state (syntax-rules () [(_ a b) (*state (scheme a) (scheme b))])] +@define[(frame n) (make-element "schemevariable" + (list "C" (make-element 'subscript (list (format "~a" n)))))] @;------------------------------------------------------------------------ -@title{Language Model} +@title{Evaluation Model} Scheme evaluation can be viewed as the simplification of expressions to obtain values. For example, just as an elementary-school student @@ -41,12 +43,12 @@ Scheme evaluation simplifies The arrow @reduces above replaces the more traditional @tt{=} to emphasize that evaluation proceeds in a particular direction towards -simpler expressions. In particular, a @defterm{value} is an +simpler expressions. In particular, a @deftech{value} is an expression that evaluation simplifies no further, such as the number @scheme[2]. @;------------------------------------------------------------------------ -@section{Sub-expression Evaluation} +@section{Sub-expression Evaluation and Continuations} Some simplifications require more than one step. For example: @@ -54,14 +56,14 @@ Some simplifications require more than one step. For example: (- 4 #,(redex (+ 1 1))) #,reduces #,(redex (- 4 2)) #,reduces 2 ] -An expression that is not a value can always be partitioned into two -parts: a @defterm{redex}, which is the part that changed in a +An expression that is not a @tech{value} can always be partitioned +into two parts: a @deftech{redex}, which is the part that changed in a single-step simplification (show in blue), and the -@defterm{continuation}, which is the surrounding expression +@deftech{continuation}, which is the surrounding expression context. In @scheme[(- 4 (+ 1 1))], the redex is @scheme[(+ 1 1)], and the continuation is @scheme[(- 4 #, @hole)], where @hole takes the place of the redex. That is, the continuation says how to ``continue'' -after the redex is reduced to a value. +after the @tech{redex} is reduced to a @tech{value}. Before some things can be evaluated, some sub-expressions must be evaluated; for example, in the application @scheme[(- 4 (+ 1 1))], the @@ -72,69 +74,72 @@ Thus, the specification of each syntactic form specifies how (some of) its sub-expressions are evaluated, and then how the results are combined to reduce the form away. -The @defterm{dynamic extent} of an expression is the sequence of -evaluation steps during which an expression contains the redex. +The @deftech{dynamic extent} of an expression is the sequence of +evaluation steps during which an expression contains the @tech{redex}. @;------------------------------------------------------------------------ @section{Tail Position} -An expression @scheme[_expr1] is in @defterm{tail position} with +An expression @scheme[_expr1] is in @deftech{tail position} with respect to an enclosing expression @scheme[_expr2] if, whenever -@scheme[_expr1] becomes a redex, its continuation is the same as was -the enclosing @scheme[_expr2]'s continuation. +@scheme[_expr1] becomes a redex, its @tech{continuation} is the same +as was the enclosing @scheme[_expr2]'s @tech{continuation}. -For example, the @scheme[(+ 1 1)] expression is @italic{not} in tail -position with respect to @scheme[(- 4 (+ 1 1))]. To illustrate, we use +For example, the @scheme[(+ 1 1)] expression is @italic{not} in @tech{tail +position} with respect to @scheme[(- 4 (+ 1 1))]. To illustrate, we use the notation @sub[_C _expr] to mean the expression that is produced by -substituing @scheme[_expr] in place of @hole in the continuation +substituting @scheme[_expr] in place of @hole in the @tech{continuation} @scheme[_C]: @schemeblock[ #, @sub[_C (- 4 (+ 1 1))] #, @reduces #, @sub[_C (- 4 2)] ] -In this case, the continuation for reducing @scheme[(+ 1 1)] is @sub[_C (+ -4 #, @hole)], not just @scheme[_C]. +In this case, the @tech{continuation} for reducing @scheme[(+ 1 1)] is +@sub[_C (+ 4 #, @hole)], not just @scheme[_C]. -In contrast, @scheme[(+ 1 1)] is in tail position with respect to -@scheme[(if (zero? 0) (+ 1 1) 3)], because, for any continuation @scheme[_C], +In contrast, @scheme[(+ 1 1)] is in @tech{tail position} with respect +to @scheme[(if (zero? 0) (+ 1 1) 3)], because, for any continuation +@scheme[_C], @schemeblock[ #, @sub[_C (if (zero? 0) (+ 1 1) 3)] #, @reduces #, @sub[_C (if #t (+ 1 1) 3)] #, @reduces #, @sub[_C (+ 1 1)] ] The steps in this reduction sequence are driven by the definition of -@scheme[if], and they do not depend on the continuation +@scheme[if], and they do not depend on the @tech{continuation} @scheme[_C]. The ``then'' branch of an @scheme[if] form is always in -tail position with respect to the @scheme[if] form. Due to a similar -reduction rule for @scheme[if] and @scheme[#f], the ``else'' branch of -an @scheme[if] form is also in tail position. +@tech{tail position} with respect to the @scheme[if] form. Due to a +similar reduction rule for @scheme[if] and @scheme[#f], the ``else'' +branch of an @scheme[if] form is also in @tech{tail position}. -Tail-position specifications provide a guarantee about the asymtotic -space consumption of a computation. In general, the specification of -tail positions goes with each syntactic form, like @scheme[if]. +@tech{Tail-position} specifications provide a guarantee about the +asymptotic space consumption of a computation. In general, the +specification of @tech{tail positions} goes with each syntactic form, +like @scheme[if]. @;------------------------------------------------------------------------ @section{Multiple Return Values} -A Scheme expression can evaluate to @defterm{multiple values}, in the +A Scheme expression can evaluate to @deftech{multiple values}, in the same way that a procedure can accept multiple arguments. -Most continuations expect a particular number of result values. -Indeed, most continuations, such as @scheme[(+ #, @hole 1)] expect a -single value. The continuation @scheme[(let-values ([(x y) #, @hole]) -_expr)] expects two result values; the first result replaces -@scheme[x] in the body @scheme[_expr], and the second replaces -@scheme[y] in @scheme[_expr]. The continuation @scheme[(begin #, @hole -(+ 1 2))] accepts any number of result values, because it ignores the -result(s). +Most @tech{continuations} expect a particular number of result +@tech{values}. Indeed, most @tech{continuations}, such as @scheme[(+ +#, @hole 1)] expect a single @tech{value}. The @tech{continuation} +@scheme[(let-values ([(x y) #, @hole]) _expr)] expects two result +@tech{values}; the first result replaces @scheme[x] in the body +@scheme[_expr], and the second replaces @scheme[y] in +@scheme[_expr]. The @tech{continuation} @scheme[(begin #, @hole (+ 1 +2))] accepts any number of result @tech{values}, because it ignores +the result(s). In general, the specification of a syntactic form inidicates the -number of values that it produces and the number that it expects from -each of its sub-expression. In addtion, some procedures (notably -@scheme[values]) produce multiple values, and some procedures (notably -@scheme[call-with-values]) create continuations internally that accept -a certain number of values. +number of @tech{values} that it produces and the number that it +expects from each of its sub-expression. In addtion, some procedures +(notably @scheme[values]) produce multiple @tech{values}, and some +procedures (notably @scheme[call-with-values]) create continuations +internally that accept a certain number of @tech{values}. @;------------------------------------------------------------------------ @section{Top-Level and Module-Level Variables} @@ -147,9 +152,9 @@ then an algebra student simplifies @tt{x + 1} as follows: @verbatim{ x + 1 = 10 + 1 = 11} -Scheme works much the same way, in that a set of top-level variables -are available for substitutions on demand during evaluation. For -example, given +Scheme works much the same way, in that a set of @tech{top-level +variables} are available for substitutions on demand during +evaluation. For example, given @schemeblock[ (define x 10) @@ -169,7 +174,7 @@ definitions in response to evaluating forms such as @scheme[define]. Each evaluation step, then, takes the current set of definitions and program to a new set of definitions and program. Before a @scheme[define] can be moved into the set of definitions, its -right-hand expression must be reduced to a value. +right-hand expression must be reduced to a @tech{value}. @prog-steps/no-obj[ [{} @@ -191,7 +196,7 @@ a module is essentially a prefix on a defined name, so that different modules can define the name. Using @scheme[set!], a program can change the value associated with an -existing top-level variable: +existing @tech{top-level variable}: @prog-steps/no-obj[ [{(define x 10)} @@ -207,26 +212,27 @@ existing top-level variable: @;------------------------------------------------------------------------ @section{Objects and Imperative Update} -In addition to @scheme[set!] for imperative update of top-level -variables, various procedures enable the modification of elements +In addition to @scheme[set!] for imperative update of @tech{top-level +variables}, various procedures enable the modification of elements within a compound data structure. For example, @scheme[vector-set!] modifies the content of a vector. To allow such modifications to data, we must distingiush between -values, which are the results of expressions, and @defterm{objects}, -which hold the data referenced by a value. +@tech{values}, which are the results of expressions, and +@deftech{objects}, which hold the data referenced by a value. -A few kinds of objects can serve directly as values, including +A few kinds of @tech{objects} can serve directly as values, including booleans, @scheme[(void)], and small exact integers. More generally, -however, a value is a reference to an object. For example, a value can -be a reference to a particular vector that currently holds the value -@scheme[10] in its first slot. If an object is modified, then the -modification is visible through all copies of the value that reference -the same object. +however, a @tech{value} is a reference to an @tech{object}. For +example, a @tech{value} can be a reference to a particular vector that +currently holds the value @scheme[10] in its first slot. If an +@tech{object} is modified, then the modification is visible through +all copies of the @tech{value} that reference the same @tech{object}. -In the evaluation model, a set of objects must be carried along with -each step in evaluation, just like the definition set. Operations that -create objects, such as @scheme[vector], add to the set of objects: +In the evaluation model, a set of @tech{objects} must be carried along +with each step in evaluation, just like the definition set. Operations +that create @tech{objects}, such as @scheme[vector], add to the set of +@tech{objects}: @prog-steps[ [{} @@ -292,38 +298,39 @@ create objects, such as @scheme[vector], add to the set of objects: 11] ] -The distinction between a top-level variable is an object reference is -crucial. A top-level variable is not a value; each time a variable -expression is evaluated, the value is extracted from the current set -of definitions. An object reference, in contrast is a value, and -therefore needs no further evaluation. The model evaluation steps -above use angle-bracketed @scheme[] for an object reference to -distinguish it from a variable name. +The distinction between a @tech{top-level variable} and an object +reference is crucial. A @tech{top-level variable} is not a +@tech{value}; each time a @tech{variable} expression is evaluated, the +value is extracted from the current set of definitions. An object +reference, in contrast is a value, and therefore needs no further +evaluation. The model evaluation steps above use angle-bracketed +@scheme[] for an object reference to distinguish it from a +@tech{variable} name. A direct object reference can never appear in a text-based source program. A program representation created with @scheme[datum->syntax-object], however, can embed direct references to -existing objects. +existing @tech{objects}. @;------------------------------------------------------------------------ @section{Object Identity and Comparisons} -The @scheme[eq?] operator compares two values, returning @scheme[#t] -when the values refer to the same object. This form of equality is -suitable for comparing objects that support imperative update (e.g., -to determine that the effect of modifying an object through one -reference is visible through another reference). Also, an @scheme[eq?] -test evaluates quickly, and @scheme[eq?]-based hashing is more -lightweight than @scheme[equal?]-based hashing in hash tables. +The @scheme[eq?] operator compares two @tech{values}, returning +@scheme[#t] when the values refer to the same @tech{object}. This form +of equality is suitable for comparing objects that support imperative +update (e.g., to determine that the effect of modifying an object +through one reference is visible through another reference). Also, an +@scheme[eq?] test evaluates quickly, and @scheme[eq?]-based hashing +is more lightweight than @scheme[equal?]-based hashing in hash tables. In some cases, however, @scheme[eq?] is unsuitable as a comparison -operator, because the generation of objects is not clearly defined. In -particular, two applications of @scheme[+] to the same two exact -integers may or may not produce results that are @scheme[eq?], +operator, because the generation of @tech{objects} is not clearly +defined. In particular, two applications of @scheme[+] to the same two +exact integers may or may not produce results that are @scheme[eq?], although the results are always @scheme[equal?]. Similarly, evaluation -of a @scheme[lambda] form typically generates a new procedure object, -but it may re-use a procedure object previously generated by the same -source @scheme[lambda] form. +of a @scheme[lambda] form typically generates a new procedure +@tech{object}, but it may re-use a procedure @tech{object} previously +generated by the same source @scheme[lambda] form. The behavior of a datatype with respect to @scheme[eq?] is generally specified with the datatype and its associated procedures. @@ -342,16 +349,17 @@ In the program state evaluation cannot depend on @scheme[], because it is not part of the program to evaluate, and it is not referenced by any definition -that is accessible in the program. The object @scheme[] may -therefore be removed from the evaluation by @defterm{garbage +that is accessible in the program. The @tech{object} @scheme[] may +therefore be removed from the evaluation by @deftech{garbage collection}. -A few special compound datatypes hold @defterm{weak references} to -objects. Such weak references are treated specialy by the garbage -collector in determining which objects are reachable for the remainder -of the computation. If an object is reachable only via a weak -reference, then the object can be reclaimed, and the weak reference is -replaced by a different value (typically @scheme[#f]). +A few special compound datatypes hold @deftech{weak references} to +objects. Such weak references are treated specially by the garbage +collector in determining which @tech{objects} are reachable for the +remainder of the computation. If an @tech{object} is reachable only +via a @tech{weak reference}, then the object can be reclaimed, and the +@tech{weak reference} is replaced by a different @tech{value} +(typically @scheme[#f]). @;------------------------------------------------------------------------ @section{Procedure Applications and Local Bindings} @@ -365,11 +373,12 @@ then an algebra student simplifies @tt{f(1)} as follows: @verbatim{ f(7) = 7 + 10 = 17} The key step in this simplification is take the body of the defined -function @tt{f}, and then replace each @tt{x} with the actual value -@tt{1}. +function @tt{f}, and then replace each @tt{x} with the actual +@tech{value} @tt{1}. Scheme procedure application works much the same way. A procedure is -an object, so evaluating @scheme[(f 7)] starts with a variable lookup: +an @tech{object}, so evaluating @scheme[(f 7)] starts with a +@tech{variable} lookup: @prog-steps[ [{(define (lambda (x) (+ x 10)))} @@ -380,16 +389,17 @@ an object, so evaluating @scheme[(f 7)] starts with a variable lookup: (code:hilite ( 7))] ] -Unlike in algebra, however, the value associated with an argument can -be changed in the body of a procedure by using @scheme[set!], as in -the example @scheme[(lambda (x) (begin (set! x 3) x))]. Since the value -associated with @scheme[x] can be changed, an actual value for cannot -be substituted for @scheme[x] when the procedure is applied. +Unlike in algebra, however, the @tech{value} associated with an +argument can be changed in the body of a procedure by using +@scheme[set!], as in the example @scheme[(lambda (x) (begin (set! x 3) +x))]. Since the @tech{value} associated with @scheme[x] can be +changed, an actual value for cannot be substituted for @scheme[x] when +the procedure is applied. -Instead, a new @defterm{location} is created for each variable on each -application. The argument value is placed in the location, and each -insteace of the variable in the procedure body is replaced with the -new location: +Instead, a new @deftech{location} is created for each @tech{variable} +on each application. The argument @tech{value} is placed in the +@tech{location}, and each instance of the @tech{variable} in the +procedure body is replaced with the new @tech{location}: @prog-steps[ [{(define (lambda (x) (+ x 10)))} @@ -409,14 +419,16 @@ new location: 17] ] -A location is the same as a top-level variable, but when a location is -generated, it (conceptually) uses a name that has not been used before -and that cannot not be generated again or accessed directly. +A @tech{location} is the same as a @tech{top-level variable}, but when +a @tech{location} is generated, it (conceptually) uses a name that has +not been used before and that cannot not be generated again or +accessed directly. -Generating a location in this way means that @scheme[set!] evaluates -for local variables in the same way as for top-level variables, -because the local variable is always replaced with a location by the -time the @scheme[set!] form is evaluated: +Generating a @tech{location} in this way means that @scheme[set!] +evaluates for @tech{local variables} in the same way as for +@tech{top-level variables}, because the @tech{local variable} is +always replaced with a @tech{location} by the time the @scheme[set!] +form is evaluated: @prog-steps[ [{(define (lambda (x) (begin (set! x 3) x)))} @@ -443,138 +455,85 @@ time the @scheme[set!] form is evaluated: 3] ] -The substition and location-generation step of procedure application -requires that the argument is a value. Therefore, in @scheme[((lambda -(x) (+ x 10)) (+ 1 2))], the @scheme[(+ 1 2)] sub-expression must be -simplified to the value @scheme[3], and then @scheme[3] can be placed -into a location for @scheme[x]. In other words, Scheme is a -@defterm{call-by-value} language. +The substition and @tech{location}-generation step of procedure +application requires that the argument is a @tech{value}. Therefore, +in @scheme[((lambda (x) (+ x 10)) (+ 1 2))], the @scheme[(+ 1 2)] +sub-expression must be simplified to the @tech{value} @scheme[3], and +then @scheme[3] can be placed into a @tech{location} for +@scheme[x]. In other words, Scheme is a @deftech{call-by-value} +language. Evaluation of a local binding, such as @scheme[(let ([x (+ 1 2)]) _expr)], is the same as for a procedure call. After @scheme[(+ 1 2)] -produces a value, it is stored in a fresh location that replaces every -instance of @scheme[x] in @scheme[_expr]. +produces a @tech{value}, it is stored in a fresh @tech{location} that +replaces every instance of @scheme[x] in @scheme[_expr]. @;------------------------------------------------------------------------ -@section{Identifiers, Variables, and Locations} +@section{Variables and Locations} -A @defterm{variable} is a placeholder for a value, and an expressions -in an initial program refer to variables. A top-level variable is both -a variable and a location. Any other variable is always replaced by a -location at run-time, so that evaluation of expressions involves only -locations. A single non-top-level variable, such as a procedure -argument, can correspond to different locations at different times. +A @deftech{variable} is a placeholder for a @tech{value}, and an +expressions in an initial program refer to @tech{variables}. A +@deftech{top-level variable} is both a @tech{variable} and a +@tech{location}. Any other @tech{variable} is always replaced by a +@tech{location} at run-time, so that evaluation of expressions +involves only @tech{locations}. A single @deftech{local variable} +(i.e., a non-top-level, non-module-level @tech{variable}), such as a +procedure argument, can correspond to different @tech{locations} +through different instantiations. -The replacement of a variable with a location during evaluation -implements Scheme's @defterm{lexical scoping}. For example, when the -procedure-argument variable @scheme[x] is replaced by the location -@scheme[xloc], then it is replaced throughout the body of the -procedure, including with any nested @scheme[lambda] forms. As a -result, future references of the variable always access the same -location. +For example, in the program -@guideintro["guide:binding"]{binding} +@schemeblock[(define y (+ (let ([x 5]) x) 6))] -An @defterm{identifier} is source-program entity. Parsing a Scheme -program reveals that some identifiers correspond to variables, some -refer to syntactic forms, and some are quoted to produce a symbol or a -syntax object. An identifier @defterm{binds} another when the former is -parsed as a variable and the latter is parsed as a reference to the -former. An identifier is @defterm{bound} in a sub-expression if it -binds any uses of the identifier in the sub-expression that are not -otherwise bound within the sub-expression; conversely, a binding for a -sub-expression @defterm{shadows} any bindings in its context, so that -uses of an identifier refer to the shaodowing binding. +both @scheme[y] and @scheme[x] are @tech{variables}. The @scheme[y] +@tech{variable} is a @tech{top-level variable}, and the @scheme[x] is +a @tech{local variable}. When this code is evaluated, a +@tech{location} is created for @scheme[x] to hold the value +@scheme[5], and a @tech{location} is also created for @scheme[y] to +hold the value @scheme[6]. -Throughout the documentation, identifiers are typeset to suggest the -way that they are parsed. A black, boldface identifier like -@scheme[lambda] indicates as a reference to a syntactic form. A plain -blue identifer like @schemeidfont{x} is a variable or a reference to -an unspecified top-level definition. A hyperlinked identifier -@scheme[cons] is a reference to a specific top-level definition. +The replacement of a @tech{variable} with a @tech{location} during +evaluation implements Scheme's @deftech{lexical scoping}. For example, +when a procedure-argument @tech{variable} @scheme[x] is replaced by +the @tech{location} @scheme[xloc], then it is replaced throughout the +body of the procedure, including with any nested @scheme[lambda] +forms. As a result, future references of the @tech{variable} always +access the same @tech{location}. @;------------------------------------------------------------------------ -@section{Parsing and Compilation} +@section{Continuation Frames and Marks} -The syntax of a Scheme program is defined by +Every continuation @scheme[_C] can be partitioned into +@deftech{continuation frames} @frame[1], @frame[2], ..., @frame["n"] +such that @scheme[_C] = @*sub[@frame[1] @*sub[@frame[2] @*sub["..." +@frame["n"]]]], and no frame @frame["i"] can be itself partitioned +into smaller continuations. Evaluation steps add an remove frames to +the current continuation, typically one at a time. -@itemize{ - - @item{a @defterm{read} phase that processes a character stream into a - Scheme value, especially one composed of pairs and symbols, - and} - - @item{an @defterm{expand} phase that processes the value to finish - parsing the code.} - -} - -For details on the read phase, see @secref["mz:reader"]. Source code -is normally read in @scheme[read-syntax] mode, otherwise it must be -converted to syntax using @scheme[datum->syntax]; the expand phase is -defined in terms of syntax objects. - -An identifier, for example, is a syntax-object symbol, and the -identifier's binding is determined by lexical information attached to -the identifier. Expansion recursively processes a syntax object, -both using its lexical information and extending the information for -nested objects. For details, see @secref["mz:expansion"]. - -Ultimately, expansion produces a syntax object matching the grammar -of the forms in @secref["mz:fully-expanded"]. This fully-expanded -datum corresponds to a parsed expression, and lexical information on -its identifiers indicates the parse. For example, a @scheme[car] -identifier might have lexical information that designates it as the -@scheme[car] from the @schememodname[big] language (i.e., the built-in -@scheme[car]). Similarly, a @scheme[lambda] identifier's lexical -information may indicate that it represents a procedure form. +Each frame is conceptually annotated with a set of +@deftech{continuation marks}. A mark consists of a key and its value; +the key is an arbitrary value, and each frame includes at most one +mark for any key. Various operations set and extract marks from +continuations, so that marks can be used to attach information to a +dynamic extent. For example, marks can be used to record information +for a ``stack trace'' to be used when an exception is raised, or +implement dynamically scoped bindings. @;------------------------------------------------------------------------ -@section{Namespaces} +@section{Prompts and Delimited Continuations} -A @idefterm{namespace} is a top-level mapping from symbols to binding -information. It is the starting point for expanding an expression; a -syntax object produced by @scheme[read-syntax] has no initial -lexical context; the syntax object can be expanded after -initializing it with the mappings of a particular namespace. - -A namespace maps each symbol to one of three possible bindings: - -@itemize{ - - @item{a particular module-level binding from a particular module} - - @item{a top-level transformer binding named by the symbol} - - @item{a top-level variable named by the symbol} - -} - -An ``empty'' namespace maps all symbols to top-level -variables. Importing a module into the top-level adjusts the namespace -bindings for all of the imported named. Evaluating a top-level -@scheme[define] form updates the namespace's mapping to refer to a -variable (if it does not already) and installs a value into the -variable. - -In addition to its main mapping, each namespace encapsulates a -distinct set of top-level variables, as well as a potentially distinct -set of module instances. After a namespace is created, module -instances from existing namespaces can be attached to the new -namespace. - -At all times during evaluation, some namespace is designated as the -@defterm{current namespace}. The current namespace has no particular -relationship, however, with the namespace used to expand the code that -is executing. Furthermore, a namespace is purely a top-level concept; -it does not encapsulate the full environment of an expression within -local binding forms. - -In terms of the evaluation model, top-level variables from different -namespaces essentially correspond to definitions with different -prefixes. In particular, changing the current namespace during -evaluation does not change the variables to which executing -expressions refer. +A @deftech{prompt} is a special kind of continuation frame that is +annotated with a specific @deftech{prompt-tag} (essentially a +continuation mark). Various operations allow the capture of frames in +the continuation from the redex position out to the nearest enclosing +prompt with a particular prompt tag; such a continuation is sometimes +called a @deftech{delimited continuation}. Other operations allow the +current continuation to be extended with a captured continuation +(specifically, a @deftech{composable continuation}). Yet other +operations abort the computation to the nearest enclosing prompt with +a particular tag, or replace the continuation to the nearest enclosing +prompt with another one. When a delimited continuation is captured, +the marks associated with the relevant frames are also captured. @;------------------------------------------------------------------------ @section{Threads} @@ -588,8 +547,64 @@ state. Most evaluation steps involve a single step in a single expression, but certain synchronization primitives require multiple threads to progress together in one step. -In addition to shared state, each thread has its own private state -that is accessed through @defterm{thread cells} and -@defterm{parameters}. In particular, the current namespace is a -thread-specific property implemented by a parameter; it is not a -global property. +In addition to the state that is shared among all threads, each thread +has its own private state that is accessed through @deftech{thread +cells}. A thread cell is similar to a normal mutable object, but a +change to the value inside a thread cell is seen only when extracting +a value from the cell from the same thread. A thread cell can be +@deftech{preserved}; when a new thread is created, the creating +thread's value for a preserved thread cell serves as the initial value +for the cell in the created thread. For a non-preserved thread cell, a +new thread sees the same initial value (specified when the thread cell +is created) as all other threads. + +@;------------------------------------------------------------------------ +@section{Parameters} + +A @deftech{parameter} is essentially a derived concept in Scheme; they +are defined in terms of continuation marks and thread cells. However, +parameters are also built in, in the sense that some primitive +procedures consult parameter values. For example, the default output +stream for primitive output operations is determined by a parameter. + +A parameter is a setting that is both thread-specific and +continuation-specific. In the empty continuation, each parameter +corresponds to a preserved thread cell; a corresponding +@deftech{parameter procedure} accesses and sets the thread cell's +value for the current thread. + +In a non-empty continuation, a parameter's value is determined through +a @deftech{parameterization} that is associated with the nearest +enclosing continuation frame though a continuation mark (whose key is +not directly accessible). A parameterization maps each parameter to a +preserved thread cell, and the combination of thread cell and current +thread yields the parameter's value. A parameter procedure sets or +accesses the relevant thread cell for its parameter. + +Various operations, such as @scheme[parameterize] or +@scheme[with-parameterization], install a parameterization into the +current continuation's frame. + +@;------------------------------------------------------------------------ +@section{Exceptions} + +@deftech{Exceptions} are essentially a derived concept in Scheme; they +are defined in terms of continuations, prompts, and continuation +marks. However, exceptions are also built in, in the sense that +primitive forms and procedures may raise exceptions. + +A handler for uncaught exceptions is designated through a built-in +parameter. A handler to catch exceptions can be associated with a +continuation frame though a continuation mark (whose key is not +directly accessible). When an exception is raised, the current +continuation's marks determine a chain of handler procedures that are +consulted to handle the exception. + +One potential action of an exception handler is to abort the current +continuation up to an enclosing prompt with a particular tag. The +default handler for uncaught exceptions, in particular, aborts to a +particular tag for which a prompt is always present, because the +prompt is installed in the outermost frame of the continuation for any +new thread. + + diff --git a/collects/scribblings/reference/read.scrbl b/collects/scribblings/reference/read.scrbl index 9169551f8f..e7ee81691d 100644 --- a/collects/scribblings/reference/read.scrbl +++ b/collects/scribblings/reference/read.scrbl @@ -22,19 +22,20 @@ through a @seclink["mz:readtables"]{readtable} and various other @seclink["parameters"]{parameters}. This section describes the reader's parsing when using the default readtable. -Reading from a stream produces one datum. If the result datum is a -compound value, then reading the datum typically requires the reader -to call itself recursively to read the component data. +Reading from a stream produces one @defterm{datum}. If the result +datum is a compound value, then reading the datum typically requires +the reader to call itself recursively to read the component data. The reader can be invoked in either of two modes: @scheme[read] mode, or @scheme[read-syntax] mode. In @scheme[read-syntax] mode, the result is always a @seclink["stxobj"]{syntax object} that includes -source-location information wrapped around the sort of datum that -@scheme[read] mode would produce. In the case of pairs, vectors, and -boxes, morever, the content is also wrapped recursively as a syntax -object. Unless specified otherwise, this section describes the -reader's behavior in @scheme[read] mode, and @scheme[read-syntax] mode -does the same modulo wrapping the final result. +source-location and (initially empty) lexical information wrapped +around the sort of datum that @scheme[read] mode would produce. In the +case of pairs, vectors, and boxes, morever, the content is also +wrapped recursively as a syntax object. Unless specified otherwise, +this section describes the reader's behavior in @scheme[read] mode, +and @scheme[read-syntax] mode does the same modulo wrapping the final +result. Reading is defined in terms of Unicode characters; see @secref["mz:char-input"] for information on how a byte stream is converted diff --git a/collects/scribblings/reference/reference.scrbl b/collects/scribblings/reference/reference.scrbl index 73a8c13288..30ccc6ba1b 100644 --- a/collects/scribblings/reference/reference.scrbl +++ b/collects/scribblings/reference/reference.scrbl @@ -12,8 +12,8 @@ language. @table-of-contents[] @include-section["model.scrbl"] +@include-section["syntax-model.scrbl"] @include-section["read.scrbl"] -@include-section["macros.scrbl"] @include-section["syntax.scrbl"] @include-section["derived.scrbl"] @include-section["data.scrbl"] @@ -22,7 +22,7 @@ language. @section["Input and Output"] -@subsection[#:tag "mz:char-input"]{Form Bytes to Characters} +@subsection[#:tag "mz:char-input"]{From Bytes to Characters} @;------------------------------------------------------------------------ diff --git a/collects/scribblings/reference/syntax-model.scrbl b/collects/scribblings/reference/syntax-model.scrbl new file mode 100644 index 0000000000..094bd7d5cc --- /dev/null +++ b/collects/scribblings/reference/syntax-model.scrbl @@ -0,0 +1,423 @@ +#reader(lib "docreader.ss" "scribble") +@require[(lib "struct.ss" "scribble")] +@require-for-syntax[mzscheme] +@require["mz.ss"] + +@;------------------------------------------------------------------------ +@title{Syntax Model} + +The syntax of a Scheme program is defined by + +@itemize{ + + @item{a @deftech{read} phase that processes a character stream into a + Scheme value, especially one composed of pairs and symbols, and + possibly with source-location information to form a + @tech{syntax object}; and} + + @item{an @deftech{expand} phase that processes a syntax object to + produce one that is fully parsed.} + +} + +For details on the @tech{read} phase, see @secref["mz:reader"]. Source +code is normally read in @scheme[read-syntax] mode. Otherwise, it must +be converted to syntax using @scheme[datum->syntax], because the +@tech{expand} phase is defined in terms of @tech{syntax objects}. + +Expansion recursively processes a @tech{syntax object}. Binding +information on a syntax object drives the expansion process, and the +expansion process generates new syntax objects that are like old ones, +but enriched with new binding information. + +@;------------------------------------------------------------------------ +@section{Identifiers and Binding} + +@guideintro["guide:binding"]{binding} + +An @deftech{identifier} is source-program entity. Parsing a Scheme +program reveals that some @tech{identifiers} correspond to +@tech{variables}, some refer to syntactic forms, and some are quoted +to produce a symbol or a syntax object. An identifier @deftech{binds} +another (i.e., it is a @deftech{binding}) when the former is parsed as +a @tech{variable} and the latter is parsed as a reference to the +former. An @tech{identifier} is @deftech{bound} in a sub-expression if +it @tech{binds} any uses of the @tech{identifier} in the +sub-expression that are not otherwise @tech{bound} within the +sub-expression; conversely, a binding for a sub-expression +@deftech{shadows} any @tech{bindings} (i.e., it is +@deftech{shadowing}) in its context, so that uses of an +@tech{identifier} refer to the @tech{shadowing} @tech{binding}. The +@deftech{environment} of a form is the set of bindings whose scope +includes the form. + +For example, as a bit of source, the text + +@schemeblock[(let ([x 5]) x)] + +includes two @tech{identifiers}: @scheme[let] and @scheme[x] (which +appears twice). When this source is parsed in a typical +@tech{environment}, @scheme[x] turns out to represent a +@tech{variable} (unlike @scheme[let]). In particular, the first +@scheme[x] @tech{binds} the second @scheme[x]. + +Throughout the documentation, @tech{identifiers} are typeset to +suggest the way that they are parsed. A black, boldface +@tech{identifier} like @scheme[lambda] indicates as a reference to a +syntactic form. A plain blue @tech{identifier} like @schemeidfont{x} +is a @tech{variable} or a reference to an unspecified @tech{top-level +variable}. A hyperlinked @tech{identifier} @scheme[cons] is a +reference to a specific @tech{top-level variable}. + +@;------------------------------------------------------------------------ +@section{Syntax Objects} + +A @deftech{syntax object} combines a simpler Scheme value, such as a +symbol or pair, which information about bindings and (optionally) +source-location information. In particular, an @tech{identifier} is +represented as a symbol object that combines a symbol and +lexical/source information. + +For example, a @schemeidfont{car} @tech{identifier} might have lexical +information that designates it as the @scheme[car] from the +@schememodname[big] language (i.e., the built-in +@scheme[car]). Similarly, a @schemeidfont{lambda} identifier's lexical +information may indicate that it represents a procedure form. Some +other @tech{identifier}'s lexical information may indicate that it +references a @tech{top-level variable}. + +When a @tech{syntax object} represents a more complex expression than +am identifier or simple constant, its internal pieces can be +extracted. Detailed information about binding is available mostly +indirectly. For example, two identifiers, perhaps extracted from a +larger expression, can be compared to see if they refer to the same +binding (i.e., @scheme[free-identifier=?]). A slightly different test +is whether each identifier would bind the other if one was in a +binding position and the other in an expression position (i.e., +@scheme[bound-identifier=?]). + +For example, the when the program written as + +@schemeblock[(let ([x 5]) (+ x 6))] + +is represented as a syntax object, then two @tech{syntax objects} can +be extracted for the two @scheme[x]s. Both the +@scheme[free-identifier=?] and @scheme[bound-identifier=?] predicates +will indicate that the @scheme[x]s are the same. In contrast, the +@scheme[let] identifier is not @scheme[free-identifier=?] or +@scheme[bound-identifier=?] to either @scheme[x]. + +The lexical information in a syntax object is independent of the other +half, and it can be transferred to a new syntax object, combined with +an arbitrary other Scheme value. Thus, identifier-binding information +in a syntax object is predicated on the symbolic name of the +identifier; the same question with the same lexical information but +different base value can produce a different answer. + +For example, combining the lexical information from @scheme[let] in +the program above to @scheme['x] would not produce an identifier that +is @scheme[free-identifier=?] to either @scheme[x], since it does not +appear in the scope of the @scheme[x] binding. Combining the lexical +context of the @scheme[6] with @scheme['x], in contrast, would produce +an identifier that is @scheme[bound-identifier=?] to both @scheme[x]s. + +The @scheme[quote-syntax] form bridges the evaluation of a program and +the representation of a program. Specifically, @scheme[(quote-syntax +_datum)] produces a syntax object that preserves all of the lexical +information that @scheme[_datum] had when it was parsed as part of a +@scheme[quote-syntax] form. + +@;------------------------------------------------------------------------ +@section[#:tag "mz:expansion"]{Expansion@aux-elem{ (Parsing)}} + +Expansion recursively processes a @tech{syntax object}. Binding +information on a syntax object drives the expansion process, and the +expansion process generates new syntax objects that are like old ones, +but enriched with new binding information. + +@;- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +@subsection[#:tag "mz:fully-expanded"]{Fully Expanded Programs} + +A complete expansion produces a @tech{syntax object} matching the +following grammar: + +@schemegrammar*[ +#:literals (#%expression module #%plain-module-begin begin provide + define-values define-syntaxes define-values-for-syntax + require require-for-syntax require-for-template + #%plain-lambda case-lambda if begin begin0 let-values letrec-values + set! quote-syntax quote with-continuation-mark + #%plain-app #%datum #%top #%variable-reference) +[top-level-form general-top-level-form + (#%expression expr) + (module id name-id + (#%plain-module-begin + module-level-form ...)) + (begin top-level-form ...)] +[module-level-form general-top-level-form + (provide provide-spec ...)] +[general-top-level-form expr + (define-values (id ...) expr) + (define-syntaxes (id ...) expr) + (define-values-for-syntax (id ...) expr) + (require require-spec ...) + (require-for-syntax require-spec ...) + (require-for-template require-spec ...)] +[expr id + (#%plain-lambda formals expr ...+) + (case-lambda (formals expr ...+) ...) + (if expr expr) + (if expr expr expr) + (begin expr ...+) + (begin0 expr expr ...) + (let-values (((id ...) expr) ...) + expr ...+) + (letrec-values (((id ...) expr) ...) + expr ...+) + (set! id expr) + (#, @scheme[quote] datum) + (quote-syntax datum) + (with-continuation-mark expr expr expr) + (#%plain-app expr ...+) + (#%top . id) + (#%variable-reference id) + (#%variable-reference (#%top . id))] +[formals (id ...) + (id ...+ . id) + id]] + +This fully-expanded @tech{syntax object} corresponds to a +@deftech{parse} of the expression (i.e., a @deftech{parsed} +expression), and lexical information on its @tech{identifiers} +indicates the @tech{parse}. + +@;- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +@subsection{Expansion Steps} + +A step in parsing a form represented as a syntax object depends on its +outermost shape: + +@itemize{ + + @item{If it is an @tech{identifier} (i.e., a syntax-object symbol), then a + binding is determined using symbol along with the lexical + information in the identifier. If the identifier has a binding + other than as a top-level variable, it is used to continue. If + the identifier has no binding, a new syntax-object symbol + @scheme['#%top] is created using the lexical context of the + identifier; if this @schemeidfont{#%top} identifier has no + binding (other than as a top-level variable), then parsing + fails with an @scheme[exn:fail:syntax] exception. Otherwise, + the new identifier is combined with the original identifier in + a new syntax-object pair (using the same context as the + original identifier), and the @schemeidfont{#%top} binding is + used to continue.} + + @item{If it is a syntax-object pair whose first element is an + identifier, and if the identifier has a binding other than as a + top-level variable, then the identifier's binding is used to + continue.} + + @item{If it is a syntax-object pair of any other form, then a new + syntax-object symbol @scheme['#%app] is created using the + lexical context of the pair. If the resulting + @schemeidfont{#%app} identifier has no binding, parsing fails + with an @scheme[exn:fail:syntax] exception. Otherwise, the new + identifier is combined with the original pair to form a new + syntax-object pair (using the same context as the original + pair), and the @schemeidfont{#%app} binding is used to + continue.} + + @item{If it is any other syntax object, then a new syntax-object + symbol @scheme['#%datum] is created using the lexical context + of the original syntax object. If the resulting + @schemeidfont{#%datum} identifier has no binding, parsing fails + with an @scheme[exn:fail:syntax] exception. Otherwise, the new + identifier is combined with the original syntax object in a new + syntax-object pair (using the same context as the original + pair), and the @schemeidfont{#%datum} binding is used to + continue.} + +} + +Thus, the possibilities that do not fail lead to an identifier with a +particular binding. This binding refers to one of three things: + +@itemize{ + + @item{A transformer binding, such as introduced by + @scheme[define-syntax] or @scheme[let-syntax]. If the + associated value is to a procedure of one argument, the + procedure is called as a syntax transformer (see + @secref["transformers"]), and parsing starts again with the + syntax-object result. If the transformer binding is to any + other kind of value, parsing fails with an + @scheme[exn:fail:syntax] exception.} + + @item{A variable binding, such as introduced by a module-level + @scheme[define] or by @scheme[let]. In this case, if the form + being parsed is just an identifier, then it is parsed as a + run-time reference to the location of the corresponding + variable. If the form being parsed is a syntax-object list, + then an @scheme[#%app] is added to the front of the + syntax-object list in the same way as when the first item in + the syntax-object list is not an identifier (third case in the + previous enumeration), and parsing continues.} + + @item{Core syntax, which is parsed as described in + @secref["mz:syntax"]. Parsing core syntactic forms typically + involves recursive parsing of sub-forms, and may introduce + bindings that control the parsing of sub-forms.} + +} + +Each expansion step occurs in a particular context, and transformers +and core-syntax parsing can depend on the context. For example, a +@scheme[module] form is allowed only in a top-level context. The +possible contexts are as follows: + +@itemize{ + + @item{@defterm{top level} : outside of any module, definition, or + expression, except that sub-expressions of a top-level + @scheme[begin] form are also expanded as top-level forms.} + + @item{@defterm{module begin} : inside the body of a module, as the + only form within the module.} + + @item{@defterm{module body} : in the body of a module (inside the + moudule-begin layer).} + + @item{@defterm{internal definition} : in a nested context that allows + both definitions and expressions.} + + @item{@defterm{expression} : in a context where only expressions are + allowed.} + +} + +Different core syntax forms parse sub-forms in different contexts. For +example, a @scheme[let] form always parses the right-hand expressions +of a binding in an expression context, but it starts parsing the body +in an internal-definition context. + +@;- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +@subsection[#:tag "mz:intdef-body"]{Internal Definitions} + +An internal-definition context corresponds to a partial expansion +step. A form that supports internal definitions starts by expanding +its first form in an internal-definition context, but only +partially. That is, it recursively expands only until the form becomes +one of the following: + +@itemize{ + + @item{A @scheme[define-values] or @scheme[define-syntaxes] form, for + any form other than the last one: The definition form is not + expanded further. Instead, the next form is expanded partially, + and so on. As soon as an expression form is found, the + accumulated definition forms are converted to a + @scheme[letrec-values] (if no @scheme[define-syntaxes] forms + were found) or @scheme[letrec-syntaxes+values] form, moving the + expression forms to the body to be expanded in expression + context. + + When a @scheme[define-values] form is discovered, the lexical + context of all syntax objects for the body sequence is + immediately enriched with bindings for the + @scheme[define-values] form before expansion continues. When a + @scheme[define-syntaxes] form is discovered, the right-hand + side is executed and a transformer binding is installed for the + body sequence before expansion continues.} + + @item{A primitive expression form other than @scheme[begin]: The + expression is expanded in an expression context, along with all + remaining body forms. If any definitions were found, this + expansion takes place after conversion to a + @scheme[letrec-values] or @scheme[letrec-syntaxes+values] + form. Otherwise, the expressions are expanded immediately.} + + @item{A @scheme[begin] form: The sub-forms of the @scheme[begin] are + spliced into the internal-definition sequence, and partial + expansion continues with the first of the newly-spliced forms + (or the next form, if the @scheme[begin] had no sub-forms).} + +} + +If the last expression form turns out to be a @scheme[define-values] +or @scheme[define-syntaxes] form, expansion fails with a syntax error. + + +@;------------------------------------------------------------------------ +@section{Compilation} + +Before expanded code is evaluated, it is first @deftech{compiled}. A +compiled form has essentially the same information as the +corresponding expanded form, though the internal representation +naturally dispenses with identifiers for syntactic forms and local +bindings. One significant difference is that a compiled form is almost +entirely opaque, so the information that it contains cannot be +accessed directly (which is why some identifiers can be dropped). At +the same time, a compiled form can be marshaled to and from a byte +string, so it is suitable for saving and re-loading code. + +Although individual read, expand, compile, and evaluate operations are +available, the operations are often combined automatically. For +example, the @scheme[eval] procedure takes a syntax object and expands +it, compiles it, and evaluates it. + +@;------------------------------------------------------------------------ +@section{Namespaces} + +A @deftech{namespace} is a top-level mapping from symbols to binding +information. It is the starting point for expanding an expression; a +@tech{syntax object} produced by @scheme[read-syntax] has no initial +lexical context; the @tech{syntax object} can be expanded after +initializing it with the mappings of a particular namespace. A +namespace is also the starting point evaluating expanded code, where +the first step in evaluation is linking the code to specific module +instances and top-level variables. + +For expansion purposes, a namespace maps each symbol to one of three +possible bindings: + +@itemize{ + + @item{a particular module-level binding from a particular module} + + @item{a top-level transformer binding named by the symbol} + + @item{a top-level variable named by the symbol} + +} + +An ``empty'' namespace maps all symbols to top-level variables. +Certain evaluations extend a namespace for future expansions; +importing a module into the top-level adjusts the namespace bindings +for all of the imported named, and evaluating a top-level +@scheme[define] form updates the namespace's mapping to refer to a +variable (in addition to installing a value into the variable). + +For evaluation, each namespace encapsulates a distinct set of +top-level variables, as well as a potentially distinct set of module +instances. After a namespace is created, module instances from +existing namespaces can be attached to the new namespace. In terms of +the evaluation model, top-level variables from different namespaces +essentially correspond to definitions with different prefixes. +Furthermore, the first step in evaluating any compiled expression is +to link its top-level variable and module-level variable references to +specific variables in the namespace. + +At all times during evaluation, some namespace is designated as the +@deftech{current namespace}. The current namespace has no particular +relationship, however, with the namespace that was used to expand the +code that is executing, or with the namespace that was used to link +the compiled form of the currently evaluating code. In particular, +changing the current namespace during evaluation does not change the +variables to which executing expressions refer. The current namespace +only determines the behavior of (essentially reflective) operations to +expand code and to start evaluating expanded/compiled code. + +A namespace is purely a top-level entity, not to be confused with an +environment. In particular, a namespace does not encapsulate the full +environment of an expression inside local-binding forms. diff --git a/collects/scribblings/reference/syntax.scrbl b/collects/scribblings/reference/syntax.scrbl index 65368a38e9..def9593188 100644 --- a/collects/scribblings/reference/syntax.scrbl +++ b/collects/scribblings/reference/syntax.scrbl @@ -527,7 +527,7 @@ in tail position only if no @scheme[body]s are present. ]} @;------------------------------------------------------------------------ -@section{Continuation Marks: @scheme[with-continuation-marks]} +@section{Continuation Marks: @scheme[with-continuation-mark]} @defform[(with-continuation-mark key-expr val-expr result-expr)]{ Evaluates @scheme[key-expr] and @scheme[val-expr] in order to obtain a key and