]> gitweb.factorcode.org Git - factor.git/blob - extra/python/python.factor
core: Rename iota to <iota> so we can have TUPLE: iota ... ; instead of TUPLE: iota...
[factor.git] / extra / python / python.factor
1 USING: alien alien.c-types alien.data arrays assocs command-line fry
2 hashtables init io.encodings.utf8 kernel namespaces
3 python.errors python.ffi python.objects sequences
4 specialized-arrays strings vectors ;
5 IN: python
6 QUALIFIED: math
7
8 ERROR: python-error type message traceback ;
9
10 SPECIALIZED-ARRAY: void*
11
12 ! Borrowed from unix.utilities
13 : strings>alien ( strings encoding -- array )
14     '[ _ malloc-string ] void*-array{ } map-as f suffix ;
15
16 ! Initialization and finalization
17 : py-initialize ( -- )
18     Py_IsInitialized [
19         Py_Initialize
20         ! Encoding must be 8bit on Windows I think, so
21         ! native-string-encoding (utf16n) doesn't work.
22         (command-line) [ length ] [ utf8 strings>alien ] bi 0 PySys_SetArgvEx
23     ] unless ;
24
25 : py-finalize ( -- )
26     Py_IsInitialized [ Py_Finalize ] when ;
27
28 ! Importing
29 : py-import ( str -- module )
30     PyImport_ImportModule check-new-ref ;
31
32 ! Unicodes
33 : py-ucs-size ( -- n )
34     "maxunicode" PySys_GetObject PyInt_AsLong 0xffff = 2 4 ? ;
35
36 : py-unicode>utf8 ( uni -- str )
37     py-ucs-size 4 =
38     [ PyUnicodeUCS4_AsUTF8String ]
39     [ PyUnicodeUCS2_AsUTF8String ] if (check-ref)
40     PyString_AsString (check-ref) ;
41
42 : utf8>py-unicode ( str -- uni )
43     py-ucs-size 4 =
44     [ PyUnicodeUCS4_FromString ]
45     [ PyUnicodeUCS2_FromString ] if ;
46
47 ! Data marshalling to Python
48 : array>py-tuple ( arr -- py-tuple )
49     [ length <py-tuple> dup ] keep
50     [ rot py-tuple-set-item ] with each-index ;
51
52 : vector>py-list ( vec -- py-list )
53     [ length <py-list> dup ] keep
54     [ rot py-list-set-item ] with each-index ;
55
56 : py-tuple>array ( py-tuple -- arr )
57     dup py-tuple-size <iota> [ py-tuple-get-item ] with map ;
58
59 : py-list>vector ( py-list -- vector )
60     dup py-list-size <iota> [ py-list-get-item ] with V{ } map-as ;
61
62 DEFER: >py
63
64 GENERIC: >py ( obj -- py-obj )
65 M: string >py
66     utf8>py-unicode check-new-ref ;
67 M: math:fixnum >py
68     PyLong_FromLong check-new-ref ;
69 M: math:float >py
70     PyFloat_FromDouble check-new-ref ;
71 M: array >py
72     [ >py ] map array>py-tuple ;
73 M: hashtable >py
74     <py-dict> swap dupd [
75         swapd [ >py ] bi@ py-dict-set-item
76     ] with assoc-each ;
77 M: vector >py
78     [ >py ] map vector>py-list ;
79 M: f >py
80     drop <none> ;
81
82 ! Data marshalling to Factor
83 SYMBOL: py-type-dispatch
84
85 DEFER: py>
86
87 : init-py-type-dispatch ( -- table )
88     H{
89         { "NoneType" [ drop f ] }
90         { "bool" [ PyObject_IsTrue 1 = ] }
91         { "dict" [ PyDict_Items (check-ref) py> >hashtable ] }
92         { "int" [ PyInt_AsLong ] }
93         { "list" [ py-list>vector [ py> ] map ] }
94         { "long" [ PyLong_AsLong ] }
95         { "str" [ PyString_AsString (check-ref) ] }
96         { "tuple" [ py-tuple>array [ py> ] map ] }
97         { "unicode" [ py-unicode>utf8 ] }
98     } clone ;
99
100 py-type-dispatch [ init-py-type-dispatch ] initialize
101
102 ERROR: missing-type type ;
103
104 : py> ( py-obj -- obj )
105     dup "__class__" getattr "__name__" getattr PyString_AsString
106     py-type-dispatch get ?at [ call( x -- x ) ] [ missing-type ] if ;
107
108 ! Callbacks
109 : quot>py-callback ( quot: ( args kw -- ret ) -- alien )
110     '[
111         [ nip ] dip
112         [ [ py> ] [ { } ] if* ] bi@ @ >py
113     ] PyCallback ; inline
114
115 : with-quot>py-cfunction ( alien quot -- )
116     '[ <py-cfunction> @ ] with-callback ; inline
117
118 [ py-initialize ] "python" add-startup-hook
119 [ py-finalize ] "python" add-shutdown-hook