bend-python 0.1.0__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,218 @@
1
+ import Base
2
+
3
+ # A borrowed Python object, scoped to one exported call. The C shim checks every
4
+ # handle before use. Never store a handle for use by a later Python call.
5
+ type Object is Data:
6
+ PyObject{id: U32}
7
+
8
+ type Call is Type:
9
+ PyCall{args: List<Object>, kwargs: Object}
10
+
11
+ # The low-level API preserves Python objects, including identity and cycles.
12
+ # Native calls hold an invocation arena; these effects run with Python attached.
13
+ def export(name: String, function: Call -> IO(Object), release_gil: Bool) -> IO(Unit):
14
+ import "./python.c"
15
+
16
+ def require_no_kwargs(kwargs: Object) -> IO(Unit):
17
+ import "./python.c"
18
+
19
+ def to_u32(value: Object) -> IO(U32):
20
+ import "./python.c"
21
+
22
+ def from_u32(value: U32) -> IO(Object):
23
+ import "./python.c"
24
+
25
+ def to_f32(value: Object) -> IO(F32):
26
+ import "./python.c"
27
+
28
+ def from_f32(value: F32) -> IO(Object):
29
+ import "./python.c"
30
+
31
+ def to_string(value: Object) -> IO(String):
32
+ import "./python.c"
33
+
34
+ def from_string(value: String) -> IO(Object):
35
+ import "./python.c"
36
+
37
+ def to_bool(value: Object) -> IO(Bool):
38
+ import "./python.c"
39
+
40
+ def from_bool(value: Bool) -> IO(Object):
41
+ import "./python.c"
42
+
43
+ def get_item(value: Object, key: Object) -> IO(Object):
44
+ import "./python.c"
45
+
46
+ def set_item(value: Object, key: Object, item: Object) -> IO(Unit):
47
+ import "./python.c"
48
+
49
+ def getattr(value: Object, name: String) -> IO(Object):
50
+ import "./python.c"
51
+
52
+ def call(function: Object, args: Object, kwargs: Object) -> IO(Object):
53
+ import "./python.c"
54
+
55
+ def builtins(name: String) -> IO(Object):
56
+ import "./python.c"
57
+
58
+ def none() -> IO(Object):
59
+ import "./python.c"
60
+
61
+ def empty_dict() -> IO(Object):
62
+ import "./python.c"
63
+
64
+ def tuple(values: List<Object>) -> IO(Object):
65
+ import "./python.c"
66
+
67
+ def list(values: List<Object>) -> IO(Object):
68
+ import "./python.c"
69
+
70
+ def len(value: Object) -> IO(Nat):
71
+ import "./python.c"
72
+
73
+ # Exact, unlike U32.from_nat, which wraps lengths and counts past 2^32.
74
+ def from_nat(value: Nat) -> IO(Object):
75
+ import "./python.c"
76
+
77
+ def type_error(-A: Type, message: String) -> IO(A):
78
+ import "./python.c"
79
+
80
+ # Python truthiness (bool(value)), including __bool__ and __len__.
81
+ def truthy(value: Object) -> IO(Bool):
82
+ import "./python.c"
83
+
84
+ # Bytes of any C-contiguous buffer (bytes, bytearray, memoryview, ...), each a
85
+ # U32 in range(256).
86
+ def to_bytes(value: Object) -> IO(List<U32>):
87
+ import "./python.c"
88
+
89
+ # A bytes object; a value outside range(256) raises ValueError.
90
+ def from_bytes(values: List<U32>) -> IO(Object):
91
+ import "./python.c"
92
+
93
+ # importlib.import_module(name), e.g. "operator" or "collections.abc".
94
+ def import_module(name: String) -> IO(Object):
95
+ import "./python.c"
96
+
97
+ # Common Python operations are assembled here from the small effect boundary.
98
+ def invoke(function: Object, args: List<Object>) -> IO(Object):
99
+ do IO<Object>:
100
+ positional : Object <- tuple(args)
101
+ keywords : Object <- empty_dict()
102
+ call(function, positional, keywords)
103
+
104
+ def construct(name: String, args: List<Object>) -> IO(Object):
105
+ do IO<Object>:
106
+ function : Object <- builtins(name)
107
+ invoke(function, args)
108
+
109
+ def fill_dict(entries: List<Pair(Object, Object)>, +target: Object) -> IO(Object):
110
+ match entries:
111
+ case []:
112
+ IO.pure(Object, target)
113
+ case (key, value) <> tail:
114
+ do IO<Object>:
115
+ set_item(target, key, value)
116
+ fill_dict(tail, target)
117
+
118
+ def dict(entries: List<Pair(Object, Object)>) -> IO(Object):
119
+ do IO<Object>:
120
+ target : Object <- empty_dict()
121
+ fill_dict(entries, target)
122
+
123
+ # Total argument-list helpers remain pure and can be used in checked laws.
124
+ def arity(args: List<Object>) -> Nat:
125
+ match args:
126
+ case []:
127
+ 0n
128
+ case _ <> tail:
129
+ 1n+arity(tail)
130
+
131
+ def argument(args: List<Object>, index: Nat) -> Maybe<Object>:
132
+ match args index:
133
+ case [] _:
134
+ None{}
135
+ case value <> _ 0n:
136
+ Some{value}
137
+ case _ <> tail 1n+pred:
138
+ argument(tail, pred)
139
+
140
+ def singleton(args: List<Object>) -> Maybe<Object>:
141
+ match args:
142
+ case [value]:
143
+ Some{value}
144
+ case _:
145
+ None{}
146
+
147
+ def pair(args: List<Object>) -> Maybe<Pair(Object, Object)>:
148
+ match args:
149
+ case [left, right]:
150
+ Some{(left, right)}
151
+ case _:
152
+ None{}
153
+
154
+ # Checked extraction is shared by the typed adapters; its pure singleton/pair
155
+ # branches are the ones specified by LAWS.bend and discharged in PROOF.bend.
156
+ def require_singleton(value: Maybe<Object>) -> IO(Object):
157
+ match value:
158
+ case Some{item}:
159
+ IO.pure(Object, item)
160
+ case None{}:
161
+ type_error(Object, "expected exactly one positional argument")
162
+
163
+ def require_pair(value: Maybe<Pair(Object, Object)>) -> IO(Pair(Object, Object)):
164
+ match value:
165
+ case Some{items}:
166
+ IO.pure(Pair(Object, Object), items)
167
+ case None{}:
168
+ type_error(Pair(Object, Object), "expected exactly two positional arguments")
169
+
170
+ def unary(request: Call) -> IO(Object):
171
+ match request:
172
+ case PyCall{args, kwargs}:
173
+ do IO<Object>:
174
+ require_no_kwargs(kwargs)
175
+ require_singleton(singleton(args))
176
+
177
+ def binary(request: Call) -> IO(Pair(Object, Object)):
178
+ match request:
179
+ case PyCall{args, kwargs}:
180
+ do IO<Pair(Object, Object)>:
181
+ require_no_kwargs(kwargs)
182
+ require_pair(pair(args))
183
+
184
+ # Template arguments are specialized at compile time, leaving a captureless
185
+ # callback that may safely be invoked repeatedly by the native runtime.
186
+ def invoke_unary(~A: Type, ~decode: Object -> IO(A), ~encode: A -> IO(Object),
187
+ ~f: A -> A, request: Call) -> IO(Object):
188
+ do IO<Object>:
189
+ value : Object <- unary(request)
190
+ x : A <- decode(value)
191
+ encode(f(x))
192
+
193
+ def invoke_binary_u32_values(~f: U32 -> U32 -> U32, values: Pair(Object, Object)) -> IO(Object):
194
+ (left, right) = values
195
+ do IO<Object>:
196
+ x : U32 <- to_u32(left)
197
+ y : U32 <- to_u32(right)
198
+ from_u32(f(x, y))
199
+
200
+ def invoke_binary_u32(~f: U32 -> U32 -> U32, request: Call) -> IO(Object):
201
+ do IO<Object>:
202
+ values : Pair(Object, Object) <- binary(request)
203
+ invoke_binary_u32_values(~f, values)
204
+
205
+ def export_u32(~f: U32 -> U32, name: String, release_gil: Bool) -> IO(Unit):
206
+ export(name, invoke_unary(~U32, ~to_u32, ~from_u32, ~f), release_gil)
207
+
208
+ def export_f32(~f: F32 -> F32, name: String, release_gil: Bool) -> IO(Unit):
209
+ export(name, invoke_unary(~F32, ~to_f32, ~from_f32, ~f), release_gil)
210
+
211
+ def export_string(~f: String -> String, name: String, release_gil: Bool) -> IO(Unit):
212
+ export(name, invoke_unary(~String, ~to_string, ~from_string, ~f), release_gil)
213
+
214
+ def export_bool(~f: Bool -> Bool, name: String, release_gil: Bool) -> IO(Unit):
215
+ export(name, invoke_unary(~Bool, ~to_bool, ~from_bool, ~f), release_gil)
216
+
217
+ def export_binary_u32(~f: U32 -> U32 -> U32, name: String, release_gil: Bool) -> IO(Unit):
218
+ export(name, invoke_binary_u32(~f), release_gil)