158 lines
		
	
	
		
			4.4 KiB
		
	
	
	
		
			Factor
		
	
	
			
		
		
	
	
			158 lines
		
	
	
		
			4.4 KiB
		
	
	
	
		
			Factor
		
	
	
| ! Copyright (C) 2009 Slava Pestov.
 | |
| ! See http://factorcode.org/license.txt for BSD license.
 | |
| USING: accessors arrays assocs combinators continuations fry
 | |
| generic kernel locals locals.types math quotations sequences
 | |
| sequences.generalizations sets smalltalk.ast smalltalk.classes
 | |
| smalltalk.compiler.assignment smalltalk.compiler.lexenv
 | |
| smalltalk.compiler.return smalltalk.selectors splitting vocabs
 | |
| words ;
 | |
| 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 fast-set ] bi
 | |
|     '[
 | |
|         dup dup _ in?
 | |
|         [ <local-reader> ]
 | |
|         [ <local> ]
 | |
|         if
 | |
|     ] H{ } map>assoc
 | |
|     dup
 | |
|     [ nip local-reader? ] assoc-filter
 | |
|     [ <local-writer> ] assoc-map
 | |
|     <lexenv> 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
 | |
|     [ <def> [ 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 <lambda> '[ _ ] ;
 | |
| 
 | |
| :: (compile-method-body) ( lexenv block -- lambda )
 | |
|     lexenv block compile-sequence
 | |
|     [ lexenv self>> suffix ] dip <lambda> ;
 | |
| 
 | |
| : 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> ( class -- lexenv )
 | |
|     <lexenv> swap >>class "self" <local> >>self "^" <local> >>return ;
 | |
| 
 | |
| M: ast-class compile-ast
 | |
|     nip
 | |
|     [
 | |
|         [ name>> ] [ superclass>> ] [ ivars>> ] tri
 | |
|         define-class <class-lexenv>
 | |
|     ]
 | |
|     [ methods>> ] bi
 | |
|     [ compile-method ] with each
 | |
|     [ nil ] ;
 | |
| 
 | |
| ERROR: no-word name ;
 | |
| 
 | |
| M: ast-foreign compile-ast
 | |
|     nip
 | |
|     [ class>> dup ":" split1 lookup-word [ ] [ no-word ] ?if ]
 | |
|     [ name>> ] bi define-foreign
 | |
|     [ nil ] ;
 | |
| 
 | |
| : compile-smalltalk ( statement -- quot )
 | |
|     [ empty-lexenv ] dip [ compile-sequence nip 0 ]
 | |
|     2keep make-return ;
 |