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
parent
f0b07540d3
commit
584e9c5ce2
|
@ -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 [
|
||||
|
|
|
@ -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
|
||||
|
|
Loading…
Reference in New Issue