diff --git a/collects/web-server/prototype-web-server/newcont/anormal.ss b/collects/web-server/prototype-web-server/newcont/anormal.ss new file mode 100644 index 0000000000..8e72e81e31 --- /dev/null +++ b/collects/web-server/prototype-web-server/newcont/anormal.ss @@ -0,0 +1,180 @@ +(module anormal mzscheme + (require-for-template mzscheme) + (require (lib "kerncase.ss" "syntax") + #;(lib "etc.ss") + (lib "list.ss") + (lib "toplevel.ss" "syntax") + (lib "plt-match.ss") + (lib "stx.ss" "syntax") + "util.ss") + (provide make-anormal-term) + + ; A-Normal Form + (define (id x) x) + + ;; a context is either + ;; frame + ;; (compose context frame) + + ;; a frame is either + ;; w -> target-redex + ;; (listof w) -> target-redex + + ;; compose: (w -> target-expr) (alpha -> target-redex) -> (alpha -> target-expr) + ;; compose a context with a frame + (define (compose ctxt frame) + (if (eq? ctxt id) + frame + (lambda (val) + (let-values ([(x ref-to-x) (generate-formal 'x)]) + #`(#%app (lambda (#,x) #,(ctxt ref-to-x)) #,(frame val)))))) + + (define (make-anormal-term elim-letrec-term) + (define (anormal-term stx) + (anormal id stx)) + + (define (anormal ctxt stx) + (kernel-syntax-case + stx #f + [(begin) + (anormal ctxt (syntax/loc stx (#%app (#%top . void))))] + [(begin lbe) + (anormal ctxt (syntax/loc stx lbe))] + [(begin fbe be ...) + ; XXX Am I a bug? + (anormal ctxt + (syntax/loc stx + (let-values ([(throw-away) fbe]) + (begin be ...))))] + [(begin0) + (anormal ctxt (syntax/loc stx (#%app (#%top . void))))] + [(begin0 lbe) + (anormal ctxt (syntax/loc stx lbe))] + [(begin0 fbe be ...) + (anormal ctxt + (syntax/loc stx + (let-values ([(save) fbe]) + (begin be ... save))))] + [(define-values (v ...) ve) + (with-syntax ([ve (anormal-term #'ve)]) + (syntax/loc stx + (define-values (v ...) ve)))] + [(define-syntaxes (v ...) ve) + (with-syntax ([ve (anormal-term #'ve)]) + (syntax/loc stx + (define-values (v ...) ve)))] + [(define-values-for-syntax (v ...) ve) + (with-syntax ([ve (anormal-term #'ve)]) + (syntax/loc stx + (define-values-for-syntax (v ...) ve)))] + [(set! v ve) + (anormal + (compose ctxt + (lambda (val) + (quasisyntax/loc stx (set! v #,val)))) + #'ve)] + [(let-values () be) + (anormal ctxt (syntax/loc stx be))] + [(let-values ([(v) ve]) be) + (anormal ctxt + (syntax/loc stx + (#%app (lambda (v) be) + ve)))] + [(let-values ([(v ...) ve]) be) + (anormal ctxt + (syntax/loc stx + (#%app call-with-values + (lambda () ve) + (lambda (v ...) be))))] + [(let-values ([(fv ...) fve] [(v ...) ve] ...) be) + (anormal ctxt + (syntax/loc stx + (let-values ([(fv ...) fve]) + (let-values ([(v ...) ve] ...) + be))))] + [(let-values ([(v ...) ve] ...) be ...) + (anormal ctxt + (syntax/loc stx + (let-values ([(v ...) ve] ...) + (begin be ...))))] + [(letrec-values ([(v ...) ve] ...) be ...) + (anormal ctxt + (elim-letrec-term stx))] + [(lambda formals be ...) + (with-syntax ([nbe (anormal-term (syntax/loc stx (begin be ...)))]) + (ctxt (syntax/loc stx (lambda formals nbe))))] + [(case-lambda [formals be] ...) + (with-syntax ([(be ...) (map anormal-term (syntax->list #'(be ...)))]) + (ctxt (syntax/loc stx (case-lambda [formals be] ...))))] + [(case-lambda [formals be ...] ...) + (anormal ctxt + (syntax/loc stx (case-lambda [formals (begin be ...)] ...)))] + [(if te ce ae) + (anormal + (compose ctxt + (lambda (val) + (quasisyntax/loc stx + (if #,val + #,(anormal-term #'ce) + #,(anormal-term #'ae))))) + #'te)] + [(if te ce) + (anormal ctxt (syntax/loc stx (if te ce (#%app void))))] + [(quote datum) + (ctxt stx)] + [(quote-syntax datum) + (ctxt stx)] + [(letrec-syntaxes+values ([(sv ...) se] ...) + ([(vv ...) ve] ...) + be ...) + (raise-syntax-error 'anormal "XXX What do I do with letrec-syntaxes+values?" stx)] + [(with-continuation-mark ke me be) + (anormal + (compose ctxt + (lambda (kev) + (anormal + (lambda (mev) + (quasisyntax/loc stx + (with-continuation-mark #,kev #,mev + #,(anormal-term #'be)))) + #'me))) + #'ke)] + [(#%expression . d) + (ctxt stx)] + [(#%app fe e ...) + (anormal + (lambda (val0) + (anormal* + (compose ctxt + (lambda (rest-vals) + (quasisyntax/loc stx + (#%app #,val0 #,@rest-vals)))) + (syntax->list #'(e ...)))) + #'fe)] + [(#%top . v) + (ctxt stx)] + [(#%datum . d) + (ctxt stx)] + [(#%variable-reference . v) + (ctxt stx)] + [id (identifier? #'id) + (ctxt #'id)] + [_ + (raise-syntax-error 'anormal "Dropped through:" stx)])) + + ;; anormal*: ((listof w) -> target-expr) (listof source-expr) -> target-expr + ;; normalize an expression given as a context and list of sub-expressions + (define (anormal* multi-ctxt exprs) + (match exprs + [(list) + (multi-ctxt '())] + [(list-rest fe re) + (anormal + (lambda (val) + (anormal* + (lambda (rest-vals) + (multi-ctxt (list* val rest-vals))) + re)) + fe)])) + + anormal-term)) \ No newline at end of file diff --git a/collects/web-server/prototype-web-server/newcont/defun.ss b/collects/web-server/prototype-web-server/newcont/defun.ss new file mode 100644 index 0000000000..f6bc19a269 --- /dev/null +++ b/collects/web-server/prototype-web-server/newcont/defun.ss @@ -0,0 +1,155 @@ +(module defun mzscheme + (require-for-template mzscheme) + (require (lib "kerncase.ss" "syntax") + #;(lib "etc.ss") + (lib "list.ss") + (lib "toplevel.ss" "syntax") + (lib "plt-match.ss") + (lib "stx.ss" "syntax") + "util.ss" + "freevars.ss" + (lib "closure.ss" "prototype-web-server")) + (provide defun) + + ; make-new-clouse-label : (syntax -> syntax) syntax -> syntax + (define (make-new-closure-label labeling stx) + (labeling stx)) + + ; defun : syntax[1] -> (values syntax?[2] (listof syntax?)[3]) + ; defunctionalizes the first syntax, returning the second and the lifted lambdas [3] + (define (defun stx) + (kernel-syntax-case + stx #f + [(begin be ...) + (let-values ([(nbes defs) (defun* (syntax->list #'(be ...)))]) + (values (quasisyntax/loc stx (begin #,@nbes)) + defs))] + [(begin0 be ...) + (let-values ([(nbes defs) (defun* (syntax->list #'(be ...)))]) + (values (quasisyntax/loc stx (begin0 #,@nbes)) + defs))] + [(define-values (v ...) ve) + (let-values ([(nve defs) (defun #'ve)]) + (values (quasisyntax/loc stx (define-values (v ...) #,nve)) + defs))] + [(define-syntaxes (v ...) ve) + (let-values ([(nve defs) (defun #'ve)]) + (values (quasisyntax/loc stx (define-syntaxes (v ...) #,nve)) + defs))] + [(define-values-for-syntax (v ...) ve) + (let-values ([(nve defs) (defun #'ve)]) + (values (quasisyntax/loc stx (define-values-for-syntax (v ...) #,nve)) + defs))] + [(set! v ve) + (let-values ([(nve defs) (defun #'ve)]) + (values (quasisyntax/loc stx (set! v #,nve)) + defs))] + [(let-values ([(v ...) ve] ...) be ...) + (let-values ([(nves ve-defs) (defun* (syntax->list #'(ve ...)))] + [(nbes be-defs) (defun* (syntax->list #'(be ...)))]) + (with-syntax ([(nve ...) nves] + [(nbe ...) nbes]) + (values (syntax/loc stx (let-values ([(v ...) nve] ...) nbe ...)) + (append ve-defs be-defs))))] + [(letrec-values ([(v ...) ve] ...) be ...) + (let-values ([(nves ve-defs) (defun* (syntax->list #'(ve ...)))] + [(nbes be-defs) (defun* (syntax->list #'(be ...)))]) + (with-syntax ([(nve ...) nves] + [(nbe ...) nbes]) + (values (syntax/loc stx (letrec-values ([(v ...) nve] ...) nbe ...)) + (append ve-defs be-defs))))] + [(lambda formals be ...) + (let-values ([(nbes be-defs) (defun* (syntax->list #'(be ...)))]) + (with-syntax ([(nbe ...) nbes]) + (let ([fvars (free-vars stx)]) + (let-values ([(make-CLOSURE new-defs) + (make-closure-definition-syntax + (make-new-closure-label (current-code-labeling) stx) + fvars + (syntax/loc stx (lambda formals nbe ...)))]) + (values (if (empty? fvars) + (quasisyntax/loc stx (#,make-CLOSURE)) + (quasisyntax/loc stx (#,make-CLOSURE (lambda () (values #,@fvars))))) + (append be-defs new-defs))))))] + [(case-lambda [formals be ...] ...) + (let-values ([(nbes be-defs) (defun** (syntax->list #'((be ...) ...)))]) + (with-syntax ([((nbe ...) ...) nbes]) + (let ([fvars (free-vars stx)]) + (let-values ([(make-CLOSURE new-defs) + (make-closure-definition-syntax + (make-new-closure-label (current-code-labeling) stx) + fvars + (syntax/loc stx (case-lambda [formals nbe ...] ...)))]) + (values (if (empty? fvars) + (quasisyntax/loc stx (#,make-CLOSURE)) + (quasisyntax/loc stx (#,make-CLOSURE (lambda () (values #,@fvars))))) + (append be-defs new-defs))))))] + [(if te ce ae) + (let-values ([(es defs) (defun* (syntax->list #'(te ce ae)))]) + (values (quasisyntax/loc stx (if #,@es)) + defs))] + [(if te ce) + (defun (quasisyntax/loc stx (if te ce (#%app void))))] + [(quote datum) + (values stx + empty)] + [(quote-syntax datum) + (values stx + empty)] + [(letrec-syntaxes+values ([(sv ...) se] ...) + ([(vv ...) ve] ...) + be ...) + (let-values ([(nses se-defs) (defun* (syntax->list #'(se ...)))] + [(nves ve-defs) (defun* (syntax->list #'(ve ...)))] + [(nbes be-defs) (defun* (syntax->list #'(be ...)))]) + (with-syntax ([(nse ...) nses] + [(nve ...) nves] + [(nbe ...) nbes]) + (values (syntax/loc stx + (letrec-syntaxes+values ([(sv ...) nse] ...) + ([(vv ...) nve] ...) + nbe ...)) + (append se-defs ve-defs be-defs))))] + [(with-continuation-mark ke me be) + (let-values ([(es defs) (defun* (list #'ke #'me #'be))]) + (values (quasisyntax/loc stx (with-continuation-mark #,@es)) + defs))] + [(#%expression . d) + (values stx + empty)] + [(#%app e ...) + (let-values ([(es defs) (defun* (syntax->list #'(e ...)))]) + (values (quasisyntax/loc stx (#%app #,@es)) + defs))] + [(#%top . v) + (values stx + empty)] + [(#%datum . d) + (values stx + empty)] + [(#%variable-reference . v) + (values stx + empty)] + [id (identifier? #'id) + (values stx + empty)] + [_ + (raise-syntax-error 'defun "Dropped through:" stx)])) + + ; lift defun to list of syntaxes + (define (lift-defun defun) + (lambda (stxs) + (match + (foldl (lambda (stx acc) + (let-values ([(nstx stx-defs) (defun stx)]) + (match acc + [(list-rest nstxs defs) + (cons (list* nstx nstxs) + (append stx-defs defs))]))) + (cons empty empty) + stxs) + [(list-rest nstxs defs) + (values (reverse nstxs) + defs)]))) + (define defun* (lift-defun defun)) + (define defun** (lift-defun (lambda (stx) (defun* (syntax->list stx)))))) \ No newline at end of file diff --git a/collects/web-server/prototype-web-server/newcont/elim-callcc.ss b/collects/web-server/prototype-web-server/newcont/elim-callcc.ss new file mode 100644 index 0000000000..92f6d725dd --- /dev/null +++ b/collects/web-server/prototype-web-server/newcont/elim-callcc.ss @@ -0,0 +1,175 @@ +(module elim-callcc mzscheme + (require-for-template mzscheme) + (require-for-template (lib "abort-resume.ss" "prototype-web-server")) + (require (lib "kerncase.ss" "syntax") + #;(lib "etc.ss") + (lib "list.ss") + (lib "toplevel.ss" "syntax") + (lib "plt-match.ss") + (lib "stx.ss" "syntax") + "util.ss") + (provide elim-callcc) + + (define (id x) x) + + ;; mark-lambda-as-safe: w -> w + ;; If w is a lambda-expression then add #t to the safety mark, otherwise no mark + (define (mark-lambda-as-safe w) + (syntax-case w (lambda case-lambda) + [(lambda formals be ...) + (syntax/loc w + (lambda formals + (with-continuation-mark safe-call? '(#t (lambda formals)) + be ...)))] + [(case-lambda [formals be ...] ...) + (syntax/loc w + (case-lambda [formals + (with-continuation-mark safe-call? '(#t (case-lambda formals ...)) + be ...)] ...))] + [_else w])) + + (define (elim-callcc stx) + (elim-callcc/mark id stx)) + + (define (elim-callcc/mark markit stx) + (kernel-syntax-case* + stx #f (call/cc call-with-values) + [(begin be ...) + (raise-syntax-error 'elim-callcc/mark "Not in ANF" stx)] + [(begin0 be ...) + (raise-syntax-error 'elim-callcc/mark "Not in ANF" stx)] + [(define-values (v ...) ve) + (with-syntax ([ve (mark-lambda-as-safe (elim-callcc #'ve))]) + (syntax/loc stx + (define-values (v ...) ve)))] + [(define-syntaxes (v ...) ve) + (with-syntax ([ve (mark-lambda-as-safe (elim-callcc #'ve))]) + (syntax/loc stx + (define-values (v ...) ve)))] + [(define-values-for-syntax (v ...) ve) + (with-syntax ([ve (mark-lambda-as-safe (elim-callcc #'ve))]) + (syntax/loc stx + (define-values-for-syntax (v ...) ve)))] + [(set! v ve) + (with-syntax ([ve (elim-callcc #'ve)]) + (syntax/loc stx (set! v ve)))] + [(let-values ([(v ...) ve] ...) be ...) + (raise-syntax-error 'elim-callcc/mark "Not in ANF" stx)] + [(letrec-values ([(v ...) ve] ...) be ...) + (raise-syntax-error 'elim-callcc/mark "Not in ANF" stx)] + [(lambda formals be) + (with-syntax ([be (elim-callcc #'be)]) + (syntax/loc stx + (lambda formals be)))] + [(case-lambda [formals be] ...) + (with-syntax ([(be ...) (map elim-callcc (syntax->list #'(be ...)))]) + (syntax/loc stx + (case-lambda [formals be] ...)))] + [(if te ce ae) + (with-syntax ([te (elim-callcc #'te)] + [ce (elim-callcc #'ce)] + [ae (elim-callcc #'ae)]) + (markit (syntax/loc stx (if te ce ae))))] + [(if te ce) + (raise-syntax-error 'elim-callcc/mark "Not in ANF" stx)] + [(quote datum) + stx] + [(quote-syntax datum) + stx] + [(letrec-syntaxes+values ([(sv ...) se] ...) + ([(vv ...) ve] ...) + be ...) + (raise-syntax-error 'elim-callcc/mark "Not in ANF" stx)] + [(with-continuation-mark ke me be) + (let* ([ke-prime (elim-callcc #'ke)] + [me-prime (elim-callcc #'me)] + [be-prime (elim-callcc #'be)]) + (markit + (quasisyntax/loc stx + (with-continuation-mark #,ke-prime #,me-prime + (with-continuation-mark the-save-cm-key (#%app cons #,ke-prime #,me-prime) + #,be-prime)))))] + [(#%expression . d) + stx] + [(#%app call/cc w) + (let-values ([(cm ref-to-cm) (generate-formal 'current-marks)] + [(x ref-to-x) (generate-formal 'x)]) + (markit + (quasisyntax/loc stx + (#%app #,(elim-callcc #'w) + (#%app (lambda (#,cm) + (lambda #,x + (#%app abort + (lambda () (#%app resume #,ref-to-cm #,ref-to-x))))) + (#%app activation-record-list))))))] + [(#%app call-with-values (lambda () prod) cons) + (let ([cons-prime (mark-lambda-as-safe (elim-callcc #'cons))]) + (markit + (quasisyntax/loc stx + (#%app call-with-values + #,(mark-lambda-as-safe + (quasisyntax/loc stx + (lambda () + #,(elim-callcc/mark + (lambda (x) + (quasisyntax/loc stx + (with-continuation-mark the-cont-key #,cons-prime #,x))) + #'prod)))) + #,cons-prime))))] + [(#%app w (#%app . stuff)) + (with-syntax ([e #'(#%app . stuff)]) + (syntax-case #'w (lambda case-lambda) + [(lambda formals body) + (let ([w-prime (datum->syntax-object #f (gensym 'l))]) + (quasisyntax/loc stx + (let-values ([(#,w-prime) #,(elim-callcc #'w)]) + #,(markit + (quasisyntax/loc stx + (#%app #,w-prime + #,(elim-callcc/mark + (lambda (x) + (quasisyntax/loc stx + (with-continuation-mark the-cont-key #,w-prime #,x))) + #'e)))))))] + [(case-lambda [formals body] ...) + (let ([w-prime (datum->syntax-object #f (gensym 'cl))]) + (quasisyntax/loc stx + (let-values ([(#,w-prime) #,(elim-callcc #'w)]) + #,(markit + (quasisyntax/loc stx + (#%app #,w-prime + #,(elim-callcc/mark + (lambda (x) + (quasisyntax/loc stx + (with-continuation-mark the-cont-key #,w-prime #,x))) + #'e)))))))] + [_else + (let ([w-prime (elim-callcc #'w)]) + (markit + (quasisyntax/loc stx + (#%app #,w-prime + #,(elim-callcc/mark + (lambda (x) + #`(with-continuation-mark the-cont-key #,w-prime #,x)) + #'e)))))]))] + [(#%app w rest ...) + (markit + (quasisyntax/loc stx + (with-continuation-mark safe-call? '(#f #,stx) + (#%app #,(mark-lambda-as-safe (elim-callcc #'w)) + #,@(map + (lambda (an-expr) + (mark-lambda-as-safe + (elim-callcc + an-expr))) + (syntax->list #'(rest ...)))))))] + [(#%top . v) + stx] + [(#%datum . d) + stx] + [(#%variable-reference . v) + stx] + [id (identifier? #'id) + stx] + [_ + (raise-syntax-error 'elim-callcc "Dropped through:" stx)]))) \ No newline at end of file diff --git a/collects/web-server/prototype-web-server/newcont/elim-letrec.ss b/collects/web-server/prototype-web-server/newcont/elim-letrec.ss new file mode 100644 index 0000000000..9372b8495e --- /dev/null +++ b/collects/web-server/prototype-web-server/newcont/elim-letrec.ss @@ -0,0 +1,140 @@ +(module elim-letrec mzscheme + (require-for-template + (lib "abort-resume.ss" "prototype-web-server") + mzscheme) + (require (lib "kerncase.ss" "syntax") + (lib "etc.ss") + (lib "list.ss") + (lib "toplevel.ss" "syntax") + (lib "stx.ss" "syntax") + "util.ss") + (provide (all-defined)) + + ; elim-letrec : (listof identifier-syntax?)[3] -> syntax?[2] -> syntax?[3] + ; Eliminates letrec-values from syntax[2] and correctly handles references to + ; letrec-bound variables [3] therein. + (define ((elim-letrec ids) stx) + (kernel-syntax-case + stx #f + [(begin be ...) + (with-syntax ([(be ...) (map (elim-letrec ids) (syntax->list #'(be ...)))]) + (syntax/loc stx + (begin be ...)))] + [(begin0 be ...) + (with-syntax ([(be ...) (map (elim-letrec ids) (syntax->list #'(be ...)))]) + (syntax/loc stx + (begin0 be ...)))] + [(define-values (v ...) ve) + (with-syntax ([ve ((elim-letrec ids) #'ve)]) + (syntax/loc stx + (define-values (v ...) ve)))] + [(define-syntaxes (v ...) ve) + (with-syntax ([ve ((elim-letrec ids) #'ve)]) + (syntax/loc stx + (define-syntaxes (v ...) ve)))] + [(define-values-for-syntax (v ...) ve) + (with-syntax ([ve ((elim-letrec ids) #'ve)]) + (syntax/loc stx + (define-values-for-syntax (v ...) ve)))] + [(set! v ve) + (with-syntax ([ve ((elim-letrec ids) #'ve)]) + (if (bound-identifier-member? #'id ids) + (syntax/loc stx (#%app set-box! id ve)) + (syntax/loc stx (set! id ve))))] + [(let-values ([(v ...) ve] ...) be ...) + (with-syntax ([(ve ...) (map (elim-letrec ids) (syntax->list #'(ve ...)))] + [(be ...) (map (elim-letrec ids) (syntax->list #'(be ...)))]) + (syntax/loc stx + (let-values ([(v ...) ve] ...) be ...)))] + [(letrec-values ([(v ...) ve] ...) be ...) + (let ([new-ids (apply append ids (map syntax->list (syntax->list #'((v ...) ...))))]) + (with-syntax ([((nv ...) ...) (map (compose generate-temporaries syntax->list) (syntax->list #'((v ...) ...)))] + [((nv-box ...) ...) (map (lambda (nvs) + (map (lambda (x) (syntax/loc x (#%app box the-undef))) + (syntax->list nvs))) + (syntax->list #`((v ...) ...)))] + [(ve ...) (map (elim-letrec new-ids) (syntax->list #'(ve ...)))] + [(be ...) (map (elim-letrec new-ids) (syntax->list #'(be ...)))]) + ; XXX Optimize special case of one nv + (syntax/loc stx + (let-values ([(v ...) + (#%app values nv-box ...)] ...) + (begin (#%app call-with-values + (lambda () ve) + (lambda (nv ...) + (#%app set-box! v nv) ...)) + ... + be ...)))))] + [(lambda formals be ...) + (with-syntax ([(be ...) (map (elim-letrec ids) (syntax->list #'(be ...)))]) + (syntax/loc stx + (lambda formals be ...)))] + [(case-lambda [formals be ...] ...) + (with-syntax ([((be ...) ...) (map (elim-letrec ids) (syntax->list #'((be ...) ...)))]) + (syntax/loc stx + (case-lambda [formals be ...] ...)))] + [(if te ce ae) + (with-syntax ([te ((elim-letrec ids) #'te)] + [ce ((elim-letrec ids) #'ce)] + [ae ((elim-letrec ids) #'ae)]) + (syntax/loc stx + (if te ce ae)))] + [(if te ce) + ((elim-letrec ids) + (syntax/loc stx + (if te ce (#%app (#%top . void)))))] + [(quote datum) + stx] + [(quote-syntax datum) + stx] + [(letrec-syntaxes+values ([(sv ...) se] ...) + ([(vv ...) ve] ...) + be ...) + (let ([new-ids (apply append ids (map syntax->list (syntax->list #'((vv ...) ...))))]) + (with-syntax ([((nvv ...) ...) (map (compose generate-temporaries syntax->list) (syntax->list #'((vv ...) ...)))] + [((nvv-box ...) ...) (map (lambda (nvs) + (map (lambda (x) (syntax/loc x (#%app box the-undef))) + (syntax->list nvs))) + (syntax->list #`((vv ...) ...)))] + [(se ...) (map (elim-letrec new-ids) (syntax->list #'(se ...)))] + [(ve ...) (map (elim-letrec new-ids) (syntax->list #'(ve ...)))] + [(be ...) (map (elim-letrec new-ids) (syntax->list #'(be ...)))]) + ; XXX Optimize special case of one nv + (syntax/loc stx + (let-values ([(vv ...) + (#%app values nvv-box ...)] ...) + ; This is okay, because we've already expanded the syntax. + (let-syntaxes + ([(sv ...) se] ...) + (begin (#%app call-with-values + (lambda () ve) + (lambda (nvv ...) + (#%app set-box! vv nvv) ...)) + ... + be ...))))))] + [(with-continuation-mark ke me be) + (with-syntax ([ke ((elim-letrec ids) #'ke)] + [me ((elim-letrec ids) #'me)] + [be ((elim-letrec ids) #'be)]) + (syntax/loc stx + (with-continuation-mark ke me be)))] + [(#%expression . d) + stx] + [(#%app e ...) + (with-syntax ([(e ...) (map (elim-letrec ids) (syntax->list #'(e ...)))]) + (syntax/loc stx + (#%app e ...)))] + [(#%top . v) + stx] + [(#%datum . d) + stx] + [(#%variable-reference . v) + stx] + [id (identifier? #'id) + (if (bound-identifier-member? #'id ids) + (syntax/loc stx (#%app unbox id)) + #'id)] + [_ + (raise-syntax-error 'elim-letrec "Dropped through:" stx)])) + + (define elim-letrec-term (elim-letrec empty))) \ No newline at end of file diff --git a/collects/web-server/prototype-web-server/newcont/examples/add-param.ss b/collects/web-server/prototype-web-server/newcont/examples/add-param.ss new file mode 100644 index 0000000000..5a53adfe09 --- /dev/null +++ b/collects/web-server/prototype-web-server/newcont/examples/add-param.ss @@ -0,0 +1,38 @@ +(module add-param (lib "newcont.ss" "newcont") + (require (lib "url.ss" "net") + (lib "servlet-helpers.ss" "web-server" "private")) + (provide start) + + (define msg (make-parameter "unknown")) + + (define (gn) + (printf "gn ~a~n" (msg)) + (let* ([req + (send/suspend/url + (lambda (k-url) + (printf "ssu ~S~n" (msg)) + `(hmtl (head (title ,(format "Get ~a number" (msg)))) + (body + (form ([action ,(url->string k-url)] + [method "post"] + [enctype "application/x-www-form-urlencoded"]) + ,(format "Enter the ~a number to add: " (msg)) + (input ([type "text"] [name "number"] [value ""])) + (input ([type "submit"])))))))] + [num (string->number + (extract-binding/single + 'number + (request-bindings req)))]) + (printf "gn ~a ~a~n" (msg) num) + num)) + + (define (start initial-request) + (printf "after s-s~n") + `(html (head (title "Final Page")) + (body + (h1 "Final Page") + (p ,(format "The answer is ~a" + (+ (parameterize ([msg "first"]) + (gn)) + (parameterize ([msg "second"]) + (gn))))))))) \ No newline at end of file diff --git a/collects/web-server/prototype-web-server/newcont/examples/add-simple.ss b/collects/web-server/prototype-web-server/newcont/examples/add-simple.ss new file mode 100644 index 0000000000..c64ce654f8 --- /dev/null +++ b/collects/web-server/prototype-web-server/newcont/examples/add-simple.ss @@ -0,0 +1,39 @@ +(module add-simple (lib "newcont.ss" "newcont") + (require (lib "url.ss" "net") + (lib "servlet-helpers.ss" "web-server" "private") + (lib "web-param.ss" "newcont")) + (provide start) + + (define msg (make-web-parameter "unknown")) + + (define (gn) + (printf "gn ~a~n" (msg)) + (let* ([req + (send/suspend/url + (lambda (k-url) + (printf "ssu ~S~n" (msg)) + `(hmtl (head (title ,(format "Get ~a number" (msg)))) + (body + (form ([action ,(url->string k-url)] + [method "post"] + [enctype "application/x-www-form-urlencoded"]) + ,(format "Enter the ~a number to add: " (msg)) + (input ([type "text"] [name "number"] [value ""])) + (input ([type "submit"])))))))] + [num (string->number + (extract-binding/single + 'number + (request-bindings req)))]) + (printf "gn ~a ~a~n" (msg) num) + num)) + + (define (start initial-request) + (printf "after s-s~n") + `(html (head (title "Final Page")) + (body + (h1 "Final Page") + (p ,(format "The answer is ~a" + (+ (web-parameterize ([msg "first"]) + (gn)) + (web-parameterize ([msg "second"]) + (gn))))))))) \ No newline at end of file diff --git a/collects/web-server/prototype-web-server/newcont/examples/add.ss b/collects/web-server/prototype-web-server/newcont/examples/add.ss new file mode 100644 index 0000000000..7c49ddaf2a --- /dev/null +++ b/collects/web-server/prototype-web-server/newcont/examples/add.ss @@ -0,0 +1,35 @@ +(module add (lib "newcont.ss" "newcont") + (require (lib "url.ss" "net") + (lib "servlet-helpers.ss" "web-server" "private")) + (provide start) + + ;; get-number-from-user: string -> number + ;; ask the user for a number + (define (get-number msg) + (printf "gn ~a~n" msg) + (let* ([req + (send/suspend/url + (lambda (k-url) + (printf "ssu~n") + `(hmtl (head (title ,(format "Get ~a number" msg))) + (body + (form ([action ,(url->string k-url)] + [method "post"] + [enctype "application/x-www-form-urlencoded"]) + ,(format "Enter the ~a number to add: " msg) + (input ([type "text"] [name "number"] [value ""])) + (input ([type "submit"])))))))] + [num (string->number + (extract-binding/single + 'number + (request-bindings req)))]) + (printf "gn ~a ~a~n" msg num) + num)) + + (define (start initial-request) + (printf "after s-s~n") + `(html (head (title "Final Page")) + (body + (h1 "Final Page") + (p ,(format "The answer is ~a" + (+ (get-number "first") (get-number "second")))))))) \ No newline at end of file diff --git a/collects/web-server/prototype-web-server/newcont/examples/temp.ss b/collects/web-server/prototype-web-server/newcont/examples/temp.ss new file mode 100644 index 0000000000..4da80971a2 --- /dev/null +++ b/collects/web-server/prototype-web-server/newcont/examples/temp.ss @@ -0,0 +1,18 @@ +(module temp (lib "newcont.ss" "newcont") + (provide start) + + (define msg (make-parameter "unknown")) + + (define (gn should-be i) + (let/cc k + (printf "~S == ~S~n" should-be (msg)) + i)) + + (define (start) + '(fun . #t) + (printf "12 + 1 = 13 = ~S~n" + (+ + (parameterize ([msg "first"]) + (gn "first" 12)) + (parameterize ([msg "second"]) + (gn "second" 1)))))) \ No newline at end of file diff --git a/collects/web-server/prototype-web-server/newcont/examples/wc-comp.ss b/collects/web-server/prototype-web-server/newcont/examples/wc-comp.ss new file mode 100644 index 0000000000..c53f7782f1 --- /dev/null +++ b/collects/web-server/prototype-web-server/newcont/examples/wc-comp.ss @@ -0,0 +1,37 @@ +(module wc-comp (lib "newcont.ss" "newcont") + (require (lib "web-cells.ss" "newcont") + (lib "web-cell-component.ss" "newcont") + (lib "url.ss" "net")) + (provide start) + + (define (start initial-request) + ; A top-level frame must exist + (define counter1 (make-counter)) + (define counter2 (make-counter)) + ; counter1 and counter2 must have been added to the top-level frame + (define include1 (include-counter counter1)) + (define include2 (include-counter counter2)) + ; counter1 and counter2 may have been modified + (send/suspend/dispatch + (lambda (embed/url) + ; The frame (ref) must have been captured, any changes to web-cells after this will be lost + `(html + (body (h2 "Web Cell Test") + (div (h3 "First") + ,(include1 embed/url)) + (div (h3 "Second") + ,(include2 embed/url))))))) + + (define (make-counter) (make-web-cell 0)) + (define-component (include-counter counter (a-counter) embed/url) + `(div (h3 ,(number->string (web-cell-ref a-counter))) + (a ([href ,(url->string + (embed/url + (lambda _ + ; A new frame has been created + (define last (web-cell-ref a-counter)) + ; It is a child of the parent frame, so we can inspect the value + (web-cell-mask a-counter (add1 last)) + ; The new frame has been modified + (counter))))]) + "+")))) \ No newline at end of file diff --git a/collects/web-server/prototype-web-server/newcont/examples/wc-fake.ss b/collects/web-server/prototype-web-server/newcont/examples/wc-fake.ss new file mode 100644 index 0000000000..105fc65726 --- /dev/null +++ b/collects/web-server/prototype-web-server/newcont/examples/wc-fake.ss @@ -0,0 +1,32 @@ +(module wc-fake (lib "newcont.ss" "newcont") + (require (lib "url.ss" "net")) + (provide start) + + (define (start initial-request) + (define counter1 0) + (define counter2 0) + (send/suspend/dispatch + (lambda (embed/url) + (let*-values ([(inc1 next-counter1 next-counter2) (include-counter counter1 counter2 embed/url)] + [(inc2 next-counter2 next-counter1) (include-counter next-counter2 next-counter1 embed/url)]) + `(html + (body (h2 "Web Cell Test") + (div (h3 "First") ,(inc1 next-counter1 next-counter2)) + (div (h3 "Second") ,(inc2 next-counter2 next-counter1)))))))) + + (define (include-counter my-counter other-counter embed/url) + (let/cc k + (letrec ([include + (lambda (next-my-counter next-other-counter) + `(div (h3 ,(number->string next-my-counter)) + (a ([href + ,(url->string + (embed/url + (lambda _ + (k include + (add1 next-my-counter) + next-other-counter))))]) + "Increment")))]) + (values include + my-counter + other-counter))))) \ No newline at end of file diff --git a/collects/web-server/prototype-web-server/newcont/examples/wc.ss b/collects/web-server/prototype-web-server/newcont/examples/wc.ss new file mode 100644 index 0000000000..225949c019 --- /dev/null +++ b/collects/web-server/prototype-web-server/newcont/examples/wc.ss @@ -0,0 +1,43 @@ +(module wc (lib "newcont.ss" "newcont") + (require (lib "web-cells.ss" "newcont") + (lib "url.ss" "net")) + (provide start) + + (define (start initial-request) + ; A top-level frame must exist + (define counter1 (make-counter)) + (define counter2 (make-counter)) + ; counter1 and counter2 must have been added to the top-level frame + (define include1 (include-counter counter1)) + (define include2 (include-counter counter2)) + ; counter1 and counter2 may have been modified + (send/suspend/dispatch + (lambda (embed/url) + ; The frame (ref) must have been captured, any changes to web-cells after this will be lost + `(html + (body (h2 "Web Cell Test") + (div (h3 "First") + ,(include1 embed/url)) + (div (h3 "Second") + ,(include2 embed/url))))))) + + (define (make-counter) + (make-web-cell 0)) + + (define (include-counter a-counter) + (let/cc k + (define (generate) + (k + (lambda (embed/url) + `(div (h3 ,(number->string (web-cell-ref a-counter))) + (a ([href ,(url->string + (embed/url + (lambda _ + ; A new frame has been created + (define last (web-cell-ref a-counter)) + ; It is a child of the parent frame, so we can inspect the value + (web-cell-mask a-counter (add1 last)) + ; The new frame has been modified + (generate))))]) + "+"))))) + (generate)))) \ No newline at end of file diff --git a/collects/web-server/prototype-web-server/newcont/file-box.ss b/collects/web-server/prototype-web-server/newcont/file-box.ss new file mode 100644 index 0000000000..09c7228ca7 --- /dev/null +++ b/collects/web-server/prototype-web-server/newcont/file-box.ss @@ -0,0 +1,29 @@ +(module file-box mzscheme + (require (lib "serialize.ss") + (lib "contract.ss")) + + (define-serializable-struct internal-file-box (path)) + (define file-box? internal-file-box?) + + (define (file-box path default) + (define fb (make-internal-file-box path)) + (unless (file-box-set? fb) + (file-box-set! fb default)) + fb) + + (define (file-box-set? fb) + (with-handlers ([exn? (lambda _ #f)]) + (file-unbox fb) + #t)) + + (define (file-unbox fb) + (deserialize (call-with-input-file (internal-file-box-path fb) read))) + (define (file-box-set! fb v) + (with-output-to-file (internal-file-box-path fb) (lambda () (write (serialize v))))) + + (provide/contract + [file-box? (any/c . -> . boolean?)] + [file-box (path? any/c . -> . file-box?)] + [file-unbox (file-box? . -> . any/c)] + [file-box-set? (file-box? . -> . boolean?)] + [file-box-set! (file-box? any/c . -> . void)])) \ No newline at end of file diff --git a/collects/web-server/prototype-web-server/newcont/freevars.ss b/collects/web-server/prototype-web-server/newcont/freevars.ss new file mode 100644 index 0000000000..ab66eb8e45 --- /dev/null +++ b/collects/web-server/prototype-web-server/newcont/freevars.ss @@ -0,0 +1,138 @@ +(module freevars mzscheme + (require-for-template mzscheme) + (require (lib "kerncase.ss" "syntax") + (lib "list.ss") + (lib "toplevel.ss" "syntax") + (lib "plt-match.ss") + (lib "stx.ss" "syntax") + "util.ss") + (provide free-vars) + + ;; free-vars: syntax -> (listof identifier) + ;; Find the free variables in an expression + (define (free-vars stx) + (kernel-syntax-case + stx #f + [(begin be ...) + (free-vars* (syntax->list #'(be ...)))] + [(begin0 be ...) + (free-vars* (syntax->list #'(be ...)))] + [(define-values (v ...) ve) + (set-diff (free-vars #'ve) + (syntax->list #'(v ...)))] + [(define-syntaxes (v ...) ve) + (set-diff (free-vars #'ve) + (syntax->list #'(v ...)))] + [(define-values-for-syntax (v ...) ve) + (set-diff (free-vars #'ve) + (syntax->list #'(v ...)))] + [(set! v ve) + (free-vars #'ve)] + [(let-values ([(v ...) ve] ...) be ...) + (union (free-vars* (syntax->list #'(ve ...))) + (set-diff (free-vars* (syntax->list #'(be ...))) + (apply append (map syntax->list (syntax->list #'((v ...) ...))))))] + [(letrec-values ([(v ...) ve] ...) be ...) + (set-diff (union (free-vars* (syntax->list #'(ve ...))) + (free-vars* (syntax->list #'(be ...)))) + (apply append (map syntax->list (syntax->list #'((v ...) ...)))))] + [(lambda formals be ...) + (set-diff (free-vars* (syntax->list #'(be ...))) + (formals-list #'formals))] + [(case-lambda [formals be ...] ...) + (apply union* + (map (lambda (fs bes) + (set-diff (free-vars* (syntax->list bes)) + (formals-list fs))) + (syntax->list #'(formals ...)) + (syntax->list #'((be ...) ...))))] + [(if te ce ae) + (free-vars* (syntax->list #'(te ce ae)))] + [(if te ce) + (free-vars #`(if te ce (#%app void)))] + [(quote datum) + empty] + [(quote-syntax datum) + empty] + [(letrec-syntaxes+values ([(sv ...) se] ...) + ([(vv ...) ve] ...) + be ...) + (set-diff (union* (free-vars* (syntax->list #'(se ...))) + (free-vars* (syntax->list #'(ve ...))) + (free-vars* (syntax->list #'(be ...)))) + (append (apply append (map syntax->list (syntax->list #'((sv ...) ...)))) + (apply append (map syntax->list (syntax->list #'((vv ...) ...))))))] + [(with-continuation-mark ke me be) + (free-vars* (syntax->list #'(ke me be)))] + [(#%expression . d) + empty] + [(#%app e ...) + (free-vars* (syntax->list #'(e ...)))] + [(#%top . v) + empty] + [(#%datum . d) + empty] + [(#%variable-reference . id) + (let ([i-bdg (identifier-binding #'id)]) + (cond + [(eqv? 'lexical (identifier-binding #'id)) + (list #'id)] + [else + empty]))] + [id (identifier? #'id) + (let ([i-bdg (identifier-binding #'id)]) + (cond + [(eqv? 'lexical (identifier-binding #'id)) + (list #'id)] + [else + empty]))] + [_ + (raise-syntax-error 'freevars "Dropped through:" stx)])) + + ;; free-vars*: (listof expr) -> (listof identifier) + ;; union the free variables that occur in several expressions + (define (free-vars* exprs) + (foldl + (lambda (expr acc) (union (free-vars expr) acc)) + empty exprs)) + + ;; union: (listof identifier) (listof identifier) -> (listof identifier) + ;; produce the set-theoretic union of two lists + (define (union l1 l2) + (cond + [(null? l1) l2] + [else (insert (car l1) (union (cdr l1) l2))])) + + (define (union* . ll) + (foldl union + empty + ll)) + + ;; insert: symbol (listof identifier) -> (listof symbol) + ;; insert a symbol into a list without creating a duplicate + (define (insert sym into) + (unless (identifier? sym) + (raise-syntax-error 'insert "Not identifier" sym)) + (cond + [(null? into) (list sym)] + [(bound-identifier=? sym (car into)) into] + [else (cons (car into) (insert sym (cdr into)))])) + + ;; set-diff: (listof identifier) (listof identifier) -> (listof identifier) + ;; produce the set-theoretic difference of two lists + (define (set-diff s1 s2) + (cond + [(null? s2) s1] + [else (set-diff (sans s1 (car s2)) (cdr s2))])) + + ;; sans: (listof identifier) symbol -> (listof identifier) + ;; produce the list sans the symbol + (define (sans s elt) + (unless (identifier? elt) + (raise-syntax-error 'sans "Not identifier" elt)) + (cond + [(null? s) empty] + [(bound-identifier=? (car s) elt) + (cdr s)] ;; if we maintain the no-dupe invariant then we don't need to recur + [else (cons (car s) + (sans (cdr s) elt))]))) \ No newline at end of file diff --git a/collects/web-server/prototype-web-server/newcont/newcont.ss b/collects/web-server/prototype-web-server/newcont/newcont.ss new file mode 100644 index 0000000000..4e7fdb01a9 --- /dev/null +++ b/collects/web-server/prototype-web-server/newcont/newcont.ss @@ -0,0 +1,35 @@ +(module newcont mzscheme + (require-for-syntax (lib "etc.ss") + (lib "labels.ss" "prototype-web-server") + "util.ss" + "elim-letrec.ss" + "anormal.ss" + "elim-callcc.ss" + "defun.ss") + (require (lib "abort-resume.ss" "prototype-web-server")) + (require (only (lib "persistent-web-interaction.ss" "prototype-web-server") + send/suspend/hidden + send/suspend/url + send/suspend/dispatch + extract-proc/url embed-proc/url + redirect/get + start-servlet)) + (provide (rename lang-module-begin #%module-begin)) + (provide (all-from (lib "abort-resume.ss" "prototype-web-server")) + (all-from-except mzscheme #%module-begin) + send/suspend/hidden + send/suspend/url + send/suspend/dispatch + extract-proc/url embed-proc/url + redirect/get + start-servlet) + + (define-syntax lang-module-begin + (make-lang-module-begin + make-labeling + (make-module-case/new-defs + (make-define-case/new-defs + (compose #;(lambda (stx) (values stx empty)) + defun + elim-callcc + (make-anormal-term elim-letrec-term))))))) \ No newline at end of file diff --git a/collects/web-server/prototype-web-server/newcont/util.ss b/collects/web-server/prototype-web-server/newcont/util.ss new file mode 100644 index 0000000000..1eb7148e9f --- /dev/null +++ b/collects/web-server/prototype-web-server/newcont/util.ss @@ -0,0 +1,194 @@ +(module util mzscheme + (require-for-template mzscheme) + (require (lib "kerncase.ss" "syntax") + (lib "etc.ss") + (lib "list.ss") + (lib "toplevel.ss" "syntax") + (lib "stx.ss" "syntax")) + (provide (all-defined)) + + (define current-code-labeling + (make-parameter + (lambda (stx) + (datum->syntax-object stx 'error)))) + + (define (generate-formal sym-name) + (let ([name (datum->syntax-object #f (gensym sym-name))]) + (with-syntax ([(lambda (formal) ref-to-formal) + (if (syntax-transforming?) + (local-expand #`(lambda (#,name) #,name) 'expression empty) + #`(lambda (#,name) #,name))]) + (values #'formal #'ref-to-formal)))) + + (define (formals-list stx) + (syntax-case stx () + [v (identifier? #'v) + (list #'v)] + [(v ...) + (syntax->list #'(v ...))] + [(v ... . rv) + (list* #'rv (syntax->list #'(v ...)))])) + + (define ((make-define-case inner) stx) + (syntax-case stx (define-values define-syntaxes define-values-for-syntax) + [(define-values (v ...) ve) + (with-syntax ([ve (inner #'ve)]) + (syntax/loc stx + (define-values (v ...) ve)))] + [(define-syntaxes (v ...) ve) + (with-syntax ([ve (inner #'ve)]) + (syntax/loc stx + (define-syntaxes (v ...) ve)))] + [(define-values-for-syntax (v ...) ve) + (with-syntax ([ve (inner #'ve)]) + (syntax/loc stx + (define-values-for-syntax (v ...) ve)))] + [_ + (raise-syntax-error 'define-case "Dropped through:" stx)])) + + (define ((make-define-case/new-defs inner) stx) + (let-values ([(nstx defs) (inner stx)]) + (append defs (list nstx)))) + + (define ((make-module-case/new-defs inner) stx) + (syntax-case* stx (require provide require-for-syntax require-for-template) module-identifier=? + [(require spec ...) + (list stx)] + [(provide spec ...) + (list stx)] + [(require-for-syntax spec ...) + (list stx)] + [(require-for-template spec ...) + (list stx)] + [_ + (inner stx)])) + + (define ((make-module-case inner) stx) + (syntax-case* stx (require provide require-for-syntax require-for-template) module-identifier=? + [(require spec ...) + stx] + [(provide spec ...) + stx] + [(require-for-syntax spec ...) + stx] + [(require-for-template spec ...) + stx] + [_ + (inner stx)])) + + (require-for-template (lib "abort-resume.ss" "prototype-web-server")) + (define ((make-lang-module-begin make-labeling transform) stx) + (syntax-case stx () + ((mb forms ...) + (with-syntax ([(pmb rfs body ...) + (local-expand (quasisyntax/loc stx + (#%plain-module-begin + #,(syntax-local-introduce #'(require-for-syntax mzscheme)) + forms ...)) + 'module-begin + empty)]) + (let ([base-labeling (make-labeling (string->bytes/utf-8 (format "~a" (syntax-object->datum stx))))]) + (parameterize ([current-code-labeling + (lambda (stx) + (datum->syntax-object stx (base-labeling)))]) + (let ([new-defs (apply append (map transform (syntax->list #'(body ...))))]) + (quasisyntax/loc stx + (pmb rfs + #,@new-defs))))))))) + + (define (bound-identifier-member? id ids) + (ormap + (lambda (an-id) + (bound-identifier=? id an-id)) + ids)) + + ;; Kernel Case Template + (define (template stx) + (kernel-syntax-case + stx #f + [(begin be ...) + (with-syntax ([(be ...) (map template (syntax->list #'(be ...)))]) + (syntax/loc stx + (begin be ...)))] + [(begin0 be ...) + (with-syntax ([(be ...) (map template (syntax->list #'(be ...)))]) + (syntax/loc stx + (begin0 be ...)))] + [(define-values (v ...) ve) + (with-syntax ([ve (template #'ve)]) + (syntax/loc stx + (define-values (v ...) ve)))] + [(define-syntaxes (v ...) ve) + (with-syntax ([ve (template #'ve)]) + (syntax/loc stx + (define-values (v ...) ve)))] + [(define-values-for-syntax (v ...) ve) + (with-syntax ([ve (template #'ve)]) + (syntax/loc stx + (define-values-for-syntax (v ...) ve)))] + [(set! v ve) + (with-syntax ([ve (template #'ve)]) + (syntax/loc stx + (set! v ve)))] + [(let-values ([(v ...) ve] ...) be ...) + (with-syntax ([(ve ...) (map template (syntax->list #'(ve ...)))] + [(be ...) (map template (syntax->list #'(be ...)))]) + (syntax/loc stx + (let-values ([(v ...) ve] ...) be ...)))] + [(letrec-values ([(v ...) ve] ...) be ...) + (with-syntax ([(ve ...) (map template (syntax->list #'(ve ...)))] + [(be ...) (map template (syntax->list #'(be ...)))]) + (syntax/loc stx + (letrec-values ([(v ...) ve] ...) be ...)))] + [(lambda formals be ...) + (with-syntax ([(be ...) (map template (syntax->list #'(be ...)))]) + (syntax/loc stx + (lambda formals be ...)))] + [(case-lambda [formals be ...] ...) + (with-syntax ([((be ...) ...) (map template (syntax->list #'((be ...) ...)))]) + (syntax/loc stx + (case-lambda [formals be ...] ...)))] + [(if te ce ae) + (with-syntax ([te (template #'te)] + [ce (template #'ce)] + [ae (template #'ae)]) + (syntax/loc stx + (if te ce ae)))] + [(if te ce) + (template (syntax/loc stx (if te ce (#%app void))))] + [(quote datum) + stx] + [(quote-syntax datum) + stx] + [(letrec-syntaxes+values ([(sv ...) se] ...) + ([(vv ...) ve] ...) + be ...) + (with-syntax ([(se ...) (map template (syntax->list #'(se ...)))] + [(ve ...) (map template (syntax->list #'(ve ...)))] + [(be ...) (map template (syntax->list #'(be ...)))]) + (syntax/loc stx + (letrec-syntaxes+values ([(sv ...) se] ...) + ([(vv ...) ve] ...) + be ...)))] + [(with-continuation-mark ke me be) + (with-syntax ([ke (template #'ke)] + [me (template #'me)] + [be (template #'be)]) + (syntax/loc stx + (with-continuation-mark ke me be)))] + [(#%expression . d) + stx] + [(#%app e ...) + (with-syntax ([(e ...) (map template (syntax->list #'(e ...)))]) + (syntax/loc stx + (#%app e ...)))] + [(#%top . v) + stx] + [(#%datum . d) + stx] + [(#%variable-reference . v) + stx] + [id (identifier? #'id) + stx] + [_ + (raise-syntax-error 'kerncase "Dropped through:" stx)]))) \ No newline at end of file diff --git a/collects/web-server/prototype-web-server/newcont/web-cell-component.ss b/collects/web-server/prototype-web-server/newcont/web-cell-component.ss new file mode 100644 index 0000000000..69cf41697f --- /dev/null +++ b/collects/web-server/prototype-web-server/newcont/web-cell-component.ss @@ -0,0 +1,15 @@ +(module web-cell-component mzscheme + (require (lib "web-cells.ss" "newcont")) + (provide define-component) + + (define-syntax define-component + (syntax-rules (define) + [(_ (include-name id formals embed/url) body ...) + (define include-name + (lambda formals + (let/cc k + (define (id) + (k + (lambda (embed/url) + body ...))) + (id))))]))) \ No newline at end of file diff --git a/collects/web-server/prototype-web-server/newcont/web-cells.ss b/collects/web-server/prototype-web-server/newcont/web-cells.ss new file mode 100644 index 0000000000..435ee2c830 --- /dev/null +++ b/collects/web-server/prototype-web-server/newcont/web-cells.ss @@ -0,0 +1,86 @@ +(module web-cells mzscheme + (require (lib "closure.ss" "prototype-web-server") + (lib "serialize.ss") + (lib "list.ss") + (lib "plt-match.ss") + (lib "contract.ss")) + ;; Implementation: Have a distinguished frame variable that is read and captured by send/suspend, + ;; installed on invocations of continuations by the server (and NOT from other continuation invocations) + + ;; Data types + (define-serializable-struct primitive-wc (id)) + (define-serializable-struct frame (env)) + + ;; Environment + (define empty-env empty) + (define env-lookup + (match-lambda* + [(list id (list)) + (error 'web-cell "Undefined web-cell: ~e" id)] + [(list id (list-rest (list-rest a-id a-val) env)) + (if (eq? id a-id) + a-val + (env-lookup id env))])) + (define env-replace + (match-lambda* + [(list id val (list)) + (list (cons id val))] + [(list id val (list-rest (list-rest a-id a-val) env)) + (if (eq? id a-id) + (list* (cons id val) env) + (list* (cons a-id a-val) + (env-replace id val env)))])) + + ;; Frames + (define *wc-frame* (make-thread-cell (make-frame empty-env) #t)) + (define (current-frame) (thread-cell-ref *wc-frame*)) + (define (update-frame! nf) (thread-cell-set! *wc-frame* nf)) + + ;; Web Cell Sets + (define web-cell-set? frame?) + (define (capture-web-cell-set) (current-frame)) + (define (restore-web-cell-set! wcs) (update-frame! wcs)) + + (provide/contract + [web-cell-set? (any/c . -> . boolean?)] + [capture-web-cell-set (-> web-cell-set?)] + [restore-web-cell-set! (web-cell-set? . -> . void)]) + + ;; Web Cells + (define next-web-cell-id + (let ([i (box 0)]) + (lambda () + (begin0 (unbox i) + (set-box! i (add1 (unbox i))))))) + + (define web-cell? primitive-wc?) + + (define-syntax make-web-cell + (syntax-rules () + [(_ default) + (make-web-cell* (closure->deserialize-name (lambda () 'web-cell)) + default)])) + (define (make-web-cell* label default) + (define id (next-web-cell-id)) + (define key (string->symbol (format "~a-~a" label id))) + (define wc (make-primitive-wc key)) + (web-cell-mask wc default) + wc) + + (define (web-cell-ref pwc) + (env-lookup (primitive-wc-id pwc) + (frame-env (current-frame)))) + + (define (web-cell-mask wc nv) + (update-frame! + (make-frame + (env-replace (primitive-wc-id wc) nv + (frame-env (current-frame)))))) + + (provide make-web-cell + make-web-cell*) + (provide/contract + #;[make-web-cell* (symbol? any/c . -> . web-cell?)] + [web-cell? (any/c . -> . boolean?)] + [web-cell-ref (web-cell? . -> . any/c)] + [web-cell-mask (web-cell? any/c . -> . void)])) \ No newline at end of file diff --git a/collects/web-server/prototype-web-server/newcont/web-param.ss b/collects/web-server/prototype-web-server/newcont/web-param.ss new file mode 100644 index 0000000000..0ad7958493 --- /dev/null +++ b/collects/web-server/prototype-web-server/newcont/web-param.ss @@ -0,0 +1,55 @@ +(module web-param mzscheme + (require (lib "closure.ss" "prototype-web-server") + (lib "list.ss")) + (provide make-web-parameter + next-web-parameter-id + web-parameter? + web-parameterize) + + (define (web-parameter? any) + (and (procedure? any) + (procedure-arity-includes? any 0) + (procedure-arity-includes? any 2))) + + (define next-web-parameter-id + (let ([i (box 0)]) + (lambda () + (begin0 (unbox i) + (set-box! i (add1 (unbox i))))))) + + ; This is syntax so that the web-language transformations can occur. + (define-syntax make-web-parameter + (syntax-rules () + [(_ default) + ; Key is a lambda, the defunctionalization process will turn it into a serializable value with the module's label embedded in it, that way the parameters are not guessable AND sensitive to changes in the source + ; I don't like the assumption of deserialization though, but I have to do this grossness because w-c-m uses equal? and post-deserialization, the two lambdas are not equal. + (let* ([id (next-web-parameter-id)] + [label (closure->deserialize-name (lambda () 'web-param))] + [key (string->symbol (format "~a-~a" label id))]) + (case-lambda + [() + (let ([cur + (continuation-mark-set->list + (current-continuation-marks) + key)]) + (if (empty? cur) + default + (first cur)))] + [(v thunk) + (with-continuation-mark key v (thunk))]))])) + + (define-syntax web-parameterize/values + (syntax-rules () + [(_ () e ...) + (begin e ...)] + [(_ ([wp v]) e ...) + (wp v (lambda () e ...))] + [(_ ([fwp fv] [wp v] ...) e ...) + (web-parameterize/values ([fwp fv]) (web-parameterize/values ([wp v] ...) e ...))])) + + (define-syntax (web-parameterize stx) + (syntax-case stx () + [(_ ([wp ve] ...) e ...) + (with-syntax ([(v ...) (generate-temporaries (syntax->list #'(ve ...)))]) + #'(let ([v ve] ...) + (web-parameterize/values ([wp v] ...) e ...)))]))) \ No newline at end of file