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