~ chicken-core (chicken-5) /tests/dirty-macros.scm
Trap1; How to write dirty R5RS macros2; http://groups.google.com/groups?selm=87oflzcdwt.fsf%40radish.petrofsky.org3; How to write seemingly unhygienic macros using syntax-rules4; Date: 2001-11-19 01:23:33 PST5;6; $Id: dirty-macros.scm,v 1.10 2003/08/16 02:13:32 oleg Exp oleg $78; Extract a colored identifier from a form9; extract? SYMB BODY CONT-T CONT-F10; BODY is a form that may contain an occurence of an identifier that11; refers to the same binding occurrence as SYMB, perhaps with a different12; color. CONT-T and CONT-F are forms of the shape (K-HEAD K-IDL . K-ARGS)13; where K-IDL are K-ARGS are lists.14; If the extract? macro finds the identifier in question, it expands into15; CONT-T, to be more precise, into16; (K-HEAD (extr-id . K-IDL) . K-ARGS)17; where extr-id is the extracted colored identifier. If the identifier18; SYMB does not occur in BODY at all, the extract macro expands into CONT-F,19; to be more precise,20; (K-HEAD (SYMB . K-IDL) . K-ARGS)2122(define-syntax m-symbol?23 (syntax-rules ()24 ((_ maybe-symbol kt kf)25 (letrec-syntax26 ((ok27 (syntax-rules ()28 ((_) kt)))29 (test30 (syntax-rules ()31 ((_ maybe-symbol) (ok))32 ((_ x) kf))))33 (test abracadabra)))))3435(define-syntax m-symb-equal?36 (syntax-rules ()37 ((_ symb b kt kf)38 (let-syntax39 ((symb (syntax-rules ()40 ((_) kf)))41 (ok (syntax-rules ()42 ((_) kt))))43 (let-syntax44 ((test (syntax-rules ()45 ((_ b) (symb))46 ((_ x) kf))))47 (test ok))))))4849(define-syntax extract?50 (syntax-rules ()51 ((_ symb body _cont-t _cont-f)52 (letrec-syntax53 ((lp54 (syntax-rules (symb)55 ((_ d symb stack (cont-head symb-l . cont-args) cont-f)56 (cont-head (d . symb-l) . cont-args)) ; symb has occurred57 ((_ d (x . y) stack . rest) ; if body is a composite form,58 (lp x x (y . stack) . rest)) ; look inside59 ((_ d1 d2 () cont-t (cont-head symb-l . cont-args))60 (cont-head (symb . symb-l) . cont-args)) ; symb does not occur61 ((_ d1 d2 (x . y) . rest)62 (lp x x y . rest)))))63 (lp body body () _cont-t _cont-f)))))6465; (define-syntax extract?66; (syntax-rules ()67; ((_ symb body _cont-t _cont-f)68; (letrec-syntax69; ((tr70; (syntax-rules ()71; ((_ d (x . y) tail . rest) ; if body is a composite form,72; (tr x x (y . tail) . rest)) ; look inside73; ((_ x y () (cont-head symb-l . cont-args)74; (cont-headf symb-lf . cont-argsf))75; (m-symb-equal? symb y76; (cont-head (x . symb-l) . cont-args) ; symb has occurred77; (cont-headf (symb . symb-lf) . cont-argsf)));symb does not occur78; ((_ d1 d2 (x . y) (cont-head symb-l . cont-args) cont-f)79; (m-symb-equal? symb d280; (cont-head (d1 . symb-l) . cont-args) ; symb has occurred81; (tr x x y (cont-head symb-l . cont-args) cont-f))))))82; (tr body body () _cont-t _cont-f)))))8384; Extract a colored identifier from a form85; extract SYMB BODY CONT86; BODY is a form that may contain an occurence of an identifier that87; refers to the same binding occurrence as SYMB, perhaps with a different88; color. CONT is a form of the shape (K-HEAD K-IDL . K-ARGS)89; where K-IDL are K-ARGS are S-expressions representing lists or the90; empty list.91; The extract macro expands into92; (K-HEAD (extr-id . K-IDL) . K-ARGS)93; where extr-id is the extracted colored identifier. If symbol SYMB does94; not occur in BODY at all, extr-id is identical to SYMB.959697(define-syntax extract98 (syntax-rules ()99 ((_ symb body cont)100 (extract? symb body cont cont))))101102; Extract several colored identifiers from a form103; extract* SYMB-L BODY CONT104; where SYMB-L is the list of symbols to extract, and BODY and CONT105; has the same meaning as in extract, see above.106;107; The extract* macro expands into108; (K-HEAD (extr-id-l . K-IDL) . K-ARGS)109; where extr-id-l is the list of extracted colored identifiers. The extraction110; itself is performed by the macro extract.111112(define-syntax extract*113 (syntax-rules ()114 ((_ (symb) body cont) ; only one symbol: use extract to do the job115 (extract symb body cont))116 ((_ _symbs _body _cont)117 (letrec-syntax118 ((ex-aux ; extract symbol-by-symbol119 (syntax-rules ()120 ((_ found-symbs () body cont)121 (reverse () found-symbs cont))122 ((_ found-symbs (symb . symb-others) body cont)123 (extract symb body124 (ex-aux found-symbs symb-others body cont)))125 ))126 (reverse ; reverse the list of extracted symbols127 (syntax-rules () ; to match the order of SYMB-L128 ((_ res () (cont-head () . cont-args))129 (cont-head res . cont-args))130 ((_ res (x . tail) cont)131 (reverse (x . res) tail cont)))))132 (ex-aux () _symbs _body _cont)))))133134; Writing weakly referentially opaque macros135136; A binding-capturing macro with an explicit specification137; of the captured variable138(define-syntax m1-i139 (syntax-rules ()140 ((_ i val body) (let ((i val)) body))))141142(display143 (m1-i i 10 (* 1 i)))144(newline) ;==> 10145146; A dirty macro m1 that extracts i from its argument and expands147; into an invocation of m1-i:148149(define-syntax m1-dirty-v1150 (syntax-rules ()151 ((_ _val _body)152 (let-syntax153 ((cont154 (syntax-rules ()155 ((_ (symb) val body) (let ((symb val)) body) ))))156 (extract i _body (cont () _val _body))))))157158(display159 (m1-dirty-v1 10 (* 1 i))160)161(newline)162163(display164 (m1-dirty-v1 10165 (m1-dirty-v1 20 (* 1 i)))166)167(newline)168169170; A macro that re-defines itself in its expansion171; m1-dirty-v2 val body172; expands into173; (let ((i val)) body)174; and also re-defines itself in the scope of body.175176(define-syntax m1-dirty-v2177 (syntax-rules ()178 ((_ _val _body)179 (letrec-syntax180 ((doit ; it's the continuation from extract*181 (syntax-rules () ; myself-symb i-symb are colored ids extracted182 ((_ (myself-symb i-symb) val body) ; from the 'body'183 (let ((i-symb val)) ; first bind the symbol i184 (letrec-syntax ; now re-define oneself185 ((myself-symb186 (syntax-rules ()187 ((_ val__ body__)188 (extract* (myself-symb i-symb) body__189 (doit () val__ body__))))))190 body))))))191 (extract* (m1-dirty-v2 i) _body192 (doit () _val _body))))))193194(display "m1-dirty-v2")195(newline)196(display197 (m1-dirty-v2 10 (* 1 i))198)199(newline)200; => 10201202(display203 (m1-dirty-v2 10204 (m1-dirty-v2 20205 (m1-dirty-v2 30 (* 1 i))))206)207(newline)208209(display210 (let ((i 1))211 (m1-dirty-v2 10 (* 1 i)))212)213(newline)214; => 1215216; A self-perpetuating smearing let217; (mylet ((var init)) body)218; expands into219; (let ((var init)) body')220; where body' is body wrapped into redefinitions of mylet221; and a macro m1-dirty-v3222223; This macro is closed (no free variables)224(define-syntax dirty-m-gen225 (syntax-rules ()226 ((_ name let-name _symb_ _body_)227 (let-syntax228 ((name229 (syntax-rules ()230 ((_ _val _body)231 (let-syntax232 ((cont233 (syntax-rules ()234 ((_ (symb) val body) (let ((symb val)) body) ))))235 (extract _symb_ _body (cont () _val _body)))))))236 _body_))))237238; (define-syntax mylet239; (syntax-rules ()240; ((_ ((_var _init)) _body)241; (letrec-syntax242; ((doit ; it's the continuation from extract*243; (syntax-rules () ; myself-symb etc. are extr. colored ids extracted244; ((_ (myself-symb dirty-m-symb i-symb) ((var init)) body)245; (let ((var init)) ; first do the binding246; (letrec-syntax ; now re-define oneself247; ((myself-symb248; (syntax-rules ()249; ((_ ((var__ init__)) body__)250; (extract* (myself-symb dirty-m-symb i-symb)251; (var__ body__)252; (doit () ((var__ init__)) body__))))))253; (dirty-m-gen ; re-generate the dirty macro254; dirty-m-symb myself-symb i-symb255; body)))))))256; (extract* (mylet m1-dirty-v3 i) (_var _body)257; (doit () ((_var _init)) _body))))))258259; (letrec-syntax260; ((ex261; (syntax-rules ()262; ((_ (mylet-symb mm-symb foo-symb) ((var init)) body)263; (let ((var init))264; (make-mm mm-symb foo-symb265; (letrec-syntax266; ((mylet-symb267; (syntax-rules ()268; ((_ ((var_ init_)) body_)269; (extract* (mylet-symb mm-symb foo-symb) (var_ body_)270; (ex () ((var_ init_)) body_))))))271; body)))272; ))))273; (extract* (mylet mm foo) (_var _body)274; (ex () ((_var _init)) _body))))))275276; (display "m1-dirty-v3")277; (newline)278; (display279; (mylet ((i 1))280; (m1-dirty-v3 10 (* 1 i)))281; )282; (newline)283284; (display285; (mylet ((i 1))286; (mylet ((i 10))287; (m1-dirty-v3 20 (* 1 i))))288; )289; (newline)290291; (display292; (mylet ((i 1))293; (m1-dirty-v3 10294; (m1-dirty-v3 20 (* 1 i))))295; )296; (newline)297298299; A macro that generates a dirty macro:300; m1-dirty BODY301; expands into a definition of a macro302; NAME BODY303; which in turn expands into (let ((SYMB 10)) BODY)304; such that the binding captures any free occurences of SYMB in BODY.305306; (define-syntax m1-dirty307; (syntax-rules ()308; ((_ _symb _body)309; (let-syntax310; ((doit311; (syntax-rules ()312; ((_ (symb) val body)313; (let ((symb val)) body)))))314; (extract _symb _body (doit () 10 _body))))))315316; Macro: make-mm NAME SYMB BODY317; In the scope of BODY, define a macro NAME that expands into a symbol SYMB318319(define-syntax make-mm320 (syntax-rules ()321 ((_ name symb body)322 (let-syntax323 ((name324 (syntax-rules ()325 ((_) symb))))326 body))))327328; (define-syntax mylet329; (syntax-rules (foo)330; ((_ ((var init)) body)331; (extract foo (var)332; (make-mm-in ((var init)) body)))))333334; (mylet ((var init)) body)335; expands into336; (let ((var init)) body')337; where body' is the body wrapped in the re-definitions of mylet and macro mm.338339(define-syntax mylet340 (syntax-rules ()341 ((_ ((_var _init)) _body)342 (letrec-syntax343 ((doit ; The continuation from extract*344 (syntax-rules () ; mylet-symb, etc. are extracted from body345 ((_ (mylet-symb mm-symb foo-symb) ((var init)) body)346 (let ((var init)) ; bind the 'var' first347 (make-mm mm-symb foo-symb ; now re-generate the macro mm348 (letrec-syntax349 ((mylet-symb ; and re-define myself350 (syntax-rules ()351 ((_ ((var_ init_)) body_)352 (extract* (mylet-symb mm-symb foo-symb) (var_ body_)353 (doit () ((var_ init_)) body_))))))354 body)))355 ))))356 (extract* (mylet mm foo) (_var _body)357 (doit () ((_var _init)) _body))))))358359(display "mylet")360(newline)361(define foo 1)362(display363 (mylet ((x 1)) (list (mm) x))364)365(newline)366367(display368 (mylet ((foo 2)) (list (mm) foo))369)370(newline)371372; ;(let ((foo 3)) (mylet ((foo 4)) (list foo (mm))))373;(mylet ((foo 2)) (mylet ((foo 3)) (list foo (mm))))374375(display376 (mylet ((foo 3)) (mylet ((foo 4)) (mylet ((foo 5)) (list foo (mm)))))377)378(newline)379380(display381 (mylet ((foo 3))382 (mylet ((thunk (lambda () (mm))))383 (mylet ((foo 4)) (list foo (mm) (thunk)))))384)385(newline)386387; The following are definitions of let, let* and letrec, straight out of R5RS.388; The only difference is that the definitions use custom-bound389; let, let*, letrec and lambda identifiers, which we explicitly pass390; to the macros in the first argument.391392(define-syntax glet ; let, straight out of R5RS393 (syntax-rules ()394 ((_ (let let* letrec lambda) ((name val) ...) body1 body2 ...)395 ((lambda (name ...) body1 body2 ...) val ...))396 ((_ (let let* letrec lambda) tag ((name val) ...) body1 body2 ...)397 ((letrec ((tag398 (lambda (name ...) body1 body2 ...))) tag) val ...))))399400(define-syntax glet* ; let*, straight out of R5RS401 (syntax-rules ()402 ((_ mynames () body1 body2 ...)403 (let () body1 body2 ...))404 ((_ (let let* letrec lambda)405 ((name1 val1) (name2 val2) ...) body1 body2 ...)406 (let ((name1 val1)) (let* ((name2 val2) ...) body1 body2 ...)))))407408; A shorter implementations of letrec, see409; "Re: Widespread bug (arguably) in letrec when an initializer returns twice"410; comp.lang.scheme, 2001-05-21 10:30:34 PST and 2001-05-21 14:56:49 PST411; http://groups.google.com/groups?selm=7eb8ac3e.0105210930.21542605%40posting.google.com412; http://groups.google.com/groups?selm=87ae468j7x.fsf%40app.dial.idiom.com413414(define-syntax gletrec415 (syntax-rules ()416 ((_ (mlet let* letrec lambda) ((var init) ...) . body)417 (mlet ((var 'undefined) ...)418 (let ((temp (list init ...))) ; the native let will do fine here419 (begin (begin (set! var (car temp)) (set! temp (cdr temp))) ...420 (let () . body)))))))421422; This macro defiles its body423; It re-defines all the let-forms and the lambda, and defines424; a non-hygienic macro 'mm'. Whenever any binding is introduced,425; the let-forms, the lambdas and 'mm' are redefined.426; The redefined lambda acts as if it were infected by a virus, which427; keeps spreading within lambda's body to infect other lambda's there.428429(define-syntax defile430 (syntax-rules ()431 ((_ dbody)432 (letrec-syntax433 ((do-defile434 (syntax-rules () ; all the shadowed symbols435 ((_ (let-symb let*-symb letrec-symb lambda-symb mm-symb foo-symb)436 body-to-defile)437 (letrec-syntax438 ((let-symb ; R5RS definition of let439 (syntax-rules ()440 ((_ . args)441 (glet (let-symb let*-symb letrec-symb lambda-symb)442 . args))))443444 (let*-symb ; Redefinition of let*445 (syntax-rules ()446 ((_ . args)447 (glet* (let-symb let*-symb letrec-symb lambda-symb)448 . args))))449450 (letrec-symb ; Redefinition of letrec451 (syntax-rules ()452 ((_ . args)453 (gletrec (let-symb let*-symb letrec-symb lambda-symb)454 . args))))455456 (lambda-symb ; re-defined, infected lambda457 (syntax-rules ()458 ((_ _vars _body)459 (letrec-syntax460 ((doit461 (syntax-rules ()462 ((_ (mylet-symb mylet*-symb myletrec-symb463 mylambda-symb mymm-symb464 myfoo-symb) vars body)465 (lambda-native vars466 (make-mm mymm-symb myfoo-symb467 (do-defile ; proliferate in the body468 (mylet-symb mylet*-symb myletrec-symb469 mylambda-symb470 mymm-symb myfoo-symb)471 body))))))472 (proliferate473 (syntax-rules ()474 ((_ dummy __vars __body)475 (extract* (let-symb let*-symb476 letrec-symb lambda-symb477 mm-symb foo-symb)478 (__vars __body)479 (doit () __vars __body)))))480 (stop-infection481 (syntax-rules ()482 ((_ dummy __vars __body)483 (lambda-native __vars __body))))484 )485 (extract? mm-symb _vars486 ; true-continuation487 (stop-infection () _vars _body)488 ; false-cont489 (proliferate () _vars _body))490 ))))491492 (lambda-native ; capture the native lambda493 (syntax-rules ()494 ((_ . args) (lambda . args))))495 )496497 body-to-defile)))))498499 (extract* (let let* letrec lambda mm foo) dbody500 (do-defile () dbody))501 ))))502503504;(mylet ((foo 2)) (mylet ((x 3)) (mylet ((foo 4)) (list (mm) foo))))505(display "defile")506(display "now.\n" (current-error-port))507(newline)508(defile509 (display510 (let ((foo 2)) (list (mm) foo))511 )512)513(newline)514; ==> (2 2)515516(defile517 (display518 (let ((foo 2)) (let ((foo 3)) (let ((foo 4)) (list (mm) foo))))519 )520)521(newline)522; ==> (4 4)523524(defile525 (display526 (let ((foo 2))527 (let ((foo 3) (bar (list (mm) foo)))528 (list foo (mm) bar)))529 )530)531(newline)532; ==> (3 3 (2 2))533534(defile535 (display536 (let ((foo 2))537 (list538 ((letrec ((bar (lambda () (list foo (mm))))539 (foo 3))540 bar))541 foo (mm)))))542(newline)543;==> ((3 3) 2 2)544545(defile546 (display547 (let ((foo 2))548 (let foo ((flag #t) (lst (list foo (mm))))549 (if flag ((mm) #f (list lst lst)) lst)))))550(newline)551; ==> ((2 2) (2 2))552553(defile554 (display555 (let* ((foo 2)556 (i 3)557 (foo 4)558 (ft (lambda () (mm))) ; will capture binding of foo to 4559 (foo 5)560 (ft1 (lambda (foo) (mm))) ; will capture the arg of ft1561 (foo 6))562 (list foo (mm) (ft) (ft1 7) '(mm))))563 )564(newline)565; ==> (6 6 4 7 (mm))566567; the use of (mm) (separately-defined macro) is equivalent to the use of variable foo --568; (define-macro (mm) foo) -- dirty macro569570571; Re-defining the global let572573(define-syntax dlet574 (syntax-rules ()575 ((_ new-let-symb . args)576 ; just renaming of new-let-symbol with 'let'577 (let-syntax578 ((ren579 (syntax-rules ()580 ((_ list) (defile (let . args))))))581 (ren let1)))))582583584(display "dlet")585(newline)586(display587 (dlet list ((foo 2)) (list (mm) foo))588 )589590; (define-syntax old-let591; (syntax-rules ()592; ((_ . args) (let . args))))593; (define-syntax old-let*594; (syntax-rules ()595; ((_ . args) (let* . args))))596; (define-syntax old-letrec597; (syntax-rules ()598; ((_ . args) (letrec . args))))599; (define-syntax old-lambda600; (syntax-rules ()601; ((_ . args) (lambda . args))))602603; (define-syntax let604; (syntax-rules ()605; ((_ . args) (defile1 (glet (old-let old-let* old-letrec lambda) . args)))))606; ; (define-syntax let607; ; (syntax-rules ()608; ; ((_ . args) (defile1 (old-let . args)))))609610611; (define-syntax defile1612; (syntax-rules ()613; ((_ dbody)614; (letrec-syntax615; ((do-defile616; (syntax-rules () ; all the shadowed symbols617; ((_ (let-symb let*-symb letrec-symb lambda-symb mm-symb foo-symb)618; body-to-defile)619; (letrec-syntax620; ((let-symb ; R5RS definition of let621; (syntax-rules ()622; ((_ . args)623; (glet (let-symb let*-symb letrec-symb lambda-symb)624; . args))))625626; (let*-symb ; Redefinition of let*627; (syntax-rules ()628; ((_ . args)629; (glet* (let-symb let*-symb letrec-symb lambda-symb)630; . args))))631632; (letrec-symb ; Redefinition of letrec633; (syntax-rules ()634; ((_ . args)635; (gletrec (let-symb let*-symb letrec-symb lambda-symb)636; . args))))637638; (lambda-symb ; re-defined, infected lambda639; (syntax-rules ()640; ((_ _vars _body)641; (letrec-syntax642; ((doit643; (syntax-rules ()644; ((_ (mylet-symb mylet*-symb myletrec-symb645; mylambda-symb mymm-symb646; myfoo-symb) vars body)647; (lambda-native vars648; (make-mm mymm-symb myfoo-symb649; (do-defile ; proliferate in the body650; (mylet-symb mylet*-symb myletrec-symb651; mylambda-symb652; mymm-symb myfoo-symb)653; body)))))))654; (extract* (let-symb let*-symb letrec-symb lambda-symb655; mm-symb foo-symb)656; (_vars _body)657; (doit () _vars _body))))))658659; (lambda-native ; capture the native lambda660; (syntax-rules ()661; ((_ . args) (lambda . args))))662; )663664; body-to-defile)))))665666; (extract* (let let* letrec lambda mm foo) dbody667; (do-defile () dbody))668; ))))669670; ; (define-syntax let671; ; (syntax-rules ()672; ; ((_ . args) (dlet let . args))))673674675676; ; (define-syntax alet677; ; (syntax-rules ()678; ; ((_ . args)679; ; (let-syntax680; ; ((doit681; ; (syntax-rules ()682; ; ((_ (let-symb) body) (defile1 let-symb (blet . body))))))683; ; (extract* (blet) args (doit () args))))))684685686; (display "corrupted-let")687; (newline)688; (display689; (let ((foo 2)) (list (mm) foo))690; )691692; (newline)693; (display694; (let ((foo 2)) (let ((foo 3)) (let ((foo 4)) (list (mm) foo))))695; )696; (newline)697; ; ==> (4 4)698699; (display700; (let ((foo 2))701; (let ((foo 3) (bar (list (mm) foo)))702; (list foo (mm) bar)))703; )704; (newline)705; ; ==> (3 3 (2 2))706707; (display708; (let ((foo 2))709; (list710; ((letrec ((bar (lambda () (list foo (mm))))711; (foo 3))712; bar))713; foo (mm))))714; (newline)715; ;==> ((3 3) 2 2)716717; (display718; (let ((foo 2))719; (let foo ((flag #t) (lst (list foo (mm))))720; (if flag ((mm) #f (list lst lst)) lst))))721; (newline)722; ; ==> ((2 2) (2 2))723724; (display725; (let ()726; (let* ((foo 2)727; (i 3)728; (foo 4)729; (ft (lambda () (mm))) ; will capture binding of foo to 4730; (foo 5)731; (ft1 (lambda (foo) (mm))) ; will capture the arg of ft1732; (foo 6))733; (list foo (mm) (ft) (ft1 7) '(mm))))734; )735; (newline)736; ; ==> (6 6 4 7 (mm))737738739(define-syntax defile-what740 (syntax-rules ()741 ((_ dirty-macro-name dirty-macro-name-gen captured-symbol dbody)742 (letrec-syntax743 ((do-defile744 (syntax-rules () ; all the shadowed symbols745 ((_ (let-symb let*-symb letrec-symb lambda-symb mm-symb foo-symb)746 body-to-defile)747 (letrec-syntax748 ((let-symb ; R5RS definition of let749 (syntax-rules ()750 ((_ . args)751 (glet (let-symb let*-symb letrec-symb lambda-symb)752 . args))))753754 (let*-symb ; Redefinition of let*755 (syntax-rules ()756 ((_ . args)757 (glet* (let-symb let*-symb letrec-symb lambda-symb)758 . args))))759760 (letrec-symb ; Redefinition of letrec761 (syntax-rules ()762 ((_ . args)763 (gletrec (let-symb let*-symb letrec-symb lambda-symb)764 . args))))765 (lambda-symb ; re-defined, infected lambda766 (syntax-rules ()767 ((_ _vars _body)768 (letrec-syntax769 ((doit770 (syntax-rules ()771 ((_ (mylet-symb mylet*-symb myletrec-symb772 mylambda-symb mymm-symb773 myfoo-symb) vars body)774 (lambda-native vars775 (dirty-macro-name-gen mymm-symb myfoo-symb776 (do-defile ; proliferate in the body777 (mylet-symb mylet*-symb myletrec-symb778 mylambda-symb779 mymm-symb myfoo-symb)780 body))))))781 (proliferate782 (syntax-rules ()783 ((_ dummy __vars __body)784 (extract* (let-symb let*-symb785 letrec-symb lambda-symb786 mm-symb foo-symb)787 (__vars __body)788 (doit () __vars __body)))))789 (stop-infection790 (syntax-rules ()791 ((_ dummy __vars __body)792 (lambda-native __vars __body))))793 )794 (extract? mm-symb _vars795 ; true-continuation796 (stop-infection () _vars _body)797 ; false-cont798 (proliferate () _vars _body))799 ))))800801; (lambda-symb ; re-defined, infected lambda802; (syntax-rules ()803; ((_ _vars _body)804; (letrec-syntax805; ((doit806; (syntax-rules ()807; ((_ (mylet-symb mylet*-symb myletrec-symb808; mylambda-symb mymm-symb809; myfoo-symb) vars body)810; (lambda-native vars811; (dirty-macro-name-gen mymm-symb myfoo-symb812; (do-defile ; proliferate in the body813; (mylet-symb mylet*-symb myletrec-symb814; mylambda-symb815; mymm-symb myfoo-symb)816; body)))))))817; (extract* (let-symb let*-symb letrec-symb lambda-symb818; mm-symb foo-symb)819; (_vars _body)820; (doit () _vars _body))))))821822 (lambda-native ; capture the native lambda823 (syntax-rules ()824 ((_ . args) (lambda . args))))825 )826827 body-to-defile)))))828829 (extract* (let let* letrec lambda dirty-macro-name captured-symbol) dbody830 (do-defile () dbody))831 ))))832833834(define-syntax let-defiled-syntax835 (syntax-rules ()836 ((_ var-to-capture ((dm-name dm-body)) body)837 (let-syntax838 ((dm-generator839 (syntax-rules ()840 ((_ dmg-name var-to-capture dmg-outer-body)841 (let-syntax842 ((dmg-name dm-body))843 dmg-outer-body)))))844 (defile-what845 dm-name dm-generator var-to-capture body)846 ))))847848(display "defile-what") (newline)849(display850 (let-defiled-syntax851 bar ((mbar (syntax-rules () ((_ val) (+ bar val)))))852 (let ((bar 1)) (let ((bar 2)) (mbar 2))))853)854(newline)855856(display "defile-what") (newline)857(display858 (let-defiled-syntax859 quux ((mquux (syntax-rules () ((_ val) (+ quux quux val)))))860 (let* ((bar 1) (quux 0) (quux 2)861 (lquux (lambda (x) (mquux x)))862 (quux 3)863 (lcquux (lambda (quux) (mquux quux)))) ; will tripple its arg864 (list (+ quux quux) (mquux 0) (lquux 2) (lcquux 5)))))865(newline)866; ==> (6 6 6 15)867868; testing shadowing869(display "test shadowing") (newline)870(display871 (let-defiled-syntax872 quux ((mquux (syntax-rules () ((_ val) (+ quux quux val)))))873 (let* ((bar 1) (quux 0) (quux 2)874 (lquux (lambda (x) (mquux x)))875 (mquux (lambda (val) 0))876 (lcquux (lambda (quux) (mquux quux)))) ; will tripple its arg877 (list (+ quux quux) (mquux 0) (lquux 2) (lcquux 5)))))878(newline)879; ==> (4 0 6 0)880(display881 (let-syntax882 ((mquux (syntax-rules () ((_ val) (+ quux quux val)))))883 (let ((mquux (lambda (val) 0)))884 (let* ((bar 1) (quux 0) (quux 2)885 (lquux (lambda (x) (mquux x)))886 (lcquux (lambda (quux) (mquux quux)))) ; will tripple its arg887 (list (+ quux quux) (mquux 0) (lquux 2) (lcquux 5))))))888(newline)889; ==> (4 0 0 0)890891(display892 (let-defiled-syntax893 quux ((mquux (syntax-rules () ((_ val) (+ quux quux val)))))894 (let-syntax ((mquux (syntax-rules () ((_ val) 0))))895 (let* ((bar 1) (quux 0) (quux 2)896 (lquux (lambda (x) (mquux x)))897 (lcquux (lambda (quux) (mquux quux)))) ; will tripple its arg898 (list (+ quux quux) (mquux 0) (lquux 2) (lcquux 5))))))899; ==> (4 0 0 0)900901(display902 (defile903 (let-syntax904 ((test2905 (syntax-rules (mm)906 ((_ mm) 'okay)907 ((_ x) 'wrong))))908 (list909 (test2 mm)910 (let ((foo 3)) (test2 mm))))))911(newline)912913; extracting on a different sort of criteria914915; extract2 MARKER BODY CONT916; Search the body for the occurrence of the form (SYMB MARKER . REST)917; where SYMB is a symbol. MARKER is a string, boolean, or number.918; For simplicity, we don't check that SYMB919; is a symbol, but we could: see a macro m-symbol?.920; CONT is a list (K-HEAD () . K-REST)921; If we found such a form, expand into922; (K-HEAD SYMB . K-REST)923; If we didn't find what we searched for, expand into924; (K-HEAD nai . K-REST)925926927(define-syntax extract2928 (syntax-rules ()929 ((_ _marker _body _cont)930 (letrec-syntax931 ((lp932 (syntax-rules ()933 ((_ (symb _marker . rest) stack (cont-head () . cont-args))934 (cont-head symb . cont-args)) ; found935 ((_ (x . y) stack cont) ; if body is a composite form,936 (lp x (y . stack) cont)) ; look inside937 ((_ d () (cont-head () . cont-args))938 (cont-head nai . cont-args)) ; symb does not occur939 ((_ d (x . y) cont)940 (lp x y cont)))))941 (lp _body () _cont)))))942943944(define-syntax loop945 (syntax-rules ()946 ((_ . exps)947 (let-syntax948 ((cont949 (syntax-rules ()950 ((_ ident exps_)951 (call-with-current-continuation952 (lambda (k)953 (let ((ident (lambda (dummy value) (k value))))954 (let f ()955 (begin 'prevent-empty-begin . exps_)956 (f)))))))))957 (extract2 "this one" exps (cont () exps))))))958959960(display "loop") (newline)961(display (loop (break "this one" 'foo)))962(newline)963; ==> foo964965(display "nested loop") (newline)966(display967 (loop968 (loop969 (break "this one" 'foo))970 (break "this one" 'bar)))971; ==> bar972(newline)973974(display "loop: shadowing") (newline)975(display976 (let ((break (lambda (dummy x) x)))977 (loop (break "this one" 'foo))978 (break "this one" 'bar)))979(newline)980981; Petrofsky:982; There are problems with writing extensions to loop. Suppose we want983; to write loop-while, which adds a test that is checked once each time984; around the loop, and still binds an exit procedure. We might think it985; could be written like this:986987(define-syntax loop-while988 (syntax-rules ()989 ((_ test exp ...)990 (loop991 (if (not test) (break "this one" #f))992 exp ...))))993994(display "loop-while") (newline)995(display996 (let ((n 0))997 (loop-while (< n 5)998 (set! n (+ n 1)))999 n))1000; ==> 51001(newline)10021003(display1004 (loop1005 (let ((n 0))1006 (loop-while (< n 5)1007 (set! n (+ n 1))1008 (if (= n 2)1009 (break "this one" 'foo)))1010 (break "this one" 'bar))))1011(newline)101210131014; (define-syntax make-lambda1015; (syntax-rules ()1016; ((_ . args) (lambda . args))))10171018; (define-syntax make-lambda1019; (syntax-rules ()1020; ((_ bindings body ...)1021; (let () (define (proc . bindings) body ...)1022; proc))))10231024(define-syntax make-lambda1025 (syntax-rules ()1026 ((_ bindings body ...)1027 (let-syntax () (define (proc . bindings) body ...)1028 proc))))10291030(define-syntax lambda1031 (syntax-rules ()1032 ((_ bindings body1 body2 ...)1033 (make-lambda bindings1034 (display "OK") (newline)1035 (begin body1 body2 ...)))))10361037(display "lambda-test") (newline)1038(let ((p (lambda (x y z) (list x y z))))1039 (display (p 1 2 3)))1040(newline)10411042(define-syntax mm1043 (syntax-rules ()1044 ((_ dummy) foo)1045 ((_ dummy k) (k foo))))10461047(define-syntax make-mm1048 (syntax-rules ()1049 ((_ mm foo bodies)1050 (let-syntax1051 ((mm1052 (syntax-rules ()1053 ((_ dummy) foo)1054 ((_ dummy (kh () . kargs)) (kh foo . kargs)))))1055 . bodies))))10561057(define-syntax recolor1058 (syntax-rules ()1059 ((_ from to bodies . rest)1060 (let-syntax1061 ((ren1062 (syntax-rules ()1063 ((_ from) bodies))))1064 (ren to)))))10651066(define-syntax nai1067 (syntax-rules ()1068 ((_ dummy (kh () . kargs)) (kh nai . kargs))))10691070(define-syntax lambda1071 (syntax-rules ()1072 ((_ bindings . bodies)1073 (letrec-syntax1074 ((test1075 (syntax-rules ()1076 ((_ symb exp _kt _kf)1077 (letrec-syntax1078 ((loop1079 (syntax-rules (symb)1080 ((_ d () kt kf) kf)1081 ((_ (s . r1) (symb . r2) (kh () . kargs) kf)1082 (kh s . kargs))1083 ((_ d (x . rest) kt kf) (loop rest rest kt kf)))))1084 (loop exp exp _kt _kf)))))1085 (doit1086 (syntax-rules ()1087 ((_ foo orig-foo bindings_ bodies_)1088 (extract2 "mm" bodies_1089 (cont () foo orig-foo bindings_ bodies_)))))1090 (cont1091 (syntax-rules ()1092 ((_ mm bindings_ bodies_)1093 (mm dummy (cont2 () mm bindings_ bodies_)))))1094 (cont21095 (syntax-rules ()1096 ((_ xxx foo mm bindings_ bodies_)1097 (test foo bindings_1098 (cont3 () mm bindings_ bodies_)1099 (make-lambda bindings_ bodies_)))))1100 (cont31101 (syntax-rules ()1102 ((_ foo mm bindings_ bodies_)1103 (make-lambda bindings_1104 (make-mm mm foo1105 bodies_))))))1106 (extract2 "mm" bodies1107 (cont () bindings bodies))))))110811091110; (define-syntax let1111; (syntax-rules ()1112; ((_ ((v i)) . bodies)1113; ((lambda (v) . bodies) i))))11141115(define-syntax let*1116 (syntax-rules ()1117 ((_ () . bodies) (begin . bodies))1118 ((_ ((v i) . rest) . bodies)1119 ((lambda (v) (let* rest . bodies)) i))))1120; ((_ . args) (glet* (let let* letrec lambda) . args))))11211122(display (let* ((foo 2)) (list foo (mm "mm"))))11231124(display1125 (let* ((foo 2)1126 (i 3)1127 (foo 4)1128 (ft (lambda () (mm "mm"))) ; will capture binding of foo to 41129 (foo 5)1130 (ft1 (lambda (foo) (mm "mm"))) ; will capture the arg of ft11131 (foo 6))1132 (list foo (mm "mm") (ft) (ft1 7) '(mm "mm"))))1133(newline)1134; ==> (6 6 4 7 (mm))11351136