1 ! Copyright (C) 2009 Slava Pestov.
2 ! See http://factorcode.org/license.txt for BSD license.
3 USING: accessors arrays assocs combinators.short-circuit
4 continuations fry kernel namespaces quotations sequences sets
5 generalizations slots locals.types splitting math
6 locals.rewrite.closures generic words combinators locals smalltalk.ast
7 smalltalk.compiler.lexenv smalltalk.compiler.assignment
8 smalltalk.compiler.return smalltalk.selectors smalltalk.classes ;
11 GENERIC: compile-ast ( lexenv ast -- quot )
13 M: object compile-ast nip 1quotation ;
15 M: self compile-ast drop self>> 1quotation ;
17 ERROR: unbound-local name ;
19 M: ast-name compile-ast name>> swap lookup-reader ;
21 : compile-arguments ( lexenv ast -- quot )
22 arguments>> [ compile-ast ] with map [ ] join ;
24 : compile-ifTrue:ifFalse: ( lexenv ast -- quot )
25 [ receiver>> compile-ast ]
26 [ compile-arguments ] 2bi
29 M: ast-message-send compile-ast
31 { "ifTrue:ifFalse:" [ compile-ifTrue:ifFalse: ] }
35 [ receiver>> compile-ast ]
36 [ nip selector>> selector>generic ]
37 2tri [ append ] dip suffix
41 M: ast-cascade compile-ast
42 [ receiver>> compile-ast ]
45 [ compile-arguments \ dip ]
46 [ selector>> selector>generic ] bi
49 unclip-last [ [ [ drop ] append ] map ] dip suffix
53 M: ast-return compile-ast
54 [ value>> compile-ast ] [ drop return>> 1quotation ] 2bi
55 [ continue-with ] 3append ;
57 : (compile-sequence) ( lexenv asts -- quot )
59 [ compile-ast ] with map [ drop ] join
62 : block-lexenv ( block -- lexenv )
63 [ [ arguments>> ] [ temporaries>> ] bi append ]
64 [ body>> [ assigned-locals ] map concat unique ] bi
72 [ nip local-reader? ] assoc-filter
73 [ <local-writer> ] assoc-map
74 <lexenv> swap >>local-writers swap >>local-readers ;
76 : lookup-block-vars ( vars lexenv -- seq )
77 local-readers>> '[ _ at ] map ;
79 : make-temporaries ( block lexenv -- quot )
80 [ temporaries>> ] dip lookup-block-vars
81 [ <def> [ f ] swap suffix ] map [ ] join ;
83 :: compile-sequence ( lexenv block -- vars quot )
84 lexenv block block-lexenv lexenv-union :> lexenv
85 block arguments>> lexenv lookup-block-vars
86 lexenv block body>> (compile-sequence) block lexenv make-temporaries prepend ;
88 M: ast-sequence compile-ast
89 compile-sequence nip ;
91 GENERIC: contains-blocks? ( obj -- ? )
93 M: ast-block contains-blocks? drop t ;
95 M: object contains-blocks? drop f ;
97 M: array contains-blocks? [ contains-blocks? ] any? ;
100 dup contains-blocks? [
101 [ [ compile-ast ] with map [ ] join ] [ length ] bi
103 ] [ call-next-method ] if ;
105 GENERIC: compile-assignment ( lexenv name -- quot )
107 M: ast-name compile-assignment name>> swap lookup-writer ;
109 M: ast-assignment compile-ast
110 [ value>> compile-ast [ dup ] ] [ name>> compile-assignment ] 2bi 3append ;
112 M: ast-block compile-ast
113 compile-sequence <lambda> '[ _ ] ;
115 :: (compile-method-body) ( lexenv block -- lambda )
116 lexenv block compile-sequence
117 [ lexenv self>> suffix ] dip <lambda> ;
119 : compile-method-body ( lexenv block -- quot )
120 [ [ (compile-method-body) ] [ arguments>> length 1+ ] bi ] 2keep
123 : compile-method ( lexenv ast-method -- )
124 [ [ class>> ] [ name>> selector>generic ] bi* create-method ]
125 [ body>> compile-method-body ]
128 : <class-lexenv> ( class -- lexenv )
129 <lexenv> swap >>class "self" <local> >>self "^" <local> >>return ;
131 M: ast-class compile-ast
134 [ name>> ] [ superclass>> ] [ ivars>> ] tri
135 define-class <class-lexenv>
138 [ compile-method ] with each
141 ERROR: no-word name ;
143 M: ast-foreign compile-ast
145 [ class>> dup ":" split1 lookup [ ] [ no-word ] ?if ]
146 [ name>> ] bi define-foreign
149 : compile-smalltalk ( statement -- quot )
150 [ empty-lexenv ] dip [ compile-sequence nip 0 ]