! Copyright (C) 2007, 2008 Slava Pestov, Eduardo Cavazos. ! See http://factorcode.org/license.txt for BSD license. USING: kernel namespaces sequences sequences.private assocs math inference.transforms parser words quotations debugger macros arrays macros splitting combinators prettyprint.backend definitions prettyprint hashtables combinators.lib prettyprint.sections ; IN: locals ! Inspired by ! http://cat-language.googlecode.com/svn/trunk/CatPointFreeForm.cs lambda TUPLE: let bindings vars body ; C: let TUPLE: wlet bindings vars body ; C: wlet PREDICATE: word local "local?" word-prop ; : ( name -- word ) #! Create a local variable identifier f dup t "local?" set-word-prop ; PREDICATE: word local-word "local-word?" word-prop ; : ( name -- word ) f dup t "local-word?" set-word-prop ; PREDICATE: word local-reader "local-reader?" word-prop ; : ( name -- word ) f dup t "local-reader?" set-word-prop ; PREDICATE: word local-writer "local-writer?" word-prop ; : ( reader -- word ) dup word-name "!" append f [ t "local-writer?" set-word-prop ] keep [ "local-writer" set-word-prop ] 2keep [ swap "local-reader" set-word-prop ] keep ; TUPLE: quote local ; C: quote ! !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! ! read-local ! !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! : local-index ( obj args -- n ) [ dup quote? [ quote-local ] when eq? ] with find drop ; : read-local ( obj args -- quot ) local-index 1+ dup [ r> ] concat [ dup ] append swap [ swap >r ] concat append ; ! !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! ! localize ! !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! : localize-writer ( obj args -- quot ) >r "local-reader" word-prop r> read-local [ set-first ] append ; : localize ( obj args -- quot ) { { [ over local? ] [ read-local ] } { [ over quote? ] [ >r quote-local r> read-local ] } { [ over local-word? ] [ read-local [ call ] append ] } { [ over local-reader? ] [ read-local [ first ] append ] } { [ over local-writer? ] [ localize-writer ] } { [ over \ lambda eq? ] [ 2drop [ ] ] } { [ t ] [ drop 1quotation ] } } cond ; ! !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! ! point-free ! !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! UNION: special local quote local-word local-reader local-writer ; : load-local ( arg -- quot ) local-reader? [ 1array >r ] [ >r ] ? ; : load-locals ( quot args -- quot ) nip [ load-local ] map concat ; : drop-locals ( args -- args quot ) dup length [ r> drop ] concat ; : point-free-body ( quot args -- newquot ) >r 1 head-slice* r> [ localize ] curry map concat ; : point-free-end ( quot args -- newquot ) over peek special? [ drop-locals >r >r peek r> localize r> append ] [ drop-locals nip swap peek add ] if ; : (point-free) ( quot args -- newquot ) { [ load-locals ] [ point-free-body ] [ point-free-end ] } map-call-with2 concat >quotation ; : point-free ( quot args -- newquot ) over empty? [ drop ] [ (point-free) ] if ; ! !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! ! !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! ! free-vars ! !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! UNION: lexical local local-reader local-writer local-word ; GENERIC: free-vars ( form -- vars ) : add-if-free ( vars object -- vars ) { { [ dup local-writer? ] [ "local-reader" word-prop add ] } { [ dup lexical? ] [ add ] } { [ dup quote? ] [ quote-local add ] } { [ t ] [ free-vars append ] } } cond ; M: object free-vars drop { } ; M: quotation free-vars { } [ add-if-free ] reduce ; M: lambda free-vars dup lambda-vars swap lambda-body free-vars seq-diff ; M: let free-vars dup let-vars swap let-body free-vars seq-diff ; M: wlet free-vars dup wlet-vars swap wlet-body free-vars seq-diff ; ! !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! ! lambda-rewrite ! !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! GENERIC: lambda-rewrite* ( obj -- ) : lambda-rewrite [ lambda-rewrite* ] [ ] make ; UNION: block quotation lambda ; GENERIC: block-vars ( block -- seq ) GENERIC: block-body ( block -- quot ) M: quotation block-vars drop { } ; M: quotation block-body ; M: lambda block-vars lambda-vars ; M: lambda block-body lambda-body ; M: block lambda-rewrite* #! Turn free variables into bound variables, curry them #! onto the body dup free-vars [ ] map dup % [ over block-vars swap append swap block-body [ [ lambda-rewrite* ] each ] [ ] make swap point-free , ] keep length \ curry % ; M: object lambda-rewrite* , ; ! !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! : make-locals ( seq -- words assoc ) [ "!" ?tail [ ] [ ] if ] map dup [ dup [ dup word-name set ] each [ dup local-reader? [ dup word-name set ] [ drop ] if ] each ] H{ } make-assoc ; : make-local-words ( seq -- words assoc ) [ dup ] { } map>assoc dup values swap ; : push-locals ( assoc -- ) use get push ; : parse-locals ( -- words assoc ) "|" parse-tokens make-locals ; : pop-locals ( assoc -- ) use get delete ; : (parse-lambda) ( assoc end -- quot ) over push-locals parse-until >quotation swap pop-locals ; : parse-lambda ( -- lambda ) parse-locals \ ] (parse-lambda) ; : (parse-bindings) ( -- ) scan dup "|" = [ drop ] [ scan { { "[" [ \ ] parse-until >quotation ] } { "[|" [ parse-lambda ] } } case 2array , (parse-bindings) ] if ; : parse-bindings ( -- alist ) scan "|" assert= [ (parse-bindings) ] { } make dup keys ; : let-rewrite ( words body -- ) lambda-rewrite* \ call , ; M: let lambda-rewrite* dup let-bindings values [ lambda-rewrite* \ call , ] each { let-vars let-body } get-slots let-rewrite ; M: wlet lambda-rewrite* dup wlet-bindings values [ lambda-rewrite* ] each { wlet-vars wlet-body } get-slots let-rewrite ; : (::) ( prop -- word quot n ) >r CREATE dup reset-generic scan "|" assert= parse-locals \ ; (parse-lambda) 2dup r> set-word-prop [ lambda-rewrite first ] keep lambda-vars length ; PRIVATE> : [| parse-lambda parsed ; parsing : [let parse-bindings make-locals \ ] (parse-lambda) parsed ; parsing : [wlet parse-bindings make-local-words \ ] (parse-lambda) parsed ; parsing MACRO: with-locals ( form -- quot ) lambda-rewrite ; : :: "lambda" (::) drop define ; parsing : MACRO:: "lambda-macro" (::) (MACRO:) ; parsing \ ] pprint-word block> ; : pprint-let ( body vars bindings -- ) \ | pprint-word t r pprint-word r> pprint* block> ] 2each block> \ | pprint-word block> ; M: let pprint* \ [let pprint-word { let-body let-vars let-bindings } get-slots pprint-let \ ] pprint-word ; M: wlet pprint* \ [let pprint-word { wlet-body wlet-vars wlet-bindings } get-slots pprint-let \ ] pprint-word ; PREDICATE: word lambda-word "lambda" word-prop >boolean ; M: lambda-word definer drop \ :: \ ; ; M: lambda-word definition "lambda" word-prop lambda-body ; : lambda-word-synopsis ( word prop -- ) over definer. over seeing-word over pprint-word \ | pprint-word word-prop lambda-vars pprint-vars \ | pprint-word ; M: lambda-word synopsis* "lambda" lambda-word-synopsis ; PREDICATE: macro lambda-macro "lambda-macro" word-prop >boolean ; M: lambda-macro definer drop \ MACRO:: \ ; ; M: lambda-macro definition "lambda-macro" word-prop lambda-body ; M: lambda-macro synopsis* "lambda-macro" lambda-word-synopsis ; PRIVATE>