diff --git a/extra/python/ffi/ffi.factor b/extra/python/ffi/ffi.factor index a9c394a6a7..b12fa5c2bf 100644 --- a/extra/python/ffi/ffi.factor +++ b/extra/python/ffi/ffi.factor @@ -71,6 +71,9 @@ FUNCTION: int PyList_Size ( PyObject* t ) ; FUNCTION: c-string PyModule_GetName ( PyObject* module ) ; FUNCTION: PyObject* PyModule_GetDict ( PyObject* module ) ; +! Callables +FUNCTION: int PyCallable_Check ( PyObject* obj ) ; + ! Objects FUNCTION: PyObject* PyObject_CallObject ( PyObject* callable, PyObject* args ) ; diff --git a/extra/python/python-tests.factor b/extra/python/python-tests.factor index 7bf73f413e..7351a6f3f2 100644 --- a/extra/python/python-tests.factor +++ b/extra/python/python-tests.factor @@ -6,7 +6,7 @@ USING: fry kernel math namespaces - python python.ffi python.stdlib.builtin python.stdlib.sys + python python.ffi sequences strings tools.test ; IN: python.tests @@ -116,31 +116,3 @@ SYMBOLS: year month day ; [ t ] [ "os" import PyModule_GetDict dup Py_IncRef &Py_DecRef py-dict-size 100 > ] py-test - -! Reference counting tests -[ 2 ] [ 3 getrefcount >factor ] py-test - -[ -2 ] [ - H{ { "foo" 33 } { "bar" 44 } } >py - [ "foo" py-dict-get-item-string getrefcount >factor ] - [ - '[ - 500 [ _ "foo" py-dict-get-item-string drop ] times - ] with-destructors - ] - [ "foo" py-dict-get-item-string getrefcount >factor ] tri - -] py-test - -[ -2 ] [ - "abcd" >py <1py-tuple> - [ 0 py-tuple-get-item getrefcount >factor ] - [ - [ 100 [ swap 0 py-tuple-get-item drop ] with times ] with-destructors - ] - [ 0 py-tuple-get-item getrefcount >factor ] tri - -] py-test - -! Tests for builtins -[ 10 ] [ 10 range >factor length ] py-test - -[ t ] [ "os" import "getpid" getattr callable >factor ] py-test diff --git a/extra/python/python.factor b/extra/python/python.factor index c5467d415d..54016efcef 100644 --- a/extra/python/python.factor +++ b/extra/python/python.factor @@ -107,21 +107,20 @@ ERROR: python-error type message ; [ PyUnicodeUCS2_FromString ] if ; ! Data marshalling to Python +: array>py-tuple ( arr -- py-tuple ) + [ length dup ] keep + [ rot py-tuple-set-item ] with each-index ; + GENERIC: (>py) ( obj -- obj' ) M: string (>py) utf8>py-unicode ; M: math:fixnum (>py) PyLong_FromLong ; M: math:float (>py) PyFloat_FromDouble ; - -M: array (>py) - [ length dup ] [ [ (>py) ] map ] bi - [ rot py-tuple-set-item ] with each-index ; - +M: array (>py) [ (>py) ] map array>py-tuple ; M: hashtable (>py) swap dupd [ swapd [ (>py) ] [ (>py) ] bi* py-dict-set-item ] with assoc-each ; -! ! I'll make a fast-path for this M: word (>py) name>> (>py) ; : >py ( obj -- py-obj ) diff --git a/extra/python/stdlib/builtin/builtin.factor b/extra/python/stdlib/builtin/builtin.factor deleted file mode 100644 index cc070aa307..0000000000 --- a/extra/python/stdlib/builtin/builtin.factor +++ /dev/null @@ -1,26 +0,0 @@ -USING: alien arrays kernel namespaces python ; -IN: python.stdlib.builtin - -py-initialize - -SYMBOL: builtin - -builtin [ "__builtin__" import ] initialize - -: simple-call ( arg func-name -- return ) - builtin get swap getattr swap <1py-tuple> call-object ; - -: repr ( alien/factor -- py-str ) - dup alien? [ >py ] unless "repr" simple-call ; - -: range ( n -- py-list ) - >py "range" simple-call ; - -: dir ( obj -- py-list ) - "dir" simple-call ; - -: type ( obj -- py-obj ) - "type" simple-call ; - -: callable ( obj -- py-obj ) - "callable" simple-call ; diff --git a/extra/python/stdlib/sys/sys.factor b/extra/python/stdlib/sys/sys.factor deleted file mode 100644 index 14657e9666..0000000000 --- a/extra/python/stdlib/sys/sys.factor +++ /dev/null @@ -1,10 +0,0 @@ -USING: kernel namespaces python ; -IN: python.stdlib.sys - -py-initialize - -SYMBOL: sys -sys [ "sys" import ] initialize - -: getrefcount ( alien -- py-int ) - <1py-tuple> sys get "getrefcount" getattr swap call-object ; diff --git a/extra/python/syntax/syntax-tests.factor b/extra/python/syntax/syntax-tests.factor new file mode 100644 index 0000000000..64b7d2f451 --- /dev/null +++ b/extra/python/syntax/syntax-tests.factor @@ -0,0 +1,81 @@ +USING: + assocs + destructors + fry + kernel + math + namespaces + python python.ffi python.syntax python.tests + sequences + tools.test ; +IN: python.syntax.tests + +! Define your own type conversions. +[ py-date>factor ] "date" py-type-dispatch get set-at + +! Importing functions +PY-FROM: os => + getpid ( -- y ) + system ( x -- y ) ; + +[ t ] [ getpid integer? ] unit-test + +! Automatic tuple unpacking +PY-FROM: os.path => + basename ( x -- x' ) + splitext ( x -- base ext ) ; + +[ "hello.doc" ] [ "/some/path/hello.doc" basename ] unit-test + +[ "hello" ".doc" ] [ "hello.doc" splitext ] unit-test + +PY-FROM: time => sleep ( n -- ) ; + +[ ] [ 0 sleep ] unit-test + +! Module variables are bound as zero-arg functions +PY-FROM: sys => path ( -- seq ) ; + +[ t ] [ path sequence? ] unit-test + +! Use the pipe functions to work on PyObjects. +PY-FROM: __builtin__ => + callable ( obj -- ? ) + int ( val -- s ) + len ( seq -- n ) + range ( n -- seq ) ; + +[ t ] [ path| |len| |int 5 > ] unit-test + +[ 10 ] [ 10 range| |len ] py-test + +! Callables +[ t ] [ + "os" import "getpid" getattr + [ |callable ] [ PyCallable_Check 1 = ] bi and +] py-test + +! Reference counting +PY-FROM: sys => getrefcount ( obj -- n ) ; + +[ 2 ] [ 3 |getrefcount ] py-test + +[ -2 ] [ + H{ { "foo" 33 } { "bar" 44 } } >py + [ "foo" py-dict-get-item-string |getrefcount ] + [ + '[ + 500 [ _ "foo" py-dict-get-item-string drop ] times + ] with-destructors + ] + [ "foo" py-dict-get-item-string |getrefcount ] tri - +] py-test + +[ -2 ] [ + "abcd" >py <1py-tuple> + [ 0 py-tuple-get-item |getrefcount ] + [ + [ 100 [ swap 0 py-tuple-get-item drop ] with times ] with-destructors + ] + [ 0 py-tuple-get-item |getrefcount ] tri - +] py-test diff --git a/extra/python/syntax/syntax.factor b/extra/python/syntax/syntax.factor new file mode 100644 index 0000000000..1068904d6a --- /dev/null +++ b/extra/python/syntax/syntax.factor @@ -0,0 +1,62 @@ +USING: + accessors + arrays + effects effects.parser + formatting + fry + generalizations + kernel + lexer + locals + namespaces + parser + python python.ffi + sequences sequences.generalizations + vocabs.parser + words ; +IN: python.syntax + +py-initialize + +SYMBOL: current-module + +: call-or-eval ( args obj -- ret ) + dup PyCallable_Check 1 = [ swap call-object ] [ nip ] if ; + +: factor>factor-quot ( py-function effect -- quot ) + [ in>> length ] [ out>> length ] bi swapd '[ + _ narray >py _ call-or-eval >factor + _ [ 1 = [ 1array ] when ] [ firstn ] bi + ] ; + +: factor>py-quot ( py-function effect -- quot ) + in>> length swap '[ _ narray >py _ call-or-eval ] ; + +: py>factor-quot ( py-function effect -- quot ) + [ in>> length ] [ out>> length ] bi swapd '[ + _ narray array>py-tuple _ call-or-eval >factor + _ [ 1 = [ 1array ] when ] [ firstn ] bi + ] ; + +: py>py-quot ( py-function effect -- quot ) + in>> length swap '[ _ narray array>py-tuple _ call-or-eval ] ; + +:: make-function ( basename format effect quot -- ) + basename format sprintf create-in + current-module get basename getattr + effect quot [ define-inline ] bi ; inline + +:: add-function ( function effect -- ) + function "%s" effect [ factor>factor-quot ] make-function + function "|%s" effect [ py>factor-quot ] make-function + function "|%s|" effect in>> { "ret" } [ py>py-quot ] make-function + function "%s|" effect in>> { "ret" } [ factor>py-quot ] make-function + ; inline + +: parse-python-word ( -- ) + scan-token dup ";" = [ drop ] [ + scan-effect add-function parse-python-word + ] if ; inline recursive + +SYNTAX: PY-FROM: + scan-token import current-module set "=>" expect parse-python-word ; inline