factor/basis/locals/locals.factor

500 lines
12 KiB
Factor
Raw Normal View History

2008-01-06 11:17:38 -05:00
! Copyright (C) 2007, 2008 Slava Pestov, Eduardo Cavazos.
! See http://factorcode.org/license.txt for BSD license.
USING: kernel namespaces make sequences sequences.private assocs
math vectors strings classes.tuple generalizations parser words
quotations debugger macros arrays macros splitting combinators
prettyprint.backend definitions prettyprint hashtables
prettyprint.sections sets sequences.private effects
effects.parser generic generic.parser compiler.units accessors
locals.backend memoize macros.expander lexer classes summary ;
2007-09-20 18:09:08 -04:00
IN: locals
2008-01-06 11:17:38 -05:00
! Inspired by
! http://cat-language.googlecode.com/svn/trunk/CatPointFreeForm.cs
ERROR: >r/r>-in-lambda-error ;
M: >r/r>-in-lambda-error summary
drop
"Explicit retain stack manipulation is not permitted in lambda bodies" ;
2007-09-20 18:09:08 -04:00
<PRIVATE
TUPLE: lambda vars body ;
C: <lambda> lambda
2008-08-24 04:59:37 -04:00
TUPLE: binding-form bindings body ;
TUPLE: let < binding-form ;
2007-09-20 18:09:08 -04:00
C: <let> let
2008-08-24 04:59:37 -04:00
TUPLE: let* < binding-form ;
2008-03-19 22:16:09 -04:00
C: <let*> let*
2008-08-24 04:59:37 -04:00
TUPLE: wlet < binding-form ;
2007-09-20 18:09:08 -04:00
C: <wlet> wlet
2008-08-24 04:59:37 -04:00
M: lambda expand-macros clone [ expand-macros ] change-body ;
2008-10-17 17:54:07 -04:00
M: lambda expand-macros* expand-macros literal ;
2008-08-24 04:59:37 -04:00
M: binding-form expand-macros
clone
[ [ expand-macros ] assoc-map ] change-bindings
[ expand-macros ] change-body ;
2008-10-17 17:54:07 -04:00
M: binding-form expand-macros* expand-macros literal ;
2008-03-26 19:23:19 -04:00
PREDICATE: local < word "local?" word-prop ;
2007-09-20 18:09:08 -04:00
: <local> ( name -- word )
#! Create a local variable identifier
f <word>
dup t "local?" set-word-prop ;
2007-09-20 18:09:08 -04:00
2008-03-26 19:23:19 -04:00
PREDICATE: local-word < word "local-word?" word-prop ;
2007-09-20 18:09:08 -04:00
: <local-word> ( name -- word )
2007-12-26 20:41:02 -05:00
f <word> dup t "local-word?" set-word-prop ;
2007-09-20 18:09:08 -04:00
2008-03-26 19:23:19 -04:00
PREDICATE: local-reader < word "local-reader?" word-prop ;
2007-09-20 18:09:08 -04:00
: <local-reader> ( name -- word )
f <word>
dup t "local-reader?" set-word-prop ;
2007-09-20 18:09:08 -04:00
2008-03-26 19:23:19 -04:00
PREDICATE: local-writer < word "local-writer?" word-prop ;
2007-09-20 18:09:08 -04:00
: <local-writer> ( reader -- word )
dup name>> "!" append f <word> {
[ nip t "local-writer?" set-word-prop ]
[ swap "local-reader" set-word-prop ]
[ "local-writer" set-word-prop ]
[ nip ]
} 2cleave ;
2007-09-20 18:09:08 -04:00
TUPLE: quote local ;
C: <quote> quote
: local-index ( obj args -- n )
2008-08-29 18:04:52 -04:00
[ dup quote? [ local>> ] when eq? ] with find drop ;
2007-09-20 18:09:08 -04:00
2008-04-17 04:05:36 -04:00
: read-local-quot ( obj args -- quot )
local-index 1+ [ get-local ] curry ;
2007-09-20 18:09:08 -04:00
: localize-writer ( obj args -- quot )
2008-07-18 20:22:59 -04:00
>r "local-reader" word-prop r>
read-local-quot [ set-local-value ] append ;
2007-09-20 18:09:08 -04:00
: localize ( obj args -- quot )
{
2008-04-17 04:05:36 -04:00
{ [ over local? ] [ read-local-quot ] }
2008-08-29 18:04:52 -04:00
{ [ over quote? ] [ >r local>> r> read-local-quot ] }
2008-04-17 04:05:36 -04:00
{ [ over local-word? ] [ read-local-quot [ call ] append ] }
{ [ over local-reader? ] [ read-local-quot [ local-value ] append ] }
2007-09-20 18:09:08 -04:00
{ [ over local-writer? ] [ localize-writer ] }
{ [ over \ lambda eq? ] [ 2drop [ ] ] }
{ [ t ] [ drop 1quotation ] }
} cond ;
UNION: special local quote local-word local-reader local-writer ;
2008-04-17 04:05:36 -04:00
: load-locals-quot ( args -- quot )
2008-09-06 20:13:59 -04:00
[
[ ]
2008-04-17 04:05:36 -04:00
] [
dup [ local-reader? ] contains? [
<reversed> [
local-reader? [ 1array >r ] [ >r ] ?
] map concat
] [
length [ load-locals ] curry >quotation
] if
2008-09-06 20:13:59 -04:00
] if-empty ;
2007-09-20 18:09:08 -04:00
2008-04-17 04:05:36 -04:00
: drop-locals-quot ( args -- quot )
2008-09-06 20:13:59 -04:00
[ [ ] ] [ length [ drop-locals ] curry ] if-empty ;
2007-09-20 18:09:08 -04:00
: point-free-body ( quot args -- newquot )
2008-05-07 02:38:34 -04:00
>r but-last-slice r> [ localize ] curry map concat ;
2007-09-20 18:09:08 -04:00
: point-free-end ( quot args -- newquot )
over peek special?
2008-04-17 04:05:36 -04:00
[ dup drop-locals-quot >r >r peek r> localize r> append ]
[ dup drop-locals-quot nip swap peek suffix ]
2007-09-20 18:09:08 -04:00
if ;
: (point-free) ( quot args -- newquot )
2008-04-17 04:05:36 -04:00
[ nip load-locals-quot ]
[ point-free-body ]
[ point-free-end ]
2tri 3append >quotation ;
2007-09-20 18:09:08 -04:00
: point-free ( quot args -- newquot )
over empty?
[ nip length \ drop <repetition> >quotation ]
[ (point-free) ] if ;
2007-09-20 18:09:08 -04:00
UNION: lexical local local-reader local-writer local-word ;
2008-04-17 04:05:36 -04:00
GENERIC: free-vars* ( form -- )
: free-vars ( form -- vars )
[ free-vars* ] { } make prune ;
2007-09-20 18:09:08 -04:00
M: local-writer free-vars* "local-reader" word-prop , ;
M: lexical free-vars* , ;
M: quote free-vars* , ;
2007-09-20 18:09:08 -04:00
2008-04-17 04:05:36 -04:00
M: object free-vars* drop ;
2007-09-20 18:09:08 -04:00
M: quotation free-vars* [ free-vars* ] each ;
2007-09-20 18:09:08 -04:00
M: lambda free-vars* [ vars>> ] [ body>> ] bi free-vars swap diff % ;
2007-09-20 18:09:08 -04:00
GENERIC: lambda-rewrite* ( obj -- )
2008-02-12 16:48:30 -05:00
GENERIC: local-rewrite* ( obj -- )
2007-09-20 18:09:08 -04:00
2008-08-24 04:59:37 -04:00
: lambda-rewrite ( form -- form' )
expand-macros
2008-02-12 16:48:30 -05:00
[ local-rewrite* ] [ ] make
[ [ lambda-rewrite* ] each ] [ ] make ;
UNION: block callable lambda ;
2007-09-20 18:09:08 -04:00
GENERIC: block-vars ( block -- seq )
GENERIC: block-body ( block -- quot )
2008-02-12 16:48:30 -05:00
M: callable block-vars drop { } ;
M: callable block-body ;
2007-09-20 18:09:08 -04:00
2008-02-12 16:48:30 -05:00
M: callable local-rewrite*
[ [ local-rewrite* ] each ] [ ] make , ;
2007-09-20 18:09:08 -04:00
2008-03-19 22:16:09 -04:00
M: lambda block-vars vars>> ;
2007-09-20 18:09:08 -04:00
2008-03-19 22:16:09 -04:00
M: lambda block-body body>> ;
2007-09-20 18:09:08 -04:00
2008-02-12 16:48:30 -05:00
M: lambda local-rewrite*
2008-04-17 04:05:36 -04:00
[ vars>> ] [ body>> ] bi
[ [ local-rewrite* ] each ] [ ] make <lambda> , ;
2008-02-12 16:48:30 -05:00
2007-09-20 18:09:08 -04:00
M: block lambda-rewrite*
#! Turn free variables into bound variables, curry them
#! onto the body
dup free-vars [ <quote> ] map dup % [
over block-vars prepend
2007-09-20 18:09:08 -04:00
swap block-body [ [ lambda-rewrite* ] each ] [ ] make
swap point-free ,
] keep length \ curry <repetition> % ;
2008-10-17 17:54:07 -04:00
GENERIC: rewrite-literal? ( obj -- ? )
M: special rewrite-literal? drop t ;
M: array rewrite-literal? [ rewrite-literal? ] contains? ;
M: quotation rewrite-literal? [ rewrite-literal? ] contains? ;
M: wrapper rewrite-literal? drop t ;
2008-10-17 17:54:07 -04:00
M: hashtable rewrite-literal? drop t ;
M: vector rewrite-literal? drop t ;
M: tuple rewrite-literal? drop t ;
M: object rewrite-literal? drop f ;
GENERIC: rewrite-element ( obj -- )
2007-09-20 18:09:08 -04:00
: rewrite-elements ( seq -- )
[ rewrite-element ] each ;
2008-02-12 16:48:30 -05:00
: rewrite-sequence ( seq -- )
[ rewrite-elements ] [ length , ] [ 0 head , ] tri \ nsequence , ;
2008-10-17 17:54:07 -04:00
M: array rewrite-element
dup rewrite-literal? [ rewrite-sequence ] [ , ] if ;
M: quotation rewrite-element
dup rewrite-literal? [ rewrite-sequence ] [ , ] if ;
M: vector rewrite-element rewrite-sequence ;
M: hashtable rewrite-element >alist rewrite-sequence \ >hashtable , ;
M: tuple rewrite-element
[ tuple-slots rewrite-elements ] [ class literalize , ] bi \ boa , ;
M: lambda rewrite-element local-rewrite* ;
M: local rewrite-element , ;
M: local-reader rewrite-element , ;
M: word rewrite-element literalize , ;
M: wrapper rewrite-element
dup rewrite-literal? [ wrapped>> rewrite-element ] [ , ] if ;
M: object rewrite-element , ;
M: array local-rewrite* rewrite-element ;
M: vector local-rewrite* rewrite-element ;
M: tuple local-rewrite* rewrite-element ;
M: hashtable local-rewrite* rewrite-element ;
M: wrapper local-rewrite* rewrite-element ;
M: word local-rewrite*
dup { >r r> load-locals get-local drop-locals } memq?
[ >r/r>-in-lambda-error ] [ call-next-method ] if ;
M: object lambda-rewrite* , ;
M: object local-rewrite* , ;
2008-03-19 22:16:09 -04:00
: make-local ( name -- word )
"!" ?tail [
<local-reader>
dup <local-writer> dup name>> set
2008-03-19 22:16:09 -04:00
] [ <local> ] if
dup dup name>> set ;
2008-03-19 22:16:09 -04:00
2007-09-20 18:09:08 -04:00
: make-locals ( seq -- words assoc )
2008-03-19 22:16:09 -04:00
[ [ make-local ] map ] H{ } make-assoc ;
: make-local-word ( name -- word )
<local-word> dup dup name>> set ;
2007-09-20 18:09:08 -04:00
: push-locals ( assoc -- )
use get push ;
: pop-locals ( assoc -- )
use get delete ;
2008-05-07 09:48:51 -04:00
SYMBOL: in-lambda?
2007-09-20 18:09:08 -04:00
: (parse-lambda) ( assoc end -- quot )
2008-05-07 09:48:51 -04:00
t in-lambda? [ parse-until ] with-variable
>quotation swap pop-locals ;
2007-09-20 18:09:08 -04:00
: parse-lambda ( -- lambda )
2008-03-19 22:16:09 -04:00
"|" parse-tokens make-locals dup push-locals
\ ] (parse-lambda) <lambda> ;
2007-09-20 18:09:08 -04:00
2008-03-19 22:16:09 -04:00
: parse-binding ( -- pair/f )
scan {
{ [ dup not ] [ unexpected-eof ] }
{ [ dup "|" = ] [ drop f ] }
{ [ dup "!" = ] [ drop POSTPONE: ! parse-binding ] }
[ scan-object 2array ]
} cond ;
2007-09-20 18:09:08 -04:00
2008-03-19 22:16:09 -04:00
: (parse-bindings) ( -- )
parse-binding [
first2 [ make-local ] dip 2array ,
2008-03-19 22:16:09 -04:00
(parse-bindings)
] when* ;
2007-09-20 18:09:08 -04:00
2008-03-19 22:16:09 -04:00
: parse-bindings ( -- bindings vars )
2008-02-12 16:48:30 -05:00
[
2008-03-19 22:16:09 -04:00
[ (parse-bindings) ] H{ } make-assoc
dup push-locals
] { } make swap ;
: parse-bindings* ( -- words assoc )
[
[
namespace push-locals
(parse-bindings)
] { } make-assoc
] { } make swap ;
: (parse-wbindings) ( -- )
parse-binding [
first2 >r make-local-word r> 2array ,
(parse-wbindings)
] when* ;
: parse-wbindings ( -- bindings vars )
[
[ (parse-wbindings) ] H{ } make-assoc
dup push-locals
] { } make swap ;
: let-rewrite ( body bindings -- )
<reversed> [
>r 1array r> spin <lambda> [ call ] curry compose
] assoc-each local-rewrite* \ call , ;
M: let local-rewrite*
[ body>> ] [ bindings>> ] bi let-rewrite ;
2008-03-19 22:16:09 -04:00
M: let* local-rewrite*
[ body>> ] [ bindings>> ] bi let-rewrite ;
2007-09-20 18:09:08 -04:00
2008-02-12 16:48:30 -05:00
M: wlet local-rewrite*
[ body>> ] [ bindings>> ] bi
2008-03-19 22:16:09 -04:00
[ [ ] curry ] assoc-map
let-rewrite ;
2007-09-20 18:09:08 -04:00
2008-03-19 22:16:09 -04:00
: parse-locals ( -- vars assoc )
2008-06-08 16:32:55 -04:00
")" parse-effect
2008-02-26 19:40:32 -05:00
word [ over "declared-effect" set-word-prop ] when*
2008-07-18 20:22:59 -04:00
in>> [ dup pair? [ first ] when ] map make-locals dup push-locals ;
2008-02-26 19:40:32 -05:00
ERROR: bad-lambda-rewrite output ;
M: bad-lambda-rewrite summary
drop "You have found a bug in locals. Please report." ;
2008-03-16 03:43:00 -04:00
: parse-locals-definition ( word -- word quot )
"(" expect parse-locals \ ; (parse-lambda) <lambda>
2008-02-26 19:40:32 -05:00
2dup "lambda" set-word-prop
lambda-rewrite dup length 1 = [ first ] [ bad-lambda-rewrite ] if ;
2008-02-26 19:40:32 -05:00
2008-06-08 16:32:55 -04:00
: (::) ( -- word def ) CREATE-WORD parse-locals-definition ;
2008-03-16 03:43:00 -04:00
2008-06-08 16:32:55 -04:00
: (M::) ( -- word def )
2008-05-01 17:23:11 -04:00
CREATE-METHOD
[ parse-locals-definition ] with-method-definition ;
2007-09-20 18:09:08 -04:00
2008-08-15 00:35:19 -04:00
: parsed-lambda ( accum form -- accum )
2008-05-07 09:48:51 -04:00
in-lambda? get [ parsed ] [ lambda-rewrite over push-all ] if ;
2007-09-20 18:09:08 -04:00
PRIVATE>
2008-05-07 09:48:51 -04:00
: [| parse-lambda parsed-lambda ; parsing
2007-09-20 18:09:08 -04:00
: [let
"|" expect parse-bindings
2008-05-07 09:48:51 -04:00
\ ] (parse-lambda) <let> parsed-lambda ; parsing
2008-03-19 22:16:09 -04:00
: [let*
"|" expect parse-bindings*
2008-05-07 09:48:51 -04:00
\ ] (parse-lambda) <let*> parsed-lambda ; parsing
2007-09-20 18:09:08 -04:00
: [wlet
"|" expect parse-wbindings
2008-05-07 09:48:51 -04:00
\ ] (parse-lambda) <wlet> parsed-lambda ; parsing
2007-09-20 18:09:08 -04:00
2008-02-26 19:40:32 -05:00
: :: (::) define ; parsing
2008-03-16 03:43:00 -04:00
: M:: (M::) define ; parsing
2008-02-26 19:40:32 -05:00
: MACRO:: (::) define-macro ; parsing
2007-09-20 18:09:08 -04:00
2008-04-27 02:46:38 -04:00
: MEMO:: (::) define-memoized ; parsing
2007-09-20 18:09:08 -04:00
<PRIVATE
! Pretty-printing locals
SYMBOL: |
: pprint-var ( var -- )
#! Prettyprint a read/write local as its writer, just like
#! in the input syntax: [| x! | ... x 3 + x! ]
dup local-reader? [
"local-writer" word-prop
] when pprint-word ;
: pprint-vars ( vars -- ) [ pprint-var ] each ;
M: lambda pprint*
<flow
\ [| pprint-word
2008-03-19 22:16:09 -04:00
dup vars>> pprint-vars
2007-09-20 18:09:08 -04:00
\ | pprint-word
2008-03-19 22:16:09 -04:00
f <inset body>> pprint-elements block>
2007-09-20 18:09:08 -04:00
\ ] pprint-word
block> ;
2008-03-19 22:16:09 -04:00
: pprint-let ( let word -- )
pprint-word
[ body>> ] [ bindings>> ] bi
2007-09-20 18:09:08 -04:00
\ | pprint-word
t <inset
<block
2008-03-19 22:16:09 -04:00
[ <block >r pprint-var r> pprint* block> ] assoc-each
2007-09-20 18:09:08 -04:00
block>
\ | pprint-word
<block pprint-elements block>
2008-03-19 22:16:09 -04:00
block>
2007-09-20 18:09:08 -04:00
\ ] pprint-word ;
2008-03-19 22:16:09 -04:00
M: let pprint* \ [let pprint-let ;
M: wlet pprint* \ [wlet pprint-let ;
M: let* pprint* \ [let* pprint-let ;
2007-09-20 18:09:08 -04:00
2008-05-10 19:09:05 -04:00
PREDICATE: lambda-word < word "lambda" word-prop >boolean ;
2007-09-20 18:09:08 -04:00
M: lambda-word definer drop \ :: \ ; ;
M: lambda-word definition
2008-03-19 22:16:09 -04:00
"lambda" word-prop body>> ;
2007-09-20 18:09:08 -04:00
2008-05-28 19:17:58 -04:00
M: lambda-word reset-word
2008-06-30 04:57:00 -04:00
[ call-next-method ] [ f "lambda" set-word-prop ] bi ;
2008-05-28 19:17:58 -04:00
2008-05-10 19:09:05 -04:00
INTERSECTION: lambda-macro macro lambda-word ;
2007-09-20 18:09:08 -04:00
M: lambda-macro definer drop \ MACRO:: \ ; ;
M: lambda-macro definition
2008-03-19 22:16:09 -04:00
"lambda" word-prop body>> ;
2008-02-26 19:40:32 -05:00
2008-05-28 19:17:58 -04:00
M: lambda-macro reset-word
2008-10-07 18:18:49 -04:00
[ call-next-method ] [ f "lambda" set-word-prop ] bi ;
2008-05-28 19:17:58 -04:00
2008-05-10 19:09:05 -04:00
INTERSECTION: lambda-method method-body lambda-word ;
2008-02-26 19:40:32 -05:00
M: lambda-method definer drop \ M:: \ ; ;
M: lambda-method definition
2008-03-19 22:16:09 -04:00
"lambda" word-prop body>> ;
2007-09-20 18:09:08 -04:00
2008-05-28 19:17:58 -04:00
M: lambda-method reset-word
2008-11-05 19:59:58 -05:00
[ call-next-method ] [ f "lambda" set-word-prop ] bi ;
2008-05-28 19:17:58 -04:00
2008-05-10 19:09:05 -04:00
INTERSECTION: lambda-memoized memoized lambda-word ;
M: lambda-memoized definer drop \ MEMO:: \ ; ;
M: lambda-memoized definition
"lambda" word-prop body>> ;
2008-05-28 19:17:58 -04:00
M: lambda-memoized reset-word
2008-10-17 17:54:45 -04:00
[ call-next-method ] [ f "lambda" set-word-prop ] bi ;
2008-05-28 19:17:58 -04:00
2008-03-05 17:00:34 -05:00
: method-stack-effect ( method -- effect )
2008-03-19 22:16:09 -04:00
dup "lambda" word-prop vars>>
2008-03-04 23:44:46 -05:00
swap "method-generic" word-prop stack-effect
2008-08-29 03:14:22 -04:00
dup [ out>> ] when
2008-02-26 19:40:32 -05:00
<effect> ;
M: lambda-method synopsis*
2008-03-05 17:00:34 -05:00
dup dup dup definer.
2008-06-18 06:58:16 -04:00
"method-class" word-prop pprint-word
"method-generic" word-prop pprint-word
2008-02-26 19:40:32 -05:00
method-stack-effect effect>string comment. ;
2007-09-20 18:09:08 -04:00
PRIVATE>