[ ast-cascade boa ]
if ;
+! Methods return self by default
+: <ast-method> ( class arguments body -- method )
+ self suffix <ast-block> ast-method boa ;
+
TUPLE: symbol { name string } ;
MEMO: intern ( name -- symbol ) symbol boa ;
\ No newline at end of file
: compile-arguments ( lexenv ast -- quot )
arguments>> [ compile-ast ] with map [ ] join ;
-M: ast-message-send compile-ast
- [ compile-arguments ]
+: compile-ifTrue:ifFalse: ( lexenv ast -- quot )
[ receiver>> compile-ast ]
- [ nip selector>> selector>generic ]
- 2tri [ append ] dip suffix ;
+ [ compile-arguments ] 2bi
+ [ if ] 3append ;
+
+M: ast-message-send compile-ast
+ dup selector>> {
+ { "ifTrue:ifFalse:" [ compile-ifTrue:ifFalse: ] }
+ [
+ drop
+ [ compile-arguments ]
+ [ receiver>> compile-ast ]
+ [ nip selector>> selector>generic ]
+ 2tri [ append ] dip suffix
+ ]
+ } case ;
M: ast-cascade compile-ast
[ receiver>> compile-ast ]
] 2bi append ;
M: ast-return compile-ast
- value>> compile-ast
- [ return-continuation get continue-with ] append ;
+ [ value>> compile-ast ] [ drop return>> 1quotation ] 2bi
+ [ continue-with ] 3append ;
: (compile-sequence) ( lexenv asts -- quot )
[ drop [ nil ] ] [
[ lexenv self>> suffix ] dip <lambda> ;
: compile-method-body ( lexenv block -- quot )
- [ [ (compile-method-body) ] [ arguments>> length 1+ ] bi ] keep
+ [ [ (compile-method-body) ] [ arguments>> length 1+ ] bi ] 2keep
make-return ;
: compile-method ( lexenv ast-method -- )
2bi define ;
: <class-lexenv> ( class -- lexenv )
- <lexenv> swap >>class "self" <local-reader> >>self ;
+ <lexenv> swap >>class "self" <local> >>self "^" <local> >>return ;
M: ast-class compile-ast
nip
[ nil ] ;
: compile-smalltalk ( statement -- quot )
- [ [ empty-lexenv ] dip compile-sequence nip 0 ]
- keep make-return ;
\ No newline at end of file
+ [ empty-lexenv ] dip [ compile-sequence nip 0 ]
+ 2keep make-return ;
\ No newline at end of file
! self: word or f for top-level forms
! class: class word or f for top-level forms
! method: generic word or f for top-level forms
-TUPLE: lexenv local-readers local-writers self class method ;
+TUPLE: lexenv local-readers local-writers self return class method ;
: <lexenv> ( -- lexenv ) lexenv new ; inline
[ [ local-readers>> ] bi@ assoc-union >>local-readers ]
[ [ local-writers>> ] bi@ assoc-union >>local-writers ]
[ [ self>> ] either? >>self ]
+ [ [ return>> ] either? >>return ]
[ [ class>> ] either? >>class ]
[ [ method>> ] either? >>method ]
} 2cleave ;
--- /dev/null
+USING: smalltalk.parser smalltalk.compiler.return tools.test ;
+
+[ t ] [ "(i <= 1) ifTrue: [^1] ifFalse: [^((Fib new i:(i-1)) compute + (Fib new i:(i-2)) compute)]" parse-smalltalk need-return-continuation? ] unit-test
\ No newline at end of file
! Copyright (C) 2009 Slava Pestov.
! See http://factorcode.org/license.txt for BSD license.
USING: accessors arrays combinators.short-circuit continuations
-fry generalizations kernel locals.rewrite.closures namespaces
-sequences smalltalk.ast ;
+fry generalizations kernel locals locals.types locals.rewrite.closures
+namespaces make sequences smalltalk.ast ;
IN: smalltalk.compiler.return
SYMBOL: return-continuation
{
[ receiver>> need-return-continuation? ]
[ arguments>> need-return-continuation? ]
- } 1&& ;
+ } 1|| ;
M: ast-cascade need-return-continuation?
{
[ receiver>> need-return-continuation? ]
[ messages>> need-return-continuation? ]
- } 1&& ;
+ } 1|| ;
M: ast-message need-return-continuation?
arguments>> need-return-continuation? ;
M: object need-return-continuation? drop f ;
-: make-return ( quot n block -- quot )
- need-return-continuation? [
- '[
- [
- _ _ ncurry
- [ return-continuation set ] prepose callcc1
- ] with-scope
- ]
- ] [ drop ] if
- rewrite-closures first ;
\ No newline at end of file
+:: make-return ( quot n lexenv block -- quot )
+ block need-return-continuation? [
+ quot clone [ lexenv return>> <def> '[ _ ] prepend ] change-body
+ n '[ _ _ ncurry callcc1 ]
+ ] [ quot ] if rewrite-closures first ;
\ No newline at end of file
IN: smalltalk.eval.tests
-USING: smalltalk.eval tools.test io.streams.string ;
+USING: smalltalk.eval tools.test io.streams.string kernel ;
[ 3 ] [ "1+2" eval-smalltalk ] unit-test
[ "HAI" ] [ "(1<10) ifTrue:['HAI'] ifFalse:['BAI']" eval-smalltalk ] unit-test
[ 6 "5\n6\n" ] [ [ "[:x|x print] value: 5; value: 6" eval-smalltalk ] with-string-writer ] unit-test
[ 5 ] [ "|x| x:=5. x" eval-smalltalk ] unit-test
[ 11 ] [ "[:i| |x| x:=5. i+x] value: 6" eval-smalltalk ] unit-test
+[ t ] [ "class Blah [method foo [5]]. Blah new foo" eval-smalltalk tuple? ] unit-test
+[ 196418 ] [ "vocab:smalltalk/eval/fib.st" eval-smalltalk-file ] unit-test
\ No newline at end of file
--- /dev/null
+class Fib [
+ |i|
+ method i: newI [i:=newI].
+ method compute [
+ (i <= 1)
+ ifTrue: [^1]
+ ifFalse: [^((Fib new i:(i-1)) compute + (Fib new i:(i-2)) compute)]
+ ].
+].
+
+[(Fib new i: 26) compute] time
\ No newline at end of file
IN: smalltalk.parser.tests
-USING: smalltalk.parser smalltalk.ast peg.ebnf tools.test accessors
+USING: smalltalk.parser smalltalk.ast
+peg.ebnf tools.test accessors
io.files io.encodings.ascii kernel ;
EBNF: test-Character
[ ] [ "class Foo []. Tests blah " parse-smalltalk drop ] unit-test
-[ ] [ "vocab:smalltalk/parser/test.st" ascii file-contents parse-smalltalk drop ] unit-test
+[ ] [ "vocab:smalltalk/parser/test.st" ascii file-contents parse-smalltalk drop ] unit-test
\ No newline at end of file
OptionalWhiteSpace "["
ExecutableCode:code
"]"
- => [[ header first2 code <ast-block> ast-method boa ]]
+ => [[ header first2 code <ast-method> ]]
ClassDeclaration = OptionalWhiteSpace "class" OptionalWhiteSpace Identifier:name
OptionalWhiteSpace