diff --git a/extra/python/syntax/syntax-tests.factor b/extra/python/syntax/syntax-tests.factor index 43a92bf1c7..f37f405f64 100644 --- a/extra/python/syntax/syntax-tests.factor +++ b/extra/python/syntax/syntax-tests.factor @@ -1,5 +1,5 @@ USING: arrays assocs destructors fry kernel math namespaces python python.ffi -python.syntax python.tests sequences tools.test ; +python.syntax python.tests sequences sets tools.test ; IN: python.syntax.tests ! Importing functions @@ -24,20 +24,21 @@ PY-FROM: time => sleep ( n -- ) ; [ ] [ 0 >py sleep ] unit-test -! ! Module variables are bound as zero-arg functions +! Module variables are bound as zero-arg functions PY-FROM: sys => path ( -- seq ) ; -[ t ] [ path >factor sequence? ] unit-test +[ t ] [ $path >factor sequence? ] unit-test -! ! Use the pipe functions to work on PyObjects. PY-FROM: __builtin__ => callable ( obj -- ? ) - open ( name mode -- file ) + dir ( obj -- seq ) int ( val -- s ) len ( seq -- n ) - range ( n -- seq ) ; + open ( name mode -- file ) + range ( n -- seq ) + repr ( obj -- str ) ; -[ t ] [ path len int >factor 5 > ] unit-test +[ t ] [ $path len int >factor 5 > ] unit-test [ 10 ] [ 10 >py range len >factor ] unit-test @@ -79,16 +80,40 @@ PY-METHODS: file => [ t ] [ "testfile" >py "wb" >py open - [ ->tell ] [ ->fileno ] [ ->close ] tri + [ tell ] [ fileno ] [ close ] tri [ >factor integer? ] bi@ and ] py-test PY-METHODS: str => - title ( self -- self' ) + partition ( self sep -- bef sep aft ) startswith ( self str -- ? ) + title ( self -- self' ) zfill ( self n -- str' ) ; ! Method chaining [ t ] [ - "hello there" >py ->title 20 >py ->zfill "00" >py ->startswith >factor + "hello there" >py title 20 >py zfill "00" >py startswith >factor +] py-test + +[ { "hello" "=" "there" } ] [ + "hello=there" >py "=" >py partition 3array [ >factor ] map +] py-test + +! Introspection +PY-METHODS: func => + func_code ( func -- code ) ; + +PY-METHODS: code => + co_argcount ( code -- n ) ; + +[ 1 ] [ $splitext $func_code $co_argcount >factor ] py-test + +! Change sys.path +PY-METHODS: list => + append ( list obj -- ) + remove ( list obj -- ) ; + +[ t ] [ + $path "test" >py [ append ] [ drop >factor ] [ remove ] 2tri + "test" swap in? ] py-test diff --git a/extra/python/syntax/syntax.factor b/extra/python/syntax/syntax.factor index 5b69f31654..6749b9e19f 100644 --- a/extra/python/syntax/syntax.factor +++ b/extra/python/syntax/syntax.factor @@ -1,50 +1,57 @@ USING: accessors arrays effects effects.parser fry generalizations -kernel lexer locals math namespaces parser python python.ffi sequences +kernel lexer math namespaces parser python python.ffi sequences sequences.generalizations vocabs.parser words ; IN: python.syntax py-initialize -SYMBOL: current-module +SYMBOL: current-context -: call-or-eval ( args obj -- ret ) - dup PyCallable_Check 1 = [ swap call-object ] [ nip ] if ; - -:: add-function ( function effect -- ) - function create-in - effect [ in>> length ] [ out>> length ] bi - current-module get function getattr swap - '[ - _ narray array>py-tuple _ call-or-eval - _ [ 0 = [ drop 0 ] when ] keep - [ 1 = [ <1py-tuple> ] when ] keep - [ py-tuple>array ] dip firstn - ] effect define-inline ; inline - -: parse-python-word ( -- ) - scan-token dup ";" = [ drop ] [ - scan-effect add-function parse-python-word +: with-each-definition ( quot -- ) + scan-token dup ";" = [ 2drop ] [ + scan-effect rot [ call( tok eff -- ) ] keep with-each-definition ] if ; inline recursive -SYNTAX: PY-FROM: - scan-token import current-module set "=>" expect parse-python-word ; inline +: scan-definitions ( quot -- ) + scan-token current-context set "=>" expect with-each-definition ; inline -:: add-method ( attr effect -- ) - attr "->" prepend create-in - effect [ in>> length 1 - ] [ out>> length ] bi +: unpack-value ( alien -- * ) + [ 0 = [ drop 0 ] when ] keep + [ 1 = [ <1py-tuple> ] when ] keep + [ py-tuple>array ] dip firstn ; inline - '[ _ narray array>py-tuple swap attr getattr swap call-object - _ [ 1 = [ 1array ] when ] [ firstn ] bi ] +: make-function-quot ( alien in out -- quot ) + swapd '[ _ narray array>py-tuple _ swap call-object _ unpack-value ] ; +: function-callable ( name alien effect -- ) + [ create-in ] 2dip + [ [ in>> length ] [ out>> length ] bi make-function-quot ] keep + define-inline ; inline - ! '[ attr getattr _ narray array>py-tuple call-object - ! _ [ 1 = [ 1array ] when ] [ firstn ] bi ] - effect define-inline ; +: function-object ( name alien -- ) + [ "$" prepend create-in ] [ '[ _ ] ] bi* + { } { "obj" } define-inline ; inline -: parse-python-method ( -- ) - scan-token dup ";" = [ drop ] [ - scan-effect add-method parse-python-method - ] if ; inline recursive +: add-function ( name effect -- ) + [ dup current-context get import swap getattr 2dup ] dip + function-callable function-object ; inline -SYNTAX: PY-METHODS: - scan-token drop "=>" expect parse-python-method ; inline +SYNTAX: PY-FROM: [ add-function ] scan-definitions ; inline + +: make-method-quot ( name in out -- ret ) + swapd '[ + _ narray array>py-tuple swap + _ getattr swap call-object + _ unpack-value + ] ; + +: method-object ( name -- ) + [ "$" prepend create-in ] [ '[ _ getattr ] ] bi + { "obj" } { "obj'" } define-inline ; + +: add-method ( name effect -- ) + [ dup dup create-in swap ] dip + [ [ in>> length 1 - ] [ out>> length ] bi make-method-quot ] keep + define-inline method-object ; + +SYNTAX: PY-METHODS: [ add-method ] scan-definitions ; inline