! Copyright (C) 2009 Slava Pestov. ! See http://factorcode.org/license.txt for BSD license. USING: accessors arrays assocs combinators.short-circuit continuations fry kernel namespaces quotations sequences sets generalizations slots locals.types splitting math locals.rewrite.closures generic words combinators locals smalltalk.ast smalltalk.compiler.lexenv smalltalk.compiler.assignment smalltalk.compiler.return smalltalk.selectors smalltalk.classes ; IN: smalltalk.compiler GENERIC: compile-ast ( lexenv ast -- quot ) M: object compile-ast nip 1quotation ; M: self compile-ast drop self>> 1quotation ; ERROR: unbound-local name ; M: ast-name compile-ast name>> swap lookup-reader ; : compile-arguments ( lexenv ast -- quot ) arguments>> [ compile-ast ] with map [ ] join ; : compile-new ( lexenv ast -- quot ) [ receiver>> compile-ast ] [ compile-arguments ] 2bi [ new ] 3append ; : compile-ifTrue:ifFalse: ( lexenv ast -- quot ) [ receiver>> compile-ast ] [ compile-arguments ] 2bi [ if ] 3append ; M: ast-message-send compile-ast dup selector>> { { "ifTrue:ifFalse:" [ compile-ifTrue:ifFalse: ] } { "new" [ compile-new ] } [ drop [ compile-arguments ] [ receiver>> compile-ast ] [ nip selector>> selector>generic ] 2tri [ append ] dip suffix ] } case ; M: ast-cascade compile-ast [ receiver>> compile-ast ] [ messages>> [ [ compile-arguments \ dip ] [ selector>> selector>generic ] bi [ ] 3sequence ] with map unclip-last [ [ [ drop ] append ] map ] dip suffix cleave>quot ] 2bi append ; M: ast-return compile-ast [ value>> compile-ast ] [ drop return>> 1quotation ] 2bi [ continue-with ] 3append ; : (compile-sequence) ( lexenv asts -- quot ) [ drop [ nil ] ] [ [ compile-ast ] with map [ drop ] join ] if-empty ; : block-lexenv ( block -- lexenv ) [ [ arguments>> ] [ temporaries>> ] bi append ] [ body>> [ assigned-locals ] map concat unique ] bi '[ dup dup _ key? [ ] [ ] if ] H{ } map>assoc dup [ nip local-reader? ] assoc-filter [ ] assoc-map swap >>local-writers swap >>local-readers ; : lookup-block-vars ( vars lexenv -- seq ) local-readers>> '[ _ at ] map ; : make-temporaries ( block lexenv -- quot ) [ temporaries>> ] dip lookup-block-vars [ [ f ] swap suffix ] map [ ] join ; :: compile-sequence ( lexenv block -- vars quot ) lexenv block block-lexenv lexenv-union :> lexenv block arguments>> lexenv lookup-block-vars lexenv block body>> (compile-sequence) block lexenv make-temporaries prepend ; M: ast-sequence compile-ast compile-sequence nip ; GENERIC: contains-blocks? ( obj -- ? ) M: ast-block contains-blocks? drop t ; M: object contains-blocks? drop f ; M: array contains-blocks? [ contains-blocks? ] any? ; M: array compile-ast dup contains-blocks? [ [ [ compile-ast ] with map [ ] join ] [ length ] bi '[ @ _ narray ] ] [ call-next-method ] if ; GENERIC: compile-assignment ( lexenv name -- quot ) M: ast-name compile-assignment name>> swap lookup-writer ; M: ast-assignment compile-ast [ value>> compile-ast [ dup ] ] [ name>> compile-assignment ] 2bi 3append ; M: ast-block compile-ast compile-sequence '[ _ ] ; :: (compile-method-body) ( lexenv block -- lambda ) lexenv block compile-sequence [ lexenv self>> suffix ] dip ; : compile-method-body ( lexenv block -- quot ) [ [ (compile-method-body) ] [ arguments>> length 1 + ] bi ] 2keep make-return ; : compile-method ( lexenv ast-method -- ) [ [ class>> ] [ name>> selector>generic ] bi* create-method ] [ body>> compile-method-body ] 2bi define ; : ( class -- lexenv ) swap >>class "self" >>self "^" >>return ; M: ast-class compile-ast nip [ [ name>> ] [ superclass>> ] [ ivars>> ] tri define-class ] [ methods>> ] bi [ compile-method ] with each [ nil ] ; ERROR: no-word name ; M: ast-foreign compile-ast nip [ class>> dup ":" split1 lookup [ ] [ no-word ] ?if ] [ name>> ] bi define-foreign [ nil ] ; : compile-smalltalk ( statement -- quot ) [ empty-lexenv ] dip [ compile-sequence nip 0 ] 2keep make-return ;