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 USING: accessors arrays assocs continuations destructors destructors.private
fry io.files.temp kernel math namespaces python python.ffi python.objects fry io.files.temp kernel math namespaces python python.ffi
python.syntax sequences sets splitting tools.test unicode.categories ; 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 IN: python.syntax.tests
: py-test ( result quot -- ) : py-test ( result quot -- )
'[ _ with-destructors ] unit-test ; inline '[ _ with-destructors ] unit-test ; inline
! py-importing functions { t } [ getpid py> integer? ] py-test
PY-FROM: os =>
getpid ( -- y )
system ( x -- y ) ;
[ t ] [ getpid py> integer? ] unit-test
! Automatic tuple unpacking ! Automatic tuple unpacking
PY-FROM: os.path => [ "hello.doc" ] [ "/some/path/hello.doc" >py basename py> ] py-test
basename ( x -- x' )
splitext ( x -- base ext ) ;
[ "hello.doc" ] [ "/some/path/hello.doc" >py basename py> ] unit-test
[ { "hello" ".doc" } ] [ [ { "hello" ".doc" } ] [
"hello.doc" >py splitext 2array [ py> ] map "hello.doc" >py splitext 2array [ py> ] s:map
] unit-test ] py-test
PY-FROM: time => sleep ( n -- ) ; [ ] [ 0 >py sleep ] py-test
[ ] [ 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 ) 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__ => [ 10 ] [ 10 >py range len py> ] py-test
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
! Callables ! Callables
[ t ] [ [ t ] [
"os" py-import "getpid" getattr "os" py-import "getpid" getattr
[ callable ] [ PyCallable_Check 1 = ] bi and [ callable ] [ PyCallable_Check 1 = ] bi and
] unit-test ] py-test
! Reference counting ! Reference counting
PY-FROM: sys => getrefcount ( obj -- n ) ; [ 1 ] [ 3 <py-tuple> getrefcount py> ] py-test
[ 2 ] [ 3 <py-tuple> getrefcount py> ] unit-test [ -1 ] [
[ -2 ] [
H{ { "foo" 33 } { "bar" 44 } } >py H{ { "foo" 33 } { "bar" 44 } } >py
[ "foo" py-dict-get-item-string getrefcount 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 - [ "foo" py-dict-get-item-string getrefcount py> ] tri -
] py-test ] py-test
[ -2 ] [ [ -1 ] [
"abcd" >py <1py-tuple> "abcd" >py <1py-tuple>
[ 0 py-tuple-get-item getrefcount py> ] [ 0 py-tuple-get-item getrefcount py> ]
[ [
@ -80,36 +60,22 @@ PY-FROM: sys => getrefcount ( obj -- n ) ;
{ t } [ { t } [
6 <py-tuple> 6 <py-tuple>
[ getrefcount py> 1 - ] [ getrefcount py> 1 - ]
[ always-destructors get [ alien>> = ] with count ] bi = [ always-destructors get [ alien>> = ] with s:count ] bi =
] py-test ] py-test
PY-METHODS: file =>
close ( self -- )
fileno ( self -- n )
tell ( self -- n ) ;
[ t ] [ [ t ] [
"python-file" temp-file >py "wb" >py open "python-file" temp-file >py "wb" >py open
[ tell ] [ fileno ] [ close ] tri [ tell ] [ fileno ] [ close ] tri
[ py> integer? ] bi@ and [ py> integer? ] bi@ and
] py-test ] 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 ! Method chaining
[ t ] [ [ t ] [
"hello there" >py title 20 >py zfill "00" >py startswith py> "hello there" >py title 20 >py zfill "00" >py startswith py>
] py-test ] py-test
[ { "hello" "=" "there" } ] [ [ { "hello" "=" "there" } ] [
"hello=there" >py "=" >py partition 3array [ py> ] map "hello=there" >py "=" >py partition 3array [ py> ] s:map
] py-test ] py-test
! Introspection ! Introspection
@ -122,49 +88,28 @@ PY-METHODS: code =>
[ 1 ] [ $splitext $func_code $co_argcount py> ] py-test [ 1 ] [ $splitext $func_code $co_argcount py> ] py-test
! Change sys.path ! Change sys.path
PY-METHODS: list =>
append ( list obj -- )
remove ( list obj -- ) ;
[ t ] [ [ t ] [
$path "test" >py [ append ] [ drop py> ] [ remove ] 2tri $path "test" >py [ append ] [ drop py> ] [ remove ] 2tri
"test" swap in? "test" swap in?
] py-test ] 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 ! Support for kwargs
PY-FROM: datetime => timedelta ( ** -- timedelta ) ;
[ "datetime.timedelta(4, 10800)" ] [ [ "datetime.timedelta(4, 10800)" ] [
H{ { "hours" 99 } } >py timedelta repr py> H{ { "hours" 99 } } >py timedelta repr py>
] py-test ] py-test
! Kwargs in methods ! Kwargs in methods
PY-FROM: argparse => ArgumentParser ( -- self ) ;
PY-METHODS: ArgumentParser =>
add_argument ( self name ** -- )
format_help ( self -- str ) ;
[ t ] [ [ t ] [
[ [
ArgumentParser dup ArgumentParser dup
"--foo" >py H{ { "help" "badger" } } >py add_argument "--foo" >py H{ { "help" "badger" } } >py add_argument
format_help py> format_help py>
] with-destructors [ blank? ] trim " " split "badger" swap in? ] with-destructors [ blank? ] s:trim " " split "badger" swap in?
] py-test ] 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 } [ { t } [
[ 987 >py basename ] [ traceback>> ] recover length 0 > [ 987 >py basename ] [ traceback>> ] recover s:length 0 >
] unit-test ] py-test
! Test if exceptions leak references. If so, the test will leak a few ! 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 ! 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 ] times
] unit-test ] unit-test
! Working with types ! Working with types
PY-METHODS: obj =>
__name__ ( self -- n ) ;
PY-QUALIFIED-FROM: types => UnicodeType ( -- ) ; PY-QUALIFIED-FROM: types => UnicodeType ( -- ) ;
{ "unicode" } [ { "unicode" } [
@ -194,7 +135,6 @@ PY-QUALIFIED-FROM: types => UnicodeType ( -- ) ;
] py-test ] py-test
! Make callbacks ! Make callbacks
PY-QUALIFIED-FROM: __builtin__ => PY-QUALIFIED-FROM: __builtin__ =>
None ( -- ) None ( -- )
map ( func seq -- seq' ) map ( func seq -- seq' )
@ -205,14 +145,16 @@ PY-QUALIFIED-FROM: __builtin__ =>
] py-test ] py-test
: double-fun ( -- alien ) : double-fun ( -- alien )
[ drop first 2 * ] quot>py-callback ; [ drop s:first 2 * ] quot>py-callback ;
{ V{ 2 4 16 2 4 68 } } [ { 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 ] py-test
: reduce-func ( -- alien ) : reduce-func ( -- alien )
[ drop first2 + ] quot>py-callback ; [ drop s:first2 + ] quot>py-callback ;
{ 48 } [ { 48 } [
reduce-func [ reduce-func [

View File

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