python.syntax: new way to bind python functions to factor words and updated tests

this way avoids binding literal alien values inside the words which is
just wrong. the hardcoded alien addresses goes "out of sync" when
factor is restarded and causes crashes.
db4
Björn Lindqvist 2014-10-27 13:41:03 +01:00 committed by Doug Coleman
parent f0b07540d3
commit 584e9c5ce2
2 changed files with 38 additions and 99 deletions

View File

@ -1,63 +1,43 @@
USING: accessors arrays assocs continuations destructors destructors.private
fry io.files.temp kernel math namespaces python python.ffi python.objects
python.syntax sequences sets splitting tools.test unicode.categories ;
fry io.files.temp kernel math namespaces python python.ffi
python.modules.__builtin__ python.modules.argparse python.modules.datetime
python.modules.os python.modules.os.path python.modules.sys
python.modules.time python.objects python.syntax sets splitting tools.test
unicode.categories ;
QUALIFIED-WITH: sequences s
IN: python.syntax.tests
: py-test ( result quot -- )
'[ _ with-destructors ] unit-test ; inline
! py-importing functions
PY-FROM: os =>
getpid ( -- y )
system ( x -- y ) ;
[ t ] [ getpid py> integer? ] unit-test
{ t } [ getpid py> integer? ] py-test
! Automatic tuple unpacking
PY-FROM: os.path =>
basename ( x -- x' )
splitext ( x -- base ext ) ;
[ "hello.doc" ] [ "/some/path/hello.doc" >py basename py> ] unit-test
[ "hello.doc" ] [ "/some/path/hello.doc" >py basename py> ] py-test
[ { "hello" ".doc" } ] [
"hello.doc" >py splitext 2array [ py> ] map
] unit-test
"hello.doc" >py splitext 2array [ py> ] s:map
] py-test
PY-FROM: time => sleep ( n -- ) ;
[ ] [ 0 >py sleep ] unit-test
[ ] [ 0 >py sleep ] py-test
! Module variables are bound as zero-arg functions
PY-FROM: sys => path ( -- seq ) argv ( -- seq ) ;
[ t ] [ $path py> s:sequence? ] py-test
[ t ] [ $path py> sequence? ] unit-test
[ t ] [ $path len int py> 5 > ] py-test
PY-FROM: __builtin__ =>
callable ( obj -- ? )
dir ( obj -- seq )
int ( val -- s )
len ( seq -- n )
open ( name mode -- file )
range ( n -- seq )
repr ( obj -- str ) ;
[ t ] [ $path len int py> 5 > ] unit-test
[ 10 ] [ 10 >py range len py> ] unit-test
[ 10 ] [ 10 >py range len py> ] py-test
! Callables
[ t ] [
"os" py-import "getpid" getattr
[ callable ] [ PyCallable_Check 1 = ] bi and
] unit-test
] py-test
! Reference counting
PY-FROM: sys => getrefcount ( obj -- n ) ;
[ 1 ] [ 3 <py-tuple> getrefcount py> ] py-test
[ 2 ] [ 3 <py-tuple> getrefcount py> ] unit-test
[ -2 ] [
[ -1 ] [
H{ { "foo" 33 } { "bar" 44 } } >py
[ "foo" py-dict-get-item-string getrefcount py> ]
[
@ -68,7 +48,7 @@ PY-FROM: sys => getrefcount ( obj -- n ) ;
[ "foo" py-dict-get-item-string getrefcount py> ] tri -
] py-test
[ -2 ] [
[ -1 ] [
"abcd" >py <1py-tuple>
[ 0 py-tuple-get-item getrefcount py> ]
[
@ -80,36 +60,22 @@ PY-FROM: sys => getrefcount ( obj -- n ) ;
{ t } [
6 <py-tuple>
[ getrefcount py> 1 - ]
[ always-destructors get [ alien>> = ] with count ] bi =
[ always-destructors get [ alien>> = ] with s:count ] bi =
] py-test
PY-METHODS: file =>
close ( self -- )
fileno ( self -- n )
tell ( self -- n ) ;
[ t ] [
"python-file" temp-file >py "wb" >py open
[ tell ] [ fileno ] [ close ] tri
[ py> integer? ] bi@ and
] py-test
PY-METHODS: str =>
lower ( 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 py>
] py-test
[ { "hello" "=" "there" } ] [
"hello=there" >py "=" >py partition 3array [ py> ] map
"hello=there" >py "=" >py partition 3array [ py> ] s:map
] py-test
! Introspection
@ -122,49 +88,28 @@ PY-METHODS: code =>
[ 1 ] [ $splitext $func_code $co_argcount py> ] py-test
! Change sys.path
PY-METHODS: list =>
append ( list obj -- )
remove ( list obj -- ) ;
[ t ] [
$path "test" >py [ append ] [ drop py> ] [ remove ] 2tri
"test" swap in?
] py-test
! setattr doesn't affect which objects $words are referencing.
PY-FROM: sys => platform ( -- x ) ;
[ t ] [
$platform "sys" py-import "platform" "tjaba" >py setattr $platform =
] py-test
! Support for kwargs
PY-FROM: datetime => timedelta ( ** -- timedelta ) ;
[ "datetime.timedelta(4, 10800)" ] [
H{ { "hours" 99 } } >py timedelta repr py>
] py-test
! Kwargs in methods
PY-FROM: argparse => ArgumentParser ( -- self ) ;
PY-METHODS: ArgumentParser =>
add_argument ( self name ** -- )
format_help ( self -- str ) ;
[ t ] [
[
ArgumentParser dup
"--foo" >py H{ { "help" "badger" } } >py add_argument
format_help py>
] with-destructors [ blank? ] trim " " split "badger" swap in?
] with-destructors [ blank? ] s:trim " " split "badger" swap in?
] py-test
! Can you pass a callback written in factor to a python function?
PY-FROM: wsgiref.simple_server => make_server ( iface port callback -- httpd ) ;
{ t } [
[ 987 >py basename ] [ traceback>> ] recover length 0 >
] unit-test
[ 987 >py basename ] [ traceback>> ] recover s:length 0 >
] py-test
! Test if exceptions leak references. If so, the test will leak a few
! hundred megs of memory. Enough to be noticed but not to slow down
@ -182,11 +127,7 @@ PY-FROM: wsgiref.simple_server => make_server ( iface port callback -- httpd ) ;
] times
] unit-test
! Working with types
PY-METHODS: obj =>
__name__ ( self -- n ) ;
PY-QUALIFIED-FROM: types => UnicodeType ( -- ) ;
{ "unicode" } [
@ -194,7 +135,6 @@ PY-QUALIFIED-FROM: types => UnicodeType ( -- ) ;
] py-test
! Make callbacks
PY-QUALIFIED-FROM: __builtin__ =>
None ( -- )
map ( func seq -- seq' )
@ -205,14 +145,16 @@ PY-QUALIFIED-FROM: __builtin__ =>
] py-test
: double-fun ( -- alien )
[ drop first 2 * ] quot>py-callback ;
[ drop s:first 2 * ] quot>py-callback ;
{ V{ 2 4 16 2 4 68 } } [
double-fun [ { 1 2 8 1 2 34 } >py __builtin__:map py> ] with-quot>py-cfunction
double-fun [
{ 1 2 8 1 2 34 } >py __builtin__:map py>
] with-quot>py-cfunction
] py-test
: reduce-func ( -- alien )
[ drop first2 + ] quot>py-callback ;
[ drop s:first2 + ] quot>py-callback ;
{ 48 } [
reduce-func [

View File

@ -1,6 +1,6 @@
USING: accessors arrays combinators effects effects.parser fry generalizations
kernel lexer math namespaces parser python python.ffi python.objects sequences
sequences.generalizations vocabs.parser words ;
kernel lexer locals math namespaces parser python python.ffi python.objects
sequences sequences.generalizations vocabs.parser words ;
IN: python.syntax
<PRIVATE
@ -29,9 +29,9 @@ SYMBOL: current-context
[ '[ py-tuple>array _ firstn ] ]
} case ;
: make-function-quot ( alien effect -- quot )
: make-function-quot ( obj-quot effect -- quot )
[ in>> gather-args-quot ] [ out>> unpack-value-quot ] bi
swapd '[ @ _ -rot call-object-full @ ] ;
swapd '[ @ @ -rot call-object-full @ ] ;
: make-factor-words ( module name prefix? -- call-word obj-word )
[ [ ":" glue ] [ ":$" glue ] 2bi ] [ nip dup "$" prepend ] if
@ -40,13 +40,10 @@ SYMBOL: current-context
: import-getattr ( module name -- alien )
[ py-import ] dip getattr ;
: make-creator-quots ( alien effect -- call-quot obj-quot )
[ '[ _ _ [ make-function-quot ] keep define-inline ] ]
[ drop '[ [ _ ] { } { "obj" } <effect> define-inline ] ] 2bi ; inline
: add-function ( effect module name prefix? -- )
[ make-factor-words ] [ drop import-getattr ] 3bi [ rot ] dip swap
make-creator-quots bi* ;
:: add-function ( name effect module prefix? -- )
module name prefix? make-factor-words :> ( call-word obj-word )
obj-word module name '[ _ _ import-getattr ] ( -- o ) define-inline
call-word obj-word def>> effect make-function-quot effect define-inline ;
: make-method-quot ( name effect -- quot )
[ in>> 1 tail gather-args-quot ] [ out>> unpack-value-quot ] bi swapd
@ -65,11 +62,11 @@ SYMBOL: current-context
PRIVATE>
SYNTAX: PY-FROM: [
current-context get rot f add-function
current-context get f add-function
] scan-definitions ; inline
SYNTAX: PY-QUALIFIED-FROM: [
current-context get rot t add-function
current-context get t add-function
] scan-definitions ; inline
SYNTAX: PY-METHODS: [ add-method ] scan-definitions ; inline