change semantic of internal definitions
and `letrec-syntaxes+values' --- allowing `let' in place of `letrec', which in turn lets the compiler optimize away location allocation
This commit is contained in:
parent
fb5c62d9d7
commit
b98e1b189a
|
@ -586,8 +586,8 @@ binding} at @tech{phase level} 0).
|
|||
@subsection[#:tag "partial-expansion"]{Partial Expansion}
|
||||
|
||||
In certain contexts, such as an @tech{internal-definition context} or
|
||||
@tech{module context}, forms are partially expanded to determine
|
||||
whether they represent definitions, expressions, or other declaration
|
||||
@tech{module context}, @deftech{partial expansion} is used to determine
|
||||
whether forms represent definitions, expressions, or other declaration
|
||||
forms. Partial expansion works by cutting off the normal recursion
|
||||
expansion when the relevant binding is for a primitive syntactic form.
|
||||
|
||||
|
@ -600,46 +600,35 @@ then expansion stops without adding the identifier.
|
|||
@;- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
@subsection[#:tag "intdef-body"]{Internal Definitions}
|
||||
|
||||
An @tech{internal-definition context} corresponds to a partial expansion step
|
||||
(see @secref["partial-expansion"]). Forms that allow internal definitions document
|
||||
such positions using the @racket[_body] meta-variable. 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:
|
||||
An @tech{internal-definition context} supports local definitions mixed
|
||||
with expressions. Forms that allow internal definitions document such
|
||||
positions using the @racket[_body] meta-variable. Definitions in an
|
||||
internal-definition context are equivalent to local binding via
|
||||
@racket[letrec-syntaxes+values]; macro expansion converts internal
|
||||
definitions to a @racket[letrec-syntaxes+values] form.
|
||||
|
||||
Expansion of an internal-definition context relies on @tech{partial
|
||||
expansion} of each @racket[_body] in an internal-definition sequence.
|
||||
Partial expansion of each @racket[_body] produces a form matching one
|
||||
of the following cases:
|
||||
|
||||
@itemize[
|
||||
|
||||
@item{A @racket[define-values] or @racket[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. The content of a @racket[begin] form is spliced into
|
||||
the body-form sequence. After all forms are partially expanded,
|
||||
the accumulated definition forms are converted to a
|
||||
@racket[letrec-values] (if no @racket[define-syntaxes] forms
|
||||
were found) or @racket[letrec-syntaxes+values] form, moving the
|
||||
expression-form tail to the body to be expanded in expression
|
||||
context. An expression @racket[_expr] that appears before a
|
||||
definition is converted to a @racket[letrec-values] clause
|
||||
@racket[[() (begin _expr (values))]], so that the expression
|
||||
can produce any number of values, and its evaluation order is
|
||||
preserved relative to definitions.
|
||||
@item{A @racket[define-values] form: The lexical context of all
|
||||
syntax objects for the body sequence is immediately enriched
|
||||
with bindings for the @racket[define-values] form. Further
|
||||
expansion of the definition is deferred, and partial expansion
|
||||
continues with the rest of the body.}
|
||||
|
||||
When a @racket[define-values] form is discovered, the lexical
|
||||
context of all syntax objects for the body sequence is
|
||||
immediately enriched with bindings for the
|
||||
@racket[define-values] form before expansion continues. When a
|
||||
@racket[define-syntaxes] form is discovered, the right-hand
|
||||
side is expanded and evaluated (as for a
|
||||
@item{A @racket[define-syntaxes] form: The right-hand side is
|
||||
expanded and evaluated (as for a
|
||||
@racket[letrec-syntaxes+values] form), and a transformer
|
||||
binding is installed for the body sequence before expansion
|
||||
continues.}
|
||||
binding is installed for the body sequence before partial
|
||||
expansion continues with the est of the body.}
|
||||
|
||||
@item{A primitive expression form other than @racket[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
|
||||
@racket[letrec-values] or @racket[letrec-syntaxes+values]
|
||||
form. Otherwise, the expressions are expanded immediately.}
|
||||
@item{A primitive expression form other than @racket[begin]: Further
|
||||
expansion of the expression is deferred, and partial expansion
|
||||
continues with the rest of the body.}
|
||||
|
||||
@item{A @racket[begin] form: The sub-forms of the @racket[begin] are
|
||||
spliced into the internal-definition sequence, and partial
|
||||
|
@ -648,8 +637,15 @@ recursively expands only until the form becomes one of the following:
|
|||
|
||||
]
|
||||
|
||||
If the last expression form turns out to be a @racket[define-values]
|
||||
or @racket[define-syntaxes] form, expansion fails with a syntax error.
|
||||
After all body forms are partially expanded, if no definitions were
|
||||
encountered, then the expressions are collected into a @racket[begin]
|
||||
form as he internal-definition context's expansion. Otherwise, at
|
||||
least one expression must appear after the last definition, and any
|
||||
@racket[_expr] that appears between definitions is converted to
|
||||
@racket[(define-values () (begin _expr (values)))]; the definitions
|
||||
are then converted to bindings in a @racket[letrec-syntaxes+values]
|
||||
form, and all expressions after the last definition become the body of
|
||||
the @racket[letrec-syntaxes+values] form.
|
||||
|
||||
@;- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
@subsection[#:tag "mod-parse"]{Module Phases and Visits}
|
||||
|
|
|
@ -1296,7 +1296,7 @@ expression.
|
|||
|
||||
Refers to a module-level or local binding, when @racket[id] is
|
||||
not bound as a transformer (see @secref["expansion"]). At run-time,
|
||||
the reference evaluates to the value in the location associated with
|
||||
the reference evaluates to the value in the @tech{location} associated with
|
||||
the binding.
|
||||
|
||||
When the expander encounters an @racket[id] that is not bound by a
|
||||
|
@ -1334,7 +1334,7 @@ introduces @racketidfont{#%top} identifiers.
|
|||
(#%variable-reference)]]{
|
||||
|
||||
Produces an opaque @deftech{variable reference} value representing the
|
||||
location of @racket[id], which must be bound as a @tech{top-level
|
||||
@tech{location} of @racket[id], which must be bound as a @tech{top-level
|
||||
variable} or @tech{module-level variable}. If no @racket[id] is
|
||||
supplied, the resulting value refers to an ``anonymous'' variable
|
||||
defined within the enclosing context (i.e., within the enclosing
|
||||
|
@ -1593,7 +1593,7 @@ Like @racket[lambda], but without support for keyword or optional arguments.
|
|||
(let proc-id ([id init-expr] ...) body ...+)]]{
|
||||
|
||||
The first form evaluates the @racket[val-expr]s left-to-right, creates
|
||||
a new location for each @racket[id], and places the values into the
|
||||
a new @tech{location} for each @racket[id], and places the values into the
|
||||
locations. It then evaluates the @racket[body]s, in which the
|
||||
@racket[id]s are bound. The last @racket[body] expression is in
|
||||
tail position with respect to the @racket[let] form. The @racket[id]s
|
||||
|
@ -1622,7 +1622,7 @@ within the @racket[body]s to the procedure itself.}
|
|||
@defform[(let* ([id val-expr] ...) body ...+)]{
|
||||
|
||||
Similar to @racket[let], but evaluates the @racket[val-expr]s one by
|
||||
one, creating a location for each @racket[id] as soon as the value is
|
||||
one, creating a @tech{location} for each @racket[id] as soon as the value is
|
||||
available. The @racket[id]s are bound in the remaining @racket[val-expr]s
|
||||
as well as the @racket[body]s, and the @racket[id]s need not be
|
||||
distinct; later bindings shadow earlier bindings.
|
||||
|
@ -1635,7 +1635,7 @@ distinct; later bindings shadow earlier bindings.
|
|||
|
||||
@defform[(letrec ([id val-expr] ...) body ...+)]{
|
||||
|
||||
Similar to @racket[let], but the locations for all @racket[id]s are
|
||||
Similar to @racket[let], but the @tech{locations} for all @racket[id]s are
|
||||
created first and filled with @|undefined-const|, and all
|
||||
@racket[id]s are bound in all @racket[val-expr]s as well as the
|
||||
@racket[body]s. The @racket[id]s must be distinct according to
|
||||
|
@ -1654,7 +1654,7 @@ created first and filled with @|undefined-const|, and all
|
|||
@defform[(let-values ([(id ...) val-expr] ...) body ...+)]{ Like
|
||||
@racket[let], except that each @racket[val-expr] must produce as many
|
||||
values as corresponding @racket[id]s, otherwise the
|
||||
@exnraise[exn:fail:contract]. A separate location is created for each
|
||||
@exnraise[exn:fail:contract]. A separate @tech{location} is created for each
|
||||
@racket[id], all of which are bound in the @racket[body]s.
|
||||
|
||||
@mz-examples[
|
||||
|
@ -1664,7 +1664,7 @@ values as corresponding @racket[id]s, otherwise the
|
|||
|
||||
@defform[(let*-values ([(id ...) val-expr] ...) body ...+)]{ Like
|
||||
@racket[let*], except that each @racket[val-expr] must produce as many
|
||||
values as corresponding @racket[id]s. A separate location is created
|
||||
values as corresponding @racket[id]s. A separate @tech{location} is created
|
||||
for each @racket[id], all of which are bound in the later
|
||||
@racket[val-expr]s and in the @racket[body]s.
|
||||
|
||||
|
@ -1676,7 +1676,7 @@ for each @racket[id], all of which are bound in the later
|
|||
|
||||
@defform[(letrec-values ([(id ...) val-expr] ...) body ...+)]{ Like
|
||||
@racket[letrec], except that each @racket[val-expr] must produce as
|
||||
many values as corresponding @racket[id]s. A separate location is
|
||||
many values as corresponding @racket[id]s. A separate @tech{location} is
|
||||
created for each @racket[id], all of which are initialized to
|
||||
@|undefined-const| and bound in all @racket[val-expr]s
|
||||
and in the @racket[body]s.
|
||||
|
@ -1738,18 +1738,40 @@ within all @racket[trans-expr]s.}
|
|||
([(val-id ...) val-expr] ...)
|
||||
body ...+)]{
|
||||
|
||||
Combines @racket[letrec-syntaxes] with @racket[letrec-values]: each
|
||||
@racket[trans-id] and @racket[val-id] is bound in all
|
||||
@racket[trans-expr]s and @racket[val-expr]s.
|
||||
Combines @racket[letrec-syntaxes] with a variant of
|
||||
@racket[letrec-values]: each @racket[trans-id] and @racket[val-id] is
|
||||
bound in all @racket[trans-expr]s and @racket[val-expr]s.
|
||||
|
||||
The @racket[letrec-syntaxes+values] form is the core form for local
|
||||
compile-time bindings, since forms like @racket[letrec-syntax] and
|
||||
internal @racket[define-syntax] expand to it. In a fully expanded
|
||||
@tech{internal-definition contexts} expand to it. In a fully expanded
|
||||
expression (see @secref["fully-expanded"]), the @racket[trans-id]
|
||||
bindings are discarded and the form reduces to @racket[letrec], but
|
||||
bindings are discarded and the form reduces to a combination of
|
||||
@racket[letrec-values] or @racket[let-values], but
|
||||
@racket[letrec-syntaxes+values] can appear in the result of
|
||||
@racket[local-expand] with an empty stop list.
|
||||
|
||||
For variables bound by @racket[letrec-syntaxes+values], the
|
||||
@tech{location}-creation rules differ slightly from
|
||||
@racket[letrec-values]. The @racket[[(val-id ...) val-expr]] binding
|
||||
clauses are partitioned into minimal sets of clauses that satisfy the
|
||||
following rule: if a clause has a @racket[val-id] binding that is
|
||||
referenced (in a full expansion) by the @racket[val-expr] of an
|
||||
earlier clause, the two clauses and all in between are in the same
|
||||
set. If a set consists of a single clause whose @racket[val-expr] does
|
||||
not refer to any of the clause's @racket[val-id]s, then
|
||||
@tech{locations} for the @racket[val-id]s are created @emph{after} the
|
||||
@racket[val-expr] is evaluated. Otherwise, @tech{locations} for all
|
||||
@racket[val-id]s in a set are created just before the first
|
||||
@racket[val-expr] in the set is evaluated.
|
||||
|
||||
The end result of the @tech{location}-creation rules is that scoping
|
||||
and evaluation order are the same as for @racket[letrec-values], but
|
||||
the compiler has more freedom to optimize away @tech{location}
|
||||
creation. The rules also correspond to a nesting of
|
||||
@racket[let-values] and @racket[letrec-values], which is how
|
||||
@racket[letrec-syntaxes+values] for a fully-expanded expression.
|
||||
|
||||
See also @racket[local], which supports local bindings with
|
||||
@racket[define], @racket[define-syntax], and more.}
|
||||
|
||||
|
@ -1760,9 +1782,9 @@ See also @racket[local], which supports local bindings with
|
|||
|
||||
@defform[(local [definition ...] body ...+)]{
|
||||
|
||||
Like @racket[letrec], except that the bindings are expressed in the
|
||||
same way as in the top-level or in a module body: using
|
||||
@racket[define], @racket[define-values], @racket[define-syntax],
|
||||
Like @racket[letrec-syntaxes+values], except that the bindings are
|
||||
expressed in the same way as in the top-level or in a module body:
|
||||
using @racket[define], @racket[define-values], @racket[define-syntax],
|
||||
@racket[struct], etc. Definitions are distinguished from
|
||||
non-definitions by partially expanding @racket[definition] forms (see
|
||||
@secref["partial-expansion"]). As in the top-level or in a module
|
||||
|
@ -2508,7 +2530,10 @@ provides a hook to control interactive evaluation through
|
|||
|
||||
Like @racket[(let () defn-or-expr ...)] for an
|
||||
@tech{internal-definition context} sequence, except that an expression
|
||||
is not allowed to precede a definition.
|
||||
is not allowed to precede a definition, and all definitions are
|
||||
treated as referring to all other definitions (i.e., @tech{locations}
|
||||
for variables are all allocated first, like @racket[letrec] and
|
||||
unlike @racket[letrec-syntaxes+values]).
|
||||
|
||||
The @racket[#%stratified-body] form is useful for implementing
|
||||
syntactic forms or languages that supply a more limited kind of
|
||||
|
|
|
@ -1112,6 +1112,41 @@
|
|||
[y (lambda () (x))])
|
||||
(list (x) (y) h)))))
|
||||
|
||||
(test-comp '(lambda (f a)
|
||||
(define x (f y))
|
||||
(define y (m))
|
||||
(define-syntax-rule (m) 10)
|
||||
(f "hi!\n")
|
||||
(define z (f (lambda () (+ x y a))))
|
||||
(define q (p))
|
||||
(define p (q))
|
||||
(list x y z))
|
||||
'(lambda (f a)
|
||||
(letrec ([x (f y)]
|
||||
[y 10])
|
||||
(f "hi!\n")
|
||||
(let ([z (f (lambda () (+ x y a)))])
|
||||
(letrec ([q (p)]
|
||||
[p (q)])
|
||||
(list x y z))))))
|
||||
|
||||
(test-comp '(lambda (f a)
|
||||
(#%stratified-body
|
||||
(define x (f y))
|
||||
(define y (m))
|
||||
(define-syntax-rule (m) 10)
|
||||
(define z (f (lambda () (+ x y a))))
|
||||
(define q (p))
|
||||
(define p (q))
|
||||
(list x y z)))
|
||||
'(lambda (f a)
|
||||
(letrec-values ([(x) (f y)]
|
||||
[(y) 10]
|
||||
[(z) (f (lambda () (+ x y a)))]
|
||||
[(q) (p)]
|
||||
[(p) (q)])
|
||||
(list x y z))))
|
||||
|
||||
(test-comp '(procedure? add1)
|
||||
#t)
|
||||
(test-comp '(procedure? (lambda (x) x))
|
||||
|
|
|
@ -689,8 +689,9 @@
|
|||
(test #t has-stx-property? (expand #'(let () (define-struct x (a)) 12)) #f 'define-struct 'origin)
|
||||
|
||||
;; Disappearing syntax decls:
|
||||
(test #t has-stx-property? (expand #'(let () (define-syntax x 1) (define y 12) 10)) 'letrec-values 'x 'disappeared-binding)
|
||||
(test #t has-stx-property? (expand #'(let () (define-struct s (x)) 10)) 'letrec-values 's 'disappeared-binding)
|
||||
(test #t has-stx-property? (expand #'(let () (define-syntax x 1) (define y 12) 10)) 'let-values 'x 'disappeared-binding)
|
||||
(test #t has-stx-property? (expand #'(let () (define-syntax x 1) (define y y) 10)) 'letrec-values 'x 'disappeared-binding)
|
||||
(test #t has-stx-property? (expand #'(let () (define-struct s (x)) 10)) 'let-values 's 'disappeared-binding)
|
||||
(test #t has-stx-property? (expand #'(let () (define-syntax x 1) 10)) 'let-values 'x 'disappeared-binding)
|
||||
(test #f has-stx-property? (expand #'(fluid-let-syntax ([x 1]) 10)) 'let-values 'x 'disappeared-binding)
|
||||
|
||||
|
|
|
@ -1388,6 +1388,54 @@
|
|||
|
||||
(test #t exn? (caar (map try (list pipeline2)))))
|
||||
|
||||
;; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||
;; Semantics of internal definitions != R5RS
|
||||
|
||||
(test 0 'racket-int-def (call-with-continuation-prompt
|
||||
(lambda ()
|
||||
(let ([v 0]
|
||||
[k #f]
|
||||
[q void])
|
||||
(define f (let/cc _k (set! k _k)))
|
||||
(define g v) ; fresh location each evaluation
|
||||
(if f
|
||||
(begin
|
||||
(set! q (lambda () g))
|
||||
(set! v 1)
|
||||
(k #f))
|
||||
(q))))))
|
||||
(test 1 'racket-int-def (call-with-continuation-prompt
|
||||
(lambda ()
|
||||
(let ([v 0]
|
||||
[k #f]
|
||||
[q void])
|
||||
(#%stratified-body
|
||||
(define f (let/cc _k (set! k _k)))
|
||||
(define g v) ; same location both evaluations
|
||||
(if f
|
||||
(begin
|
||||
(set! q (lambda () g))
|
||||
(set! v 1)
|
||||
(k #f))
|
||||
(q)))))))
|
||||
|
||||
;; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||
;; check that the compiler is not too agressive with `letrec' -> `let*'
|
||||
|
||||
(test "#<undefined>\nready\n"
|
||||
get-output-string
|
||||
(let ([p (open-output-string)])
|
||||
(parameterize ([current-output-port p])
|
||||
(let ([restart void])
|
||||
(letrec ([dummy1 (let/cc k (set! restart k))]
|
||||
[dummy2 (displayln maybe-ready)]
|
||||
[maybe-ready 'ready])
|
||||
(let ([rs restart])
|
||||
(set! restart void)
|
||||
(rs #f)))))
|
||||
p))
|
||||
|
||||
|
||||
;; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||
|
||||
(report-errs)
|
||||
|
|
|
@ -1,3 +1,7 @@
|
|||
Version 5.1.2.2
|
||||
Changed the location-creation semantics of internal definitions
|
||||
and `letrec-syntaxes+values'
|
||||
|
||||
Version 5.1.2, July 2011
|
||||
Replaced syntax certificates with syntax taints:
|
||||
Added syntax-tainted?, syntax-arm, syntax-disarm, syntax-rearm,
|
||||
|
|
|
@ -1676,6 +1676,365 @@ case_lambda_expand(Scheme_Object *orig_form, Scheme_Comp_Env *env, Scheme_Expand
|
|||
/* let, let-values, letrec, etc. */
|
||||
/**********************************************************************/
|
||||
|
||||
static Scheme_Let_Header *make_header(Scheme_Object *first, int num_bindings, int num_clauses,
|
||||
int flags)
|
||||
{
|
||||
Scheme_Let_Header *head;
|
||||
|
||||
head = MALLOC_ONE_TAGGED(Scheme_Let_Header);
|
||||
head->iso.so.type = scheme_compiled_let_void_type;
|
||||
head->body = first;
|
||||
head->count = num_bindings;
|
||||
head->num_clauses = num_clauses;
|
||||
SCHEME_LET_FLAGS(head) = flags;
|
||||
|
||||
return head;
|
||||
}
|
||||
|
||||
static Scheme_Object *shift_compiled_expression(Scheme_Object *v, int delta, int skip);
|
||||
|
||||
static Scheme_Object *shift_compiled_expression_k(void)
|
||||
{
|
||||
Scheme_Thread *p = scheme_current_thread;
|
||||
Scheme_Object *v = (Scheme_Object *)p->ku.k.p1;
|
||||
|
||||
p->ku.k.p1 = NULL;
|
||||
|
||||
return (void *)shift_compiled_expression(v, p->ku.k.i1, p->ku.k.i2);
|
||||
}
|
||||
|
||||
static Scheme_Object *shift_compiled_expression(Scheme_Object *v, int delta, int skip)
|
||||
{
|
||||
if (!delta || (SCHEME_TYPE(v) > _scheme_compiled_values_types_))
|
||||
return v;
|
||||
|
||||
if (delta < 0) scheme_signal_error("internal error: bad shift delta");
|
||||
|
||||
#ifdef DO_STACK_CHECK
|
||||
{
|
||||
# include "mzstkchk.h"
|
||||
{
|
||||
Scheme_Thread *p = scheme_current_thread;
|
||||
|
||||
p->ku.k.p1 = (void *)v;
|
||||
p->ku.k.i1 = delta;
|
||||
p->ku.k.i2 = skip;
|
||||
|
||||
return scheme_handle_stack_overflow(shift_compiled_expression_k);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
/* Perform simple shifts directly. We want to avoid adding
|
||||
extra `let' ayers if possible, since it might interefere
|
||||
with optimizations. */
|
||||
|
||||
switch (SCHEME_TYPE(v)) {
|
||||
case scheme_compiled_toplevel_type:
|
||||
case scheme_compiled_quote_syntax_type:
|
||||
case scheme_varref_form_type:
|
||||
return v;
|
||||
case scheme_local_type:
|
||||
{
|
||||
int pos = SCHEME_LOCAL_POS(v);
|
||||
if (pos < skip)
|
||||
return v;
|
||||
else
|
||||
return scheme_make_local(scheme_local_type, pos - delta, 0);
|
||||
}
|
||||
case scheme_application_type:
|
||||
{
|
||||
Scheme_App_Rec *app = (Scheme_App_Rec *)v;
|
||||
int i;
|
||||
|
||||
for (i = app->num_args + 1; i--; ) {
|
||||
v = shift_compiled_expression(app->args[i], delta, skip);
|
||||
app->args[i] = v;
|
||||
}
|
||||
|
||||
return (Scheme_Object *)app;
|
||||
}
|
||||
case scheme_application2_type:
|
||||
{
|
||||
Scheme_App2_Rec *app = (Scheme_App2_Rec *)v;
|
||||
|
||||
v = shift_compiled_expression(app->rator, delta, skip);
|
||||
app->rator = v;
|
||||
v = shift_compiled_expression(app->rand, delta, skip);
|
||||
app->rand = v;
|
||||
|
||||
return (Scheme_Object *)app;
|
||||
}
|
||||
case scheme_application3_type:
|
||||
{
|
||||
Scheme_App3_Rec *app = (Scheme_App3_Rec *)v;
|
||||
|
||||
v = shift_compiled_expression(app->rator, delta, skip);
|
||||
app->rator = v;
|
||||
v = shift_compiled_expression(app->rand1, delta, skip);
|
||||
app->rand1 = v;
|
||||
v = shift_compiled_expression(app->rand2, delta, skip);
|
||||
app->rand2 = v;
|
||||
|
||||
return (Scheme_Object *)app;
|
||||
}
|
||||
case scheme_branch_type:
|
||||
{
|
||||
Scheme_Branch_Rec *b = (Scheme_Branch_Rec *)v;
|
||||
|
||||
v = shift_compiled_expression(b->test, delta, skip);
|
||||
b->test = v;
|
||||
v = shift_compiled_expression(b->tbranch, delta, skip);
|
||||
b->tbranch = v;
|
||||
v = shift_compiled_expression(b->fbranch, delta, skip);
|
||||
b->fbranch = v;
|
||||
|
||||
return (Scheme_Object *)b;
|
||||
}
|
||||
case scheme_with_cont_mark_type:
|
||||
{
|
||||
Scheme_With_Continuation_Mark *wcm = (Scheme_With_Continuation_Mark *)v;
|
||||
|
||||
v = shift_compiled_expression(wcm->key, delta, skip);
|
||||
wcm->key = v;
|
||||
v = shift_compiled_expression(wcm->val, delta, skip);
|
||||
wcm->val = v;
|
||||
v = shift_compiled_expression(wcm->body, delta, skip);
|
||||
wcm->body = v;
|
||||
|
||||
return (Scheme_Object *)wcm;
|
||||
}
|
||||
case scheme_sequence_type:
|
||||
case scheme_begin0_sequence_type:
|
||||
{
|
||||
Scheme_Sequence *s = (Scheme_Sequence *)v;
|
||||
int i;
|
||||
|
||||
for (i = s->count; i--; ) {
|
||||
v = shift_compiled_expression(s->array[i], delta, skip);
|
||||
s->array[i] = v;
|
||||
}
|
||||
|
||||
return (Scheme_Object *)s;
|
||||
}
|
||||
case scheme_apply_values_type:
|
||||
{
|
||||
Scheme_Object *v2;
|
||||
|
||||
v2 = shift_compiled_expression(SCHEME_PTR1_VAL(v), delta, skip);
|
||||
SCHEME_PTR1_VAL(v) = v2;
|
||||
v2 = shift_compiled_expression(SCHEME_PTR2_VAL(v), delta, skip);
|
||||
SCHEME_PTR2_VAL(v) = v2;
|
||||
|
||||
return v;
|
||||
}
|
||||
case scheme_set_bang_type:
|
||||
{
|
||||
Scheme_Set_Bang *sb = (Scheme_Set_Bang *)v;
|
||||
|
||||
v = shift_compiled_expression(sb->var, delta, skip);
|
||||
sb->var = v;
|
||||
v = shift_compiled_expression(sb->val, delta, skip);
|
||||
sb->val = v;
|
||||
|
||||
return (Scheme_Object *)sb;
|
||||
}
|
||||
case scheme_compiled_unclosed_procedure_type:
|
||||
{
|
||||
Scheme_Closure_Data *data = (Scheme_Closure_Data *)v;
|
||||
|
||||
v = shift_compiled_expression(data->code, delta, skip + data->num_params);
|
||||
data->code = v;
|
||||
|
||||
return (Scheme_Object *)data;
|
||||
}
|
||||
case scheme_case_lambda_sequence_type:
|
||||
{
|
||||
Scheme_Case_Lambda *cl = (Scheme_Case_Lambda *)v;
|
||||
int i;
|
||||
|
||||
for (i = cl->count; i--; ) {
|
||||
v = shift_compiled_expression(cl->array[i], delta, skip);
|
||||
cl->array[i] = v;
|
||||
}
|
||||
|
||||
return (Scheme_Object *)cl;
|
||||
}
|
||||
case scheme_compiled_let_void_type:
|
||||
{
|
||||
Scheme_Let_Header *lh = (Scheme_Let_Header *)v;
|
||||
Scheme_Compiled_Let_Value *clv;
|
||||
int post_bind = !(SCHEME_LET_FLAGS(lh) & (SCHEME_LET_RECURSIVE | SCHEME_LET_STAR));
|
||||
int i;
|
||||
|
||||
if (!post_bind) skip += lh->count;
|
||||
|
||||
clv = (Scheme_Compiled_Let_Value *)lh->body;
|
||||
i = lh->num_clauses;
|
||||
while (1) {
|
||||
v = shift_compiled_expression(clv->value, delta, skip);
|
||||
clv->value = v;
|
||||
if (--i)
|
||||
clv = (Scheme_Compiled_Let_Value *)clv->body;
|
||||
else
|
||||
break;
|
||||
}
|
||||
|
||||
if (post_bind) skip += lh->count;
|
||||
|
||||
if (!lh->num_clauses) {
|
||||
v = shift_compiled_expression(lh->body, delta, skip);
|
||||
lh->body = v;
|
||||
} else {
|
||||
v = shift_compiled_expression(clv->body, delta, skip);
|
||||
clv->body = v;
|
||||
}
|
||||
|
||||
return (Scheme_Object *)lh;
|
||||
}
|
||||
default:
|
||||
scheme_signal_error("internal error: compile-time shift failed: %d", SCHEME_TYPE(v));
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
static Scheme_Object *force_traditional_letrec(Scheme_Object *result, Scheme_Comp_Env *env)
|
||||
{
|
||||
/* Force `letrec'-style binding by adding a forward
|
||||
reference to the last binding as a first binding:
|
||||
(letrec-values+syntaxes ([() (if #f <last-id> (#%app values))] ....) ....).
|
||||
To avoid affecting performance, this hack is reverted in
|
||||
the `letrec' compiler and expander. */
|
||||
Scheme_Object *sbh, *vbh, *vb, *v, *last_name = NULL, *values, *app;
|
||||
|
||||
sbh = SCHEME_STX_CDR(result);
|
||||
vbh = SCHEME_STX_CDR(sbh);
|
||||
vb = SCHEME_STX_CAR(vbh);
|
||||
|
||||
while (!SCHEME_STX_NULLP(vb)) {
|
||||
v = SCHEME_STX_CAR(vb);
|
||||
v = SCHEME_STX_CAR(v);
|
||||
if (!SCHEME_STX_NULLP(v)) {
|
||||
last_name = SCHEME_STX_CAR(v);
|
||||
}
|
||||
vb = SCHEME_STX_CDR(vb);
|
||||
}
|
||||
|
||||
if (last_name) {
|
||||
vb = SCHEME_STX_CAR(vbh);
|
||||
v = scheme_datum_to_syntax(scheme_intern_symbol("if"), scheme_false,
|
||||
scheme_sys_wraps(env), 0, 0);
|
||||
app = scheme_datum_to_syntax(app_symbol, scheme_false,
|
||||
scheme_sys_wraps(env), 0, 0);
|
||||
values = scheme_datum_to_syntax(values_symbol, scheme_false,
|
||||
scheme_sys_wraps(env), 0, 0);
|
||||
vb = icons(icons(scheme_null,
|
||||
icons(icons(v,
|
||||
icons(scheme_false,
|
||||
icons(last_name,
|
||||
icons(icons(app, icons(values, scheme_null)),
|
||||
scheme_null)))),
|
||||
scheme_null)),
|
||||
vb);
|
||||
vbh = SCHEME_STX_CDR(vbh);
|
||||
sbh = SCHEME_STX_CAR(sbh);
|
||||
v = SCHEME_STX_CAR(result);
|
||||
v = icons(v, icons(sbh, icons(vb, vbh)));
|
||||
result = scheme_datum_to_syntax(v, result, result, 0, 2);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
static Scheme_Object *detect_traditional_letrec(Scheme_Object *form, Scheme_Comp_Env *env)
|
||||
/* See force_traditional_letrec() */
|
||||
{
|
||||
Scheme_Object *v, *v2, *v3, *id;
|
||||
|
||||
v = SCHEME_STX_CDR(form);
|
||||
v = SCHEME_STX_CAR(v);
|
||||
if (SCHEME_STX_NULLP(v)) return form;
|
||||
|
||||
v = SCHEME_STX_CAR(v);
|
||||
/* is v `[() ...]' ? */
|
||||
v2 = SCHEME_STX_CAR(v);
|
||||
if (!SCHEME_STX_NULLP(v2)) return form;
|
||||
|
||||
v2 = SCHEME_STX_CDR(v);
|
||||
v2 = SCHEME_STX_CAR(v2);
|
||||
|
||||
/* is v2 `(if #f ... (values))' ? */
|
||||
if (!SCHEME_STX_PAIRP(v2)) return form;
|
||||
v = SCHEME_STX_CDR(v2);
|
||||
if (!SCHEME_STX_PAIRP(v)) return form;
|
||||
v = SCHEME_STX_CAR(v);
|
||||
v = SCHEME_STX_VAL(v);
|
||||
|
||||
if (!SCHEME_FALSEP(v)) {
|
||||
/* try '#f: */
|
||||
if (!SCHEME_PAIRP(v)) return form;
|
||||
v3 = SCHEME_CDR(v);
|
||||
if (!SCHEME_STX_PAIRP(v3)) return form;
|
||||
v3 = SCHEME_STX_CAR(v3);
|
||||
v3 = SCHEME_STX_VAL(v3);
|
||||
if (!SCHEME_FALSEP(v3)) return form;
|
||||
|
||||
v3 = SCHEME_CDR(v);
|
||||
v3 = SCHEME_STX_CDR(v3);
|
||||
if (!SCHEME_STX_NULLP(v3)) return form;
|
||||
}
|
||||
|
||||
/* found #f; look for `if' and `(#%app values)': */
|
||||
v = SCHEME_STX_CAR(v2);
|
||||
if (!SCHEME_STX_SYMBOLP(v)) return form;
|
||||
|
||||
id = scheme_datum_to_syntax(scheme_intern_symbol("if"), scheme_false,
|
||||
scheme_sys_wraps(env), 0, 0);
|
||||
if (!scheme_stx_module_eq(v, id, env->genv->phase)) return form;
|
||||
|
||||
/* found `if'; look for `(#%app values)' */
|
||||
v = SCHEME_STX_CDR(v2);
|
||||
v = SCHEME_STX_CDR(v);
|
||||
if (!SCHEME_STX_PAIRP(v)) return form;
|
||||
v = SCHEME_STX_CDR(v);
|
||||
if (!SCHEME_STX_PAIRP(v)) return form;
|
||||
v2 = SCHEME_STX_CDR(v);
|
||||
if (!SCHEME_STX_NULLP(v2)) return form;
|
||||
|
||||
v = SCHEME_STX_CAR(v);
|
||||
if (!SCHEME_STX_PAIRP(v)) return form;
|
||||
v2 = SCHEME_STX_CAR(v);
|
||||
if (!SCHEME_STX_SYMBOLP(v2)) return form;
|
||||
id = scheme_datum_to_syntax(app_symbol, scheme_false,
|
||||
scheme_sys_wraps(env), 0, 0);
|
||||
if (!scheme_stx_module_eq(v2, id, env->genv->phase)) return form;
|
||||
|
||||
v = SCHEME_STX_CDR(v);
|
||||
if (!SCHEME_STX_PAIRP(v)) return form;
|
||||
v2 = SCHEME_STX_CDR(v);
|
||||
if (!SCHEME_STX_NULLP(v2)) return form;
|
||||
|
||||
v = SCHEME_STX_CAR(v);
|
||||
if (!SCHEME_STX_SYMBOLP(v)) return form;
|
||||
id = scheme_datum_to_syntax(values_symbol, scheme_false,
|
||||
scheme_sys_wraps(env), 0, 0);
|
||||
if (!scheme_stx_module_eq(v, id, env->genv->phase)) return form;
|
||||
|
||||
/* pattern matched; drop the first clause */
|
||||
v = SCHEME_STX_CDR(form);
|
||||
v2 = SCHEME_STX_CAR(v);
|
||||
v2 = SCHEME_STX_CDR(v2);
|
||||
|
||||
v = SCHEME_STX_CDR(v);
|
||||
v = scheme_datum_to_syntax(v, scheme_false, scheme_false, 0, 0);
|
||||
v2 = icons(v2, v);
|
||||
|
||||
v = SCHEME_STX_CAR(form);
|
||||
v2 = icons(v, v2);
|
||||
|
||||
return scheme_datum_to_syntax(v2, form, form, 0, 2);
|
||||
}
|
||||
|
||||
static Scheme_Object *
|
||||
gen_let_syntax (Scheme_Object *form, Scheme_Comp_Env *origenv, char *formname,
|
||||
int star, int recursive, int multi, Scheme_Compile_Info *rec, int drec,
|
||||
|
@ -1691,9 +2050,18 @@ gen_let_syntax (Scheme_Object *form, Scheme_Comp_Env *origenv, char *formname,
|
|||
int rec_env_already = rec[drec].env_already;
|
||||
int rev_bind_order = recursive;
|
||||
int post_bind = !recursive && !star;
|
||||
Scheme_Let_Header *head;
|
||||
|
||||
form = scheme_stx_taint_disarm(form, NULL);
|
||||
|
||||
if (rec_env_already == 2) {
|
||||
l = detect_traditional_letrec(form, origenv);
|
||||
if (!SAME_OBJ(l, form)) {
|
||||
rec_env_already = 1;
|
||||
form = l;
|
||||
}
|
||||
}
|
||||
|
||||
i = scheme_stx_proper_list_length(form);
|
||||
if (i < 3)
|
||||
scheme_wrong_syntax(NULL, NULL, form, (!i ? "bad syntax (empty body)" : NULL));
|
||||
|
@ -1896,7 +2264,15 @@ gen_let_syntax (Scheme_Object *form, Scheme_Comp_Env *origenv, char *formname,
|
|||
}
|
||||
}
|
||||
|
||||
head = make_header(first, num_bindings, num_clauses,
|
||||
((recursive ? SCHEME_LET_RECURSIVE : 0)
|
||||
| (star ? SCHEME_LET_STAR : 0)));
|
||||
|
||||
if (recursive) {
|
||||
Scheme_Let_Header *current_head = head;
|
||||
int prev_might_invoke = 0;
|
||||
int group_clauses = 0, group_count = 0;
|
||||
|
||||
lv = (Scheme_Compiled_Let_Value *)first;
|
||||
for (i = 0; i < num_clauses; i++, lv = (Scheme_Compiled_Let_Value *)lv->body) {
|
||||
Scheme_Object *ce, *rhs;
|
||||
|
@ -1906,14 +2282,55 @@ gen_let_syntax (Scheme_Object *form, Scheme_Comp_Env *origenv, char *formname,
|
|||
lv->value = ce;
|
||||
|
||||
/* Record the fact that this binding doesn't use any or later
|
||||
bindings in the same set. The `let' optimizer and resolver
|
||||
bindings in the same set. In internal-definition mode,
|
||||
break bindings into smaller sets based on this
|
||||
information. */
|
||||
if (!scheme_env_check_reset_any_use(env)
|
||||
&& !scheme_might_invoke_call_cc(ce))
|
||||
information; otherwise, the `let' optimizer and resolver
|
||||
may do so, but we have to be more conservative as reflected
|
||||
by scheme_might_invoke_call_cc(). */
|
||||
if ((rec_env_already == 2) /* int def: semantics is `let' */
|
||||
|| (!prev_might_invoke
|
||||
&& !scheme_might_invoke_call_cc(ce))) {
|
||||
if (!scheme_env_check_reset_any_use(env))
|
||||
SCHEME_CLV_FLAGS(lv) |= SCHEME_CLV_NO_GROUP_USES;
|
||||
if (!scheme_env_min_use_below(env, lv->position))
|
||||
if ((rec_env_already == 2)
|
||||
&& !group_clauses
|
||||
&& !scheme_env_min_use_below(env, lv->position + lv->count)) {
|
||||
/* A clause that should be in its own `let' */
|
||||
Scheme_Let_Header *next_head;
|
||||
next_head = make_header(lv->body,
|
||||
current_head->count - lv->count,
|
||||
current_head->num_clauses - 1,
|
||||
SCHEME_LET_RECURSIVE);
|
||||
current_head->num_clauses = 1;
|
||||
current_head->count = lv->count;
|
||||
current_head->body = (Scheme_Object *)next_head;
|
||||
SCHEME_LET_FLAGS(current_head) -= SCHEME_LET_RECURSIVE;
|
||||
current_head = next_head;
|
||||
} else if (!scheme_env_min_use_below(env, lv->position)) {
|
||||
/* End a recursive `letrec' group */
|
||||
SCHEME_CLV_FLAGS(lv) |= SCHEME_CLV_NO_GROUP_LATER_USES;
|
||||
|
||||
if (rec_env_already == 2) {
|
||||
Scheme_Let_Header *next_head;
|
||||
group_clauses++;
|
||||
group_count += lv->count;
|
||||
next_head = make_header(lv->body,
|
||||
current_head->count - group_count,
|
||||
current_head->num_clauses - group_clauses,
|
||||
SCHEME_LET_RECURSIVE);
|
||||
current_head->num_clauses = group_clauses;
|
||||
current_head->count = group_count;
|
||||
current_head->body = (Scheme_Object *)next_head;
|
||||
current_head = next_head;
|
||||
}
|
||||
group_clauses = 0;
|
||||
group_count = 0;
|
||||
} else {
|
||||
group_clauses++;
|
||||
group_count += lv->count;
|
||||
}
|
||||
} else
|
||||
prev_might_invoke = 1;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1933,23 +2350,43 @@ gen_let_syntax (Scheme_Object *form, Scheme_Comp_Env *origenv, char *formname,
|
|||
lv->flags = flags;
|
||||
}
|
||||
|
||||
{
|
||||
Scheme_Let_Header *head;
|
||||
if (rec_env_already == 2) {
|
||||
/* `head' is a chain of group headers; splice them into the lv
|
||||
chain, and adjust coordinates in each lv->value due to
|
||||
grouping */
|
||||
Scheme_Let_Header *current_head = head, *next_head = (Scheme_Let_Header *)head->body;
|
||||
Scheme_Object *rhs, *next = NULL;
|
||||
int num_group_clauses = 0;
|
||||
|
||||
head = MALLOC_ONE_TAGGED(Scheme_Let_Header);
|
||||
head->iso.so.type = scheme_compiled_let_void_type;
|
||||
head->body = first;
|
||||
head->count = num_bindings;
|
||||
head->num_clauses = num_clauses;
|
||||
SCHEME_LET_FLAGS(head) = ((recursive ? SCHEME_LET_RECURSIVE : 0)
|
||||
| (star ? SCHEME_LET_STAR : 0));
|
||||
lv = (Scheme_Compiled_Let_Value *)first;
|
||||
for (i = 0; i < num_clauses; i++, lv = (Scheme_Compiled_Let_Value *)next) {
|
||||
rhs = shift_compiled_expression(lv->value,
|
||||
((SCHEME_LET_FLAGS(current_head) & SCHEME_LET_RECURSIVE)
|
||||
? num_bindings - current_head->count
|
||||
: num_bindings),
|
||||
0);
|
||||
lv->value = rhs;
|
||||
lv->position -= (num_bindings - current_head->count);
|
||||
next = lv->body;
|
||||
|
||||
first = (Scheme_Object *)head;
|
||||
num_group_clauses++;
|
||||
if (current_head->num_clauses == num_group_clauses) {
|
||||
num_bindings -= current_head->count;
|
||||
current_head = next_head;
|
||||
next_head = (Scheme_Let_Header *)current_head->body;
|
||||
if ((i + 1) < num_clauses) {
|
||||
current_head->body = lv->body;
|
||||
lv->body = (Scheme_Object *)current_head;
|
||||
}
|
||||
num_group_clauses = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
scheme_merge_compile_recs(rec, drec, recs, num_clauses + 1);
|
||||
|
||||
return first;
|
||||
return (Scheme_Object *)head;
|
||||
}
|
||||
|
||||
static Scheme_Object *
|
||||
|
@ -1957,14 +2394,25 @@ do_let_expand(Scheme_Object *orig_form, Scheme_Comp_Env *origenv, Scheme_Expand_
|
|||
const char *formname, int letrec, int multi, int letstar,
|
||||
Scheme_Comp_Env *env_already)
|
||||
{
|
||||
Scheme_Object *vars, *body, *first, *last, *name, *v, *vs, *vlist, *boundname, *form;
|
||||
Scheme_Object *vars, *body, *first, *last, *name, *v, *vs, *vlist, *boundname, *form, *pre_set;
|
||||
Scheme_Comp_Env *use_env, *env;
|
||||
Scheme_Expand_Info erec1;
|
||||
DupCheckRecord r;
|
||||
int rec_env_already = erec[drec].env_already;
|
||||
int rec_env_already = erec[drec].env_already, forward_ref_boundary;
|
||||
/* If env_already == 2, then it's not a true `letrec':
|
||||
it's from `letrec-values+syntax' and should be
|
||||
expanded into `let' plus `letrec'. */
|
||||
|
||||
form = scheme_stx_taint_disarm(orig_form, NULL);
|
||||
|
||||
if (rec_env_already == 2) {
|
||||
v = detect_traditional_letrec(form, origenv);
|
||||
if (!SAME_OBJ(v, form)) {
|
||||
rec_env_already = 1;
|
||||
form = v;
|
||||
}
|
||||
}
|
||||
|
||||
vars = SCHEME_STX_CDR(form);
|
||||
|
||||
if (!SCHEME_STX_PAIRP(vars))
|
||||
|
@ -2091,6 +2539,7 @@ do_let_expand(Scheme_Object *orig_form, Scheme_Comp_Env *origenv, Scheme_Expand_
|
|||
|
||||
first = last = NULL;
|
||||
vs = vars;
|
||||
forward_ref_boundary = 0;
|
||||
while (SCHEME_STX_PAIRP(vars)) {
|
||||
Scheme_Object *rhs;
|
||||
|
||||
|
@ -2100,6 +2549,9 @@ do_let_expand(Scheme_Object *orig_form, Scheme_Comp_Env *origenv, Scheme_Expand_
|
|||
name = SCHEME_STX_CAR(v);
|
||||
name = scheme_add_env_renames(name, env, origenv);
|
||||
|
||||
if (rec_env_already == 2)
|
||||
forward_ref_boundary += scheme_stx_proper_list_length(name);
|
||||
|
||||
rhs = SCHEME_STX_CDR(v);
|
||||
rhs = SCHEME_STX_CAR(rhs);
|
||||
rhs = scheme_add_env_renames(rhs, use_env, origenv);
|
||||
|
@ -2127,6 +2579,7 @@ do_let_expand(Scheme_Object *orig_form, Scheme_Comp_Env *origenv, Scheme_Expand_
|
|||
/* Pass 2: Expand */
|
||||
|
||||
first = last = NULL;
|
||||
pre_set = scheme_null;
|
||||
while (SCHEME_STX_PAIRP(vars)) {
|
||||
Scheme_Object *rhs, *rhs_name;
|
||||
|
||||
|
@ -2158,6 +2611,26 @@ do_let_expand(Scheme_Object *orig_form, Scheme_Comp_Env *origenv, Scheme_Expand_
|
|||
|
||||
last = v;
|
||||
|
||||
if (rec_env_already == 2) {
|
||||
/* Expansion for internal definitions: break into `let' and
|
||||
`letrec' groups based on references among definitions: */
|
||||
int cnt;
|
||||
cnt = scheme_stx_proper_list_length(name);
|
||||
if (SCHEME_NULLP(SCHEME_CDR(first))
|
||||
&& !scheme_env_min_use_below(use_env, forward_ref_boundary)) {
|
||||
/* no self or forward references */
|
||||
first = scheme_datum_to_syntax(first, vs, vs, 0, 1);
|
||||
pre_set = cons(cons(let_values_symbol, first), pre_set);
|
||||
first = NULL;
|
||||
} else if (!scheme_env_min_use_below(use_env, forward_ref_boundary - cnt)) {
|
||||
/* no (further) forward references */
|
||||
first = scheme_datum_to_syntax(first, vs, vs, 0, 1);
|
||||
pre_set = cons(cons(letrec_values_symbol, first), pre_set);
|
||||
first = NULL;
|
||||
}
|
||||
forward_ref_boundary -= cnt;
|
||||
}
|
||||
|
||||
vars = SCHEME_STX_CDR(vars);
|
||||
}
|
||||
|
||||
|
@ -2166,19 +2639,36 @@ do_let_expand(Scheme_Object *orig_form, Scheme_Comp_Env *origenv, Scheme_Expand_
|
|||
if (!SCHEME_STX_NULLP(vars))
|
||||
scheme_wrong_syntax(NULL, vars, form, NULL);
|
||||
|
||||
if (SCHEME_NULLP(pre_set) || first) {
|
||||
if (!first)
|
||||
first = scheme_null;
|
||||
|
||||
first = scheme_datum_to_syntax(first, vs, vs, 0, 1);
|
||||
}
|
||||
|
||||
SCHEME_EXPAND_OBSERVE_NEXT_GROUP(erec[drec].observer);
|
||||
scheme_init_expand_recs(erec, drec, &erec1, 1);
|
||||
erec1.value_name = erec[drec].value_name;
|
||||
body = expand_block(body, env, &erec1, 0);
|
||||
|
||||
if (SCHEME_PAIRP(pre_set)) {
|
||||
if (first)
|
||||
pre_set = cons(cons(letrec_values_symbol, first), pre_set);
|
||||
|
||||
while (!SCHEME_NULLP(pre_set)) {
|
||||
v = scheme_datum_to_syntax(SCHEME_CAR(SCHEME_CAR(pre_set)), orig_form, scheme_sys_wraps(origenv), 0, 0);
|
||||
body = cons(v, cons(SCHEME_CDR(SCHEME_CAR(pre_set)), body));
|
||||
body = scheme_datum_to_syntax(body, orig_form, orig_form, 0, 2);
|
||||
body = cons(body, scheme_null);
|
||||
pre_set = SCHEME_CDR(pre_set);
|
||||
}
|
||||
|
||||
return SCHEME_CAR(body);
|
||||
} else {
|
||||
v = SCHEME_STX_CAR(form);
|
||||
v = cons(v, cons(first, body));
|
||||
v = scheme_datum_to_syntax(v, orig_form, orig_form, 0, 2);
|
||||
}
|
||||
|
||||
return v;
|
||||
}
|
||||
|
@ -3321,14 +3811,27 @@ do_letrec_syntaxes(const char *where,
|
|||
v = cons(letrec_values_symbol, cons(var_bindings, body));
|
||||
v = scheme_datum_to_syntax(v, orig_forms, scheme_sys_wraps(origenv), 0, 2);
|
||||
|
||||
if (!env_already) { /* i.e., not internal defn */
|
||||
/* We want non-`letrec' semantics for value bindings (i.e., sort
|
||||
out the bindings into `letrec' and `let'): */
|
||||
rec[drec].env_already = 2;
|
||||
}
|
||||
|
||||
if (rec[drec].comp) {
|
||||
v = gen_let_syntax(v, stx_env, "letrec-values", 0, 1, 1, rec, drec, var_env);
|
||||
} else {
|
||||
int restore = ((depth >= 0) || (depth == -2));
|
||||
|
||||
if (restore && (rec[drec].env_already == 2)) {
|
||||
/* don't sort out after all, because we're keeping `letrec-values+syntaxes' */
|
||||
rec[drec].env_already = 1;
|
||||
}
|
||||
|
||||
SCHEME_EXPAND_OBSERVE_PRIM_LETREC_VALUES(rec[drec].observer);
|
||||
v = do_let_expand(v, stx_env, rec, drec, "letrec-values", 1, 1, 0, var_env);
|
||||
|
||||
if ((depth >= 0) || (depth == -2)) {
|
||||
/* Pull back out the pieces we want: */
|
||||
if (restore) {
|
||||
/* Add back out the pieces we want: */
|
||||
Scheme_Object *formname;
|
||||
formname = SCHEME_STX_CAR(forms);
|
||||
v = scheme_stx_taint_disarm(v, NULL);
|
||||
|
@ -5157,9 +5660,9 @@ compile_expand_block(Scheme_Object *forms, Scheme_Comp_Env *env,
|
|||
scheme_null);
|
||||
}
|
||||
|
||||
if (stx_start) {
|
||||
if (stx_start || (mixed && !rec[drec].comp && (rec[drec].depth != -1))) {
|
||||
result = scheme_make_pair(letrec_syntaxes_symbol,
|
||||
scheme_make_pair(stx_start,
|
||||
scheme_make_pair((stx_start ? stx_start : scheme_null),
|
||||
scheme_make_pair(start, result)));
|
||||
} else {
|
||||
result = scheme_make_pair(letrec_values_symbol, scheme_make_pair(start, result));
|
||||
|
@ -5191,25 +5694,28 @@ compile_expand_block(Scheme_Object *forms, Scheme_Comp_Env *env,
|
|||
if (!more) {
|
||||
/* We've converted to a letrec or letrec-values+syntaxes */
|
||||
scheme_stx_seal_rib(rib);
|
||||
rec[drec].env_already = 1;
|
||||
rec[drec].env_already = (mixed ? 2 : 1);
|
||||
|
||||
if (rec[drec].comp) {
|
||||
result = scheme_compile_expr(result, env, rec, drec);
|
||||
return scheme_make_pair(result, scheme_null);
|
||||
} else {
|
||||
if (!mixed && ((rec[drec].depth == -2) || (rec[drec].depth > 0))) {
|
||||
if (SAME_OBJ(letrec_syntaxes_symbol, SCHEME_STX_VAL(SCHEME_CAR(SCHEME_STX_VAL(result)))))
|
||||
result = force_traditional_letrec(result, env);
|
||||
}
|
||||
if (rec[drec].depth > 0)
|
||||
--rec[drec].depth;
|
||||
if (rec[drec].depth) {
|
||||
result = scheme_make_pair(result, scheme_null);
|
||||
SCHEME_EXPAND_OBSERVE_BLOCK_TO_LETREC(rec[drec].observer, result);
|
||||
return scheme_expand_list(result, env, rec, drec);
|
||||
} else {
|
||||
SCHEME_EXPAND_OBSERVE_BLOCK_TO_LETREC(rec[drec].observer,
|
||||
scheme_make_pair(result, scheme_null));
|
||||
result = scheme_expand_expr(result, env, rec, drec);
|
||||
}
|
||||
result = scheme_make_pair(result, scheme_null);
|
||||
return scheme_datum_to_syntax(result, forms, forms, 0, 0);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
scheme_stx_seal_rib(rib);
|
||||
|
||||
|
|
Loading…
Reference in New Issue
Block a user