diff --git a/collects/stepper/private/annotate.rkt b/collects/stepper/private/annotate.rkt index 6c61372cd9..4e61c924ad 100644 --- a/collects/stepper/private/annotate.rkt +++ b/collects/stepper/private/annotate.rkt @@ -1,4 +1,4 @@ -#lang scheme/base +#lang racket/base (require (prefix-in kernel: syntax/kerncase) mzlib/contract @@ -9,7 +9,6 @@ "shared.ss" "my-macros.ss" #;"xml-box.ss" - #;(file "/Users/clements/clements/scheme-scraps/eli-debug.ss") (prefix-in beginner-defined: "beginner-defined.ss") (for-syntax scheme/base)) @@ -103,11 +102,14 @@ ; top-level-rewrite : (SYNTAX-OBJECT -> SYNTAX-OBJECT) -; top-level-rewrite performs several tasks; it labels variables with their types (let-bound, lambda-bound, or non-lexical), -; it flags if's which could come from cond's, it labels the begins in conds with 'stepper-skip annotations +; top-level-rewrite performs several tasks; it labels variables with their types +; (let-bound, lambda-bound, or non-lexical), it flags if's which could come from +; cond's, it labels the begins in conds with 'stepper-skip annotations -; label-var-types returns a syntax object which is identical to the original except that the variable references are labeled -; with the stepper-syntax-property 'stepper-binding-type, which is set to either let-bound, lambda-bound, or non-lexical. +; label-var-types returns a syntax object which is identical to the original except +; that the variable references are labeled with the stepper-syntax-property +; 'stepper-binding-type, which is set to either let-bound, lambda-bound, or +; non-lexical. (define (top-level-rewrite stx) (let loop ([stx stx] @@ -128,16 +130,30 @@ [do-let/rec (lambda (stx rec?) (with-syntax ([(label ((vars rhs) ...) . bodies) stx]) - (let* ([vars-list (apply append (map syntax->list (syntax->list (syntax (vars ...)))))] - [labelled-vars-list (map (lambda (var-list) (map (lambda (exp) (recur-with-bindings exp vars-list)) - (syntax->list var-list))) - (syntax->list (syntax (vars ...))))] - [rhs-list (if rec? - (map (lambda (exp) (recur-with-bindings exp vars-list)) (syntax->list #'(rhs ...))) - (map recur-regular (syntax->list #'(rhs ...))))] - [new-bodies (map (lambda (exp) (recur-with-bindings exp vars-list)) (syntax->list #'bodies))] + (let* ([vars-list + (apply append + (map syntax->list + (syntax->list (syntax (vars ...)))))] + [labelled-vars-list + (map (lambda (var-list) + (map (lambda (exp) + (recur-with-bindings exp vars-list)) + (syntax->list var-list))) + (syntax->list (syntax (vars ...))))] + [rhs-list + (if rec? + (map (lambda (exp) + (recur-with-bindings exp vars-list)) + (syntax->list #'(rhs ...))) + (map recur-regular (syntax->list #'(rhs ...))))] + [new-bodies + (map (lambda (exp) + (recur-with-bindings exp vars-list)) + (syntax->list #'bodies))] [new-bindings (map list labelled-vars-list rhs-list)]) - (datum->syntax stx `(,#'label ,new-bindings ,@new-bodies) stx stx))))] + (datum->syntax + stx + `(,#'label ,new-bindings ,@new-bodies) stx stx))))] ; evaluated at runtime, using 3D code: [put-into-xml-table (lambda (val) @@ -476,48 +492,78 @@ [lambda-clause-abstraction (lambda (clause) (with-syntax ([(args-stx . bodies) clause]) - (let*-2vals ([(annotated-body free-varrefs) - ; wrap bodies in explicit begin if more than 1 user-introduced (non-skipped) bodies - ; NB: CAN'T HAPPEN in beginner up through int/lambda - (if (> (length (filter (lambda (clause) - (not (stepper-syntax-property clause 'stepper-skip-completely))) - (syntax->list (syntax bodies)))) 1) - (lambda-body-recur (syntax (begin . bodies))) - (let*-2vals ([(annotated-bodies free-var-sets) - (2vals-map lambda-body-recur (syntax->list #`bodies))]) - (2vals #`(begin . #,annotated-bodies) (varref-set-union free-var-sets))))] - [new-free-varrefs (varref-set-remove-bindings free-varrefs - (arglist-flatten #'args-stx))]) - (2vals (datum->syntax #'here `(,#'args-stx ,annotated-body) #'clause) new-free-varrefs))))] + (match-let* + ([(vector annotated-body free-varrefs) + ; wrap bodies in explicit begin if more than 1 + ; user-introduced (non-skipped) bodies + ; NB: CAN'T HAPPEN in beginner up through int/lambda + (let ([non-skipped-bodies + (filter + (lambda (clause) + (not (skipped? clause))) + (syntax->list (syntax bodies)))]) + (if (> (length non-skipped-bodies) 1) + (lambda-body-recur (syntax (begin . bodies))) + (match-let* + ([(vector annotated-bodies free-var-sets) + (2vals-map lambda-body-recur + (syntax->list #`bodies))]) + (vector #`(begin . #,annotated-bodies) + (varref-set-union free-var-sets)))))] + [new-free-varrefs + (varref-set-remove-bindings + free-varrefs + (arglist-flatten #'args-stx))]) + (vector (datum->syntax + #'here + `(,#'args-stx ,annotated-body) #'clause) + new-free-varrefs))))] [outer-lambda-abstraction (lambda (annotated-lambda free-varrefs) - (let*-2vals - ([closure-info (make-debug-info-app 'all free-varrefs 'none)] - ;; if we manually disable the storage of names, lambdas get rendered as lambdas. - [closure-name (if show-lambdas-as-lambdas? - #f - (cond [(syntax? procedure-name-info) procedure-name-info] - [(pair? procedure-name-info) (car procedure-name-info)] - [else #f]))] + (match-let* + ([ap-struct-maker + #`(#,annotated-proc #,annotated-lambda #f)] + [closure-info (make-debug-info-app 'all free-varrefs 'none)] + ;; if we manually disable the storage of + ;; names, lambdas get rendered as lambdas. + [closure-name + (if show-lambdas-as-lambdas? + #f + (cond [(syntax? procedure-name-info) procedure-name-info] + [(pair? procedure-name-info) + (car procedure-name-info)] + [else #f]))] [closure-storing-proc (opt-lambda (closure debug-info [lifted-index #f]) - (closure-table-put! closure (make-closure-record - closure-name - debug-info - #f - lifted-index)) + (closure-table-put! closure + (make-closure-record + closure-name + debug-info + #f + lifted-index)) closure)] + ;; gnarr! I can't find a test case + ;; that depends on the attachment of the inferred name... [inferred-name-lambda (if closure-name - (syntax-property annotated-lambda 'inferred-name (syntax-e closure-name)) + (syntax-property + annotated-lambda + 'inferred-name + (syntax-e closure-name)) annotated-lambda)] [captured (cond [(pair? procedure-name-info) - #`(#%plain-app #,closure-storing-proc #,inferred-name-lambda #,closure-info - #,(cadr procedure-name-info))] + #`(#%plain-app + #,closure-storing-proc + #,inferred-name-lambda + #,closure-info + #,(cadr procedure-name-info))] [else - #`(#%plain-app #,closure-storing-proc #,inferred-name-lambda #,closure-info)])]) + #`(#%plain-app + #,closure-storing-proc + #,inferred-name-lambda + #,closure-info)])]) (normal-bundle free-varrefs captured)))] @@ -803,19 +849,24 @@ (kernel:kernel-syntax-case exp #f [(#%plain-lambda . clause) - (let*-2vals ([(annotated-clause free-varrefs) - (lambda-clause-abstraction (syntax clause))] - [annotated-lambda - (with-syntax ([annotated-clause annotated-clause]) - (syntax/loc exp (#%plain-lambda . annotated-clause)))]) + (match-let* + ([(vector annotated-clause free-varrefs) + (lambda-clause-abstraction #'clause)] + [annotated-lambda + (with-syntax ([annotated-clause annotated-clause]) + (syntax/loc exp + (#%plain-lambda . annotated-clause)))]) (outer-lambda-abstraction annotated-lambda free-varrefs))] [(case-lambda . clauses) - (let*-2vals ([(annotated-cases free-varrefs-cases) - (2vals-map lambda-clause-abstraction (syntax->list (syntax clauses)))] - [annotated-case-lambda (with-syntax ([annotated-cases annotated-cases]) - (syntax/loc exp (case-lambda . annotated-cases)))] - [free-varrefs (varref-set-union free-varrefs-cases)]) + (match-let* + ([(vector annotated-cases free-varrefs-cases) + (2vals-map lambda-clause-abstraction + (syntax->list (syntax clauses)))] + [annotated-case-lambda + (with-syntax ([annotated-cases annotated-cases]) + (syntax/loc exp (case-lambda . annotated-cases)))] + [free-varrefs (varref-set-union free-varrefs-cases)]) (outer-lambda-abstraction annotated-case-lambda free-varrefs))] @@ -1225,3 +1276,7 @@ (define (stepper-recertify new-stx old-stx) (syntax-recertify new-stx old-stx saved-code-inspector #f)) + +;; does this stx have the 'stepper-skip-completely property? +(define (skipped? stx) + (stepper-syntax-property stx 'stepper-skip-completely)) \ No newline at end of file diff --git a/collects/stepper/private/my-macros.rkt b/collects/stepper/private/my-macros.rkt index d781a47017..00fcfbd755 100644 --- a/collects/stepper/private/my-macros.rkt +++ b/collects/stepper/private/my-macros.rkt @@ -1,89 +1,88 @@ -(module my-macros mzscheme +#lang racket - (require-for-syntax mzlib/list) - - ;;;;;;;;;; - ;; - ;; paul graham's [ _ ] macro - ;; - ;;;;;;;;;; - - (provide lx) - - (define-syntax (lx stx) - (syntax-case stx () - [(lx term) - (with-syntax ([binder (datum->syntax-object (syntax term) `_)]) - (syntax (lambda (binder) term)))])) - - - - ;;;;;;;;;; - ;; - ;; ccond implementation - ;; - ;;;;;;;;;; + +;;;;;;;;;; +;; +;; paul graham's [ _ ] macro +;; +;;;;;;;;;; + +(provide lx) + +(define-syntax (lx stx) + (syntax-case stx () + [(lx term) + (with-syntax ([binder (datum->syntax (syntax term) `_)]) + (syntax (lambda (binder) term)))])) + + +;;;;;;;;;; +;; +;; ccond implementation +;; +;;;;;;;;;; + (provide ccond) - - (define-syntax (ccond stx) - (syntax-case stx () - [(_ (question answer) ...) - (syntax - (cond - (question answer) ... - (else (error 'ccond "fell off end of cond expression"))))])) - - - - ;;;;;;;;;; - ;; - ;; 2vals implementation - ;; - ;;;;;;;;;; - - - ;; honestly, match-let* supersedes all of this, if I ever have time to redo it... - - (provide 2vals let*-2vals 2vals-first 2vals-second 2vals-map apply-to-first-of-2vals) - - (define 2vals vector) - - (define-syntax (let*-2vals stx) - (syntax-case stx (let*-2vals) - [(let*-2vals () . bodies) - (syntax/loc stx (begin . bodies))] - [(let*-2vals ([(id-a id-b) rhs] binding ...) . bodies) ; 2 values in a vector - (syntax/loc stx (let* ([_a rhs] [id-a (vector-ref _a 0)] [id-b (vector-ref _a 1)]) - (let*-2vals (binding ...) . bodies)))] - [(let*-2vals ([id-a rhs] binding ...) . bodies) ; just 1 value - (quasisyntax/loc stx (let* ([id-a rhs]) - #,(syntax/loc stx (let*-2vals (binding ...) . bodies))))])) - - (define-syntax (2vals-first stx) - (syntax-case stx (2vals-first) - [(2vals-first a) - (syntax (vector-ref a 0))])) - - (define-syntax (2vals-second stx) - (syntax-case stx (2vals-second) - [(2vals-second a) - (syntax (vector-ref a 1))])) - - (define (apply-to-first-of-2vals proc 2vals) - (vector (proc (vector-ref 2vals 0)) - (vector-ref 2vals 1))) - ; 2vals-map : (('a -> (2vals 'b 'c)) ('a list)) -> (2vals ('b list) ('c list)) - ; dual-map is like map, only for a procedure that returns (values a b), and its - ; result is (values a-list b-list)... the contract specifies this more clearly. - - (define (2vals-map f . lsts) - (if (null? (car lsts)) - (2vals null null) - (let*-2vals ([(a b) (apply f (map car lsts))] - [(a-rest b-rest) (apply 2vals-map f (map cdr lsts))]) - (2vals (cons a a-rest) (cons b b-rest)))))) +(define-syntax (ccond stx) + (syntax-case stx () + [(_ (question answer) ...) + (syntax + (cond + (question answer) ... + (else (error 'ccond "fell off end of cond expression"))))])) + + + +;;;;;;;;;; +;; +;; 2vals implementation +;; +;;;;;;;;;; + + +;; honestly, match-let* supersedes all of this, if I ever have time to redo it... + +(provide 2vals let*-2vals 2vals-first 2vals-second 2vals-map apply-to-first-of-2vals) + +(define 2vals vector) + +(define-syntax (let*-2vals stx) + (syntax-case stx (let*-2vals) + [(let*-2vals () . bodies) + (syntax/loc stx (begin . bodies))] + [(let*-2vals ([(id-a id-b) rhs] binding ...) . bodies) ; 2 values in a vector + (syntax/loc stx (let* ([_a rhs] [id-a (vector-ref _a 0)] [id-b (vector-ref _a 1)]) + (let*-2vals (binding ...) . bodies)))] + [(let*-2vals ([id-a rhs] binding ...) . bodies) ; just 1 value + (quasisyntax/loc stx (let* ([id-a rhs]) + #,(syntax/loc stx (let*-2vals (binding ...) . bodies))))])) + +(define-syntax (2vals-first stx) + (syntax-case stx (2vals-first) + [(2vals-first a) + (syntax (vector-ref a 0))])) + +(define-syntax (2vals-second stx) + (syntax-case stx (2vals-second) + [(2vals-second a) + (syntax (vector-ref a 1))])) + +(define (apply-to-first-of-2vals proc 2vals) + (vector (proc (vector-ref 2vals 0)) + (vector-ref 2vals 1))) + +; 2vals-map : (('a -> (2vals 'b 'c)) ('a list)) -> (2vals ('b list) ('c list)) +; dual-map is like map, only for a procedure that returns (values a b), and its +; result is (values a-list b-list)... the contract specifies this more clearly. + +(define (2vals-map f . lsts) + (if (null? (car lsts)) + (2vals null null) + (let*-2vals ([(a b) (apply f (map car lsts))] + [(a-rest b-rest) (apply 2vals-map f (map cdr lsts))]) + (2vals (cons a a-rest) (cons b b-rest))))) ; test cases ; (require my-macros) diff --git a/collects/stepper/private/shared.rkt b/collects/stepper/private/shared.rkt index a831d60434..ecc0523c5e 100644 --- a/collects/stepper/private/shared.rkt +++ b/collects/stepper/private/shared.rkt @@ -1,37 +1,39 @@ -#lang scheme +#lang racket -(require "my-macros.ss" +(require "my-macros.rkt" srfi/26 scheme/class) -#;(require (for-syntax mzlib/list)) - ; CONTRACTS - - (define varref-set? (listof identifier?)) - (define binding-set? (or/c varref-set? (symbols 'all))) - (define (arglist? v) - (or (null? v) - (identifier? v) - (and (pair? v) - ((flat-contract-predicate (cons/c identifier? arglist?)) v)) - (and (syntax? v) (null? (syntax-e v))) - (and (syntax? v) - ((flat-contract-predicate (cons/c identifier? arglist?)) (syntax-e v))))) - - #;(provide/contract +; CONTRACTS + +(define varref-set? (listof identifier?)) +(define binding-set? (or/c varref-set? (symbols 'all))) +(define (arglist? v) + (or (null? v) + (identifier? v) + (and (pair? v) + ((flat-contract-predicate (cons/c identifier? arglist?)) v)) + (and (syntax? v) (null? (syntax-e v))) + (and (syntax? v) + ((flat-contract-predicate (cons/c identifier? arglist?)) (syntax-e v))))) + +#;(provide/contract [varref-set-remove-bindings (-> varref-set? varref-set? varref-set?)] [binding-set-varref-set-intersect (-> binding-set? varref-set? binding-set?)] [binding-set-union (-> (listof binding-set?) binding-set?)] [varref-set-union (-> (listof varref-set?) varref-set?)] - [skipto/auto (syntax? (symbols 'rebuild 'discard) (syntax? . -> . syntax?) . -> . syntax?)] + [skipto/auto (syntax? (symbols 'rebuild 'discard) + (syntax? . -> . syntax?) + . -> . + syntax?)] [in-closure-table (-> any/c boolean?)] [sublist (-> number? number? list? list?)] [attach-info (-> syntax? syntax? syntax?)] [transfer-info (-> syntax? syntax? syntax?)] [arglist->ilist (-> arglist? any)] [arglist-flatten (-> arglist? (listof identifier?))]) - + (provide skipto/auto in-closure-table @@ -97,26 +99,30 @@ skipto/third skipto/fourth skipto/firstarg - + + (struct-out annotated-proc) + view-controller^ stepper-frame^ ) - - ;; stepper-syntax-property : like syntax property, but adds properties to an association - ;; list associated with the syntax property 'stepper-properties - (define stepper-syntax-property - (case-lambda - [(stx tag) (let ([stepper-props (syntax-property stx 'stepper-properties)]) - (if stepper-props - (let ([table-lookup (assq tag stepper-props)]) - (if table-lookup - (cadr table-lookup) - #f)) - #f))] - [(stx tag new-val) (syntax-property stx 'stepper-properties - (cons (list tag new-val) - (or (syntax-property stx 'stepper-properties) - null)))])) + +;; stepper-syntax-property : like syntax property, but adds properties to an association +;; list associated with the syntax property 'stepper-properties +;; 2010-12-05: I no longer see any reason not just to use the regular +;; syntax-property for this... +(define stepper-syntax-property + (case-lambda + [(stx tag) (let ([stepper-props (syntax-property stx 'stepper-properties)]) + (if stepper-props + (let ([table-lookup (assq tag stepper-props)]) + (if table-lookup + (cadr table-lookup) + #f)) + #f))] + [(stx tag new-val) (syntax-property stx 'stepper-properties + (cons (list tag new-val) + (or (syntax-property stx 'stepper-properties) + null)))])) ;; with-stepper-syntax-properties : like stepper-syntax-property, but in a "let"-like form (define-syntax (with-stepper-syntax-properties stx) @@ -678,8 +684,8 @@ stx)])) - ;; the xml-snip-creation@ unit accepts the xml-snip% and scheme-snip% classes and provides - ;; functions which map a "spec" to an xml-snip. + ;; the xml-snip-creation@ unit accepts the xml-snip% and scheme-snip% classes and + ;; provides functions which map a "spec" to an xml-snip. ;; An xml-spec is (listof xml-spec-elt) ;; An xml-spec-elt is either ;; - a string, @@ -720,10 +726,21 @@ (car (last-pair (send language get-language-position)))) + ;; per Robby's suggestion: rather than using a hash table for + ;; lambdas, just use an applicable structure instead. + + ;; An annotated procedure is represented at runtime by + ;; an applicable structure that stores stepper information. + (struct annotated-proc (base info) + #:property prop:procedure + (struct-field-index base)) + (define-signature view-controller^ (go)) (define-signature stepper-frame^ (stepper-frame%)) + + ; test cases diff --git a/collects/tests/stepper/through-tests.rkt b/collects/tests/stepper/through-tests.rkt index 0b0a76a67c..72ec65401d 100755 --- a/collects/tests/stepper/through-tests.rkt +++ b/collects/tests/stepper/through-tests.rkt @@ -213,6 +213,15 @@ -> ,@defs {(+ 12 9)} -> ,@defs {21})) +;;intermediate/lambda hof +(let ([defs `((define (a x) + (lambda (y) (+ x y))) + (define b (a 9)))]) + (t 'intermediate-lambda-hof m:intermediate-lambda + ,@defs (b 5) + :: ,@defs {(b 5)} + -> @defs {'zoofrenzy})) + ;;;;;;;;;;;; ;; ;; OR / AND @@ -604,9 +613,16 @@ (t1 'let-deriv m:intermediate "(define (f g) (let ([gp (lambda (x) (/ (- (g (+ x 0.1)) (g x)) 0.001))]) gp)) (define gprime (f cos))" - (let ([defs `((define (f g) (let ([gp (lambda (x) (/ (- (g (+ x 0.1)) (g x)) 0.001))]) gp)))]) - `((before-after (,@defs (define gprime (hilite (f cos)))) - (,@defs (define gprime (hilite (let ([gp (lambda (x) (/ (- (cos (+ x 0.1)) (cos x)) 0.001))]) gp))))) + (let ([defs `((define (f g) + (let ([gp (lambda (x) (/ (- (g (+ x 0.1)) (g x)) 0.001))]) + gp)))]) + `((before-after (,@defs (define gprime + (hilite (f cos)))) + (,@defs (define gprime + (hilite (let ([gp (lambda (x) + (/ (- (cos (+ x 0.1)) (cos x)) + 0.001))]) + gp))))) (before-after (,@defs (define gprime (hilite (let ([gp (lambda (x) (/ (- (cos (+ x 0.1)) (cos x)) 0.001))]) gp)))) (,@defs (hilite (define gp_0 (lambda (x) (/ (- (cos (+ x 0.1)) (cos x)) 0.001)))) (define gprime (hilite gp_0)))) (finished-stepping)))) @@ -625,6 +641,8 @@ ((define f_0 (lambda (x) (+ x 13))) (define a (hilite (lambda (x) (+ x 13)))))) (finished-stepping))) + + ;;;;;;;;;;;;; ;; ;; LET* @@ -1486,4 +1504,5 @@ check-error check-error-bad)) #;(run-tests '(teachpack-universe)) #;(run-all-tests) - (run-tests '(check-expect)))) + (run-tests '(intermediate-lambda-hof)) + ))