klongpy 0.7.0__py3-none-any.whl → 0.7.1__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.
- klongpy/__init__.py +0 -2
- klongpy/adverbs.py +84 -82
- klongpy/autograd.py +0 -9
- klongpy/backend.py +9 -142
- klongpy/backends/__init__.py +9 -77
- klongpy/backends/base.py +154 -5
- klongpy/backends/numpy_backend.py +2 -1
- klongpy/backends/registry.py +76 -0
- klongpy/backends/torch_backend.py +83 -31
- klongpy/cli.py +50 -7
- klongpy/core.py +113 -1094
- klongpy/db/sys_fn_db.py +3 -3
- klongpy/db/sys_fn_kvs.py +2 -4
- klongpy/dyads.py +203 -162
- klongpy/interpreter.py +32 -15
- klongpy/monads.py +99 -89
- klongpy/parser.py +328 -0
- klongpy/repl.py +2 -2
- klongpy/sys_fn.py +53 -15
- klongpy/sys_fn_ipc.py +4 -9
- klongpy/types.py +503 -0
- klongpy/writer.py +122 -0
- klongpy/ws/sys_fn_ws.py +5 -8
- {klongpy-0.7.0.dist-info → klongpy-0.7.1.dist-info}/METADATA +146 -95
- klongpy-0.7.1.dist-info/RECORD +52 -0
- klongpy-0.7.0.dist-info/RECORD +0 -48
- {klongpy-0.7.0.dist-info → klongpy-0.7.1.dist-info}/WHEEL +0 -0
- {klongpy-0.7.0.dist-info → klongpy-0.7.1.dist-info}/entry_points.txt +0 -0
- {klongpy-0.7.0.dist-info → klongpy-0.7.1.dist-info}/licenses/LICENSE +0 -0
- {klongpy-0.7.0.dist-info → klongpy-0.7.1.dist-info}/top_level.txt +0 -0
klongpy/parser.py
ADDED
|
@@ -0,0 +1,328 @@
|
|
|
1
|
+
"""
|
|
2
|
+
KlongPy parser and lexer functions.
|
|
3
|
+
|
|
4
|
+
This module contains all the parsing functions for the Klong language:
|
|
5
|
+
- Lexeme reading (numbers, strings, symbols, operators)
|
|
6
|
+
- List parsing
|
|
7
|
+
- Conditional expression parsing
|
|
8
|
+
- Comment handling
|
|
9
|
+
"""
|
|
10
|
+
import copy
|
|
11
|
+
|
|
12
|
+
from .types import (
|
|
13
|
+
KGSym, KGChar, KGOp, KGCond, KGCall, KGLambda,
|
|
14
|
+
reserved_fn_symbol_map,
|
|
15
|
+
safe_eq, is_symbolic, is_adverb
|
|
16
|
+
)
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
# Character matching utilities
|
|
20
|
+
|
|
21
|
+
def cmatch(t, i, c):
|
|
22
|
+
return i < len(t) and t[i] == c
|
|
23
|
+
|
|
24
|
+
|
|
25
|
+
def cmatch2(t, i, a, b):
|
|
26
|
+
return cmatch(t, i, a) and cmatch(t, i+1, b)
|
|
27
|
+
|
|
28
|
+
|
|
29
|
+
def cpeek(t, i):
|
|
30
|
+
return t[i] if i < len(t) else None
|
|
31
|
+
|
|
32
|
+
|
|
33
|
+
def cpeek2(t, i):
|
|
34
|
+
return t[i:i+2] if i < (len(t)-1) else None
|
|
35
|
+
|
|
36
|
+
|
|
37
|
+
class UnexpectedChar(Exception):
|
|
38
|
+
def __init__(self, t, i, c):
|
|
39
|
+
super().__init__(f"t: {t[i-10:i+10]} pos: {i} char: {c}")
|
|
40
|
+
|
|
41
|
+
|
|
42
|
+
class UnexpectedEOF(Exception):
|
|
43
|
+
def __init__(self, t, i):
|
|
44
|
+
self.t = t
|
|
45
|
+
self.i = i
|
|
46
|
+
super().__init__(f"t: {t[i-10:]} pos: {i}")
|
|
47
|
+
|
|
48
|
+
|
|
49
|
+
def cexpect(t, i, c):
|
|
50
|
+
if cmatch(t, i, c):
|
|
51
|
+
return i + 1
|
|
52
|
+
raise UnexpectedChar(t, i, c)
|
|
53
|
+
|
|
54
|
+
|
|
55
|
+
def cexpect2(t, i, a, b):
|
|
56
|
+
if cmatch(t, i, a) and cmatch(t, i+1, b):
|
|
57
|
+
return i + 2
|
|
58
|
+
raise UnexpectedChar(t, i, b)
|
|
59
|
+
|
|
60
|
+
|
|
61
|
+
# Comment handling
|
|
62
|
+
|
|
63
|
+
def read_shifted_comment(t, i=0):
|
|
64
|
+
while i < len(t):
|
|
65
|
+
c = t[i]
|
|
66
|
+
if c == '"':
|
|
67
|
+
i += 1
|
|
68
|
+
if not cmatch(t, i, '"'):
|
|
69
|
+
break
|
|
70
|
+
i += 1
|
|
71
|
+
return i
|
|
72
|
+
|
|
73
|
+
|
|
74
|
+
def read_sys_comment(t, i, a):
|
|
75
|
+
"""
|
|
76
|
+
.comment(x) [Comment]
|
|
77
|
+
|
|
78
|
+
Read and discard lines until the current line starts with the
|
|
79
|
+
string specified in "x". Also discard the line containing the
|
|
80
|
+
end-of-comment marker and return "x".
|
|
81
|
+
|
|
82
|
+
Example: .comment("end-of-comment")
|
|
83
|
+
this will be ignored
|
|
84
|
+
this, too: *%(*^#)&(#
|
|
85
|
+
end-of-comment
|
|
86
|
+
|
|
87
|
+
NOTE: this is handled in the parsing phase and is not a runtime function
|
|
88
|
+
"""
|
|
89
|
+
try:
|
|
90
|
+
j = t[i:].index(a)
|
|
91
|
+
while t[i+j+1:].startswith(a):
|
|
92
|
+
j += 1
|
|
93
|
+
return i + j + len(a)
|
|
94
|
+
except ValueError:
|
|
95
|
+
return RuntimeError("end of comment not found")
|
|
96
|
+
|
|
97
|
+
|
|
98
|
+
# Whitespace handling
|
|
99
|
+
|
|
100
|
+
def skip_space(t, i=0, ignore_newline=False):
|
|
101
|
+
"""
|
|
102
|
+
NOTE: a newline character translates to a semicolon in Klong,
|
|
103
|
+
except in functions, dictionaries, conditional expressions,
|
|
104
|
+
and lists. So
|
|
105
|
+
"""
|
|
106
|
+
while i < len(t) and (t[i].isspace() and (ignore_newline or t[i] != '\n')):
|
|
107
|
+
i += 1
|
|
108
|
+
return i
|
|
109
|
+
|
|
110
|
+
|
|
111
|
+
def skip(t, i=0, ignore_newline=False):
|
|
112
|
+
i = skip_space(t, i, ignore_newline=ignore_newline)
|
|
113
|
+
if cmatch2(t, i, ':', '"'):
|
|
114
|
+
i = read_shifted_comment(t, i+2)
|
|
115
|
+
i = skip(t, i)
|
|
116
|
+
return i
|
|
117
|
+
|
|
118
|
+
|
|
119
|
+
# Lexeme readers
|
|
120
|
+
|
|
121
|
+
def read_num(t, i=0):
|
|
122
|
+
p = i
|
|
123
|
+
use_float = False
|
|
124
|
+
if t[i] == '-':
|
|
125
|
+
i += 1
|
|
126
|
+
while i < len(t):
|
|
127
|
+
if t[i] == '.':
|
|
128
|
+
use_float = True
|
|
129
|
+
elif t[i] == 'e':
|
|
130
|
+
use_float = True
|
|
131
|
+
if cmatch(t, i+1, '-'):
|
|
132
|
+
i += 2
|
|
133
|
+
elif not t[i].isnumeric():
|
|
134
|
+
break
|
|
135
|
+
i += 1
|
|
136
|
+
return i, float(t[p:i]) if use_float else int(t[p:i])
|
|
137
|
+
|
|
138
|
+
|
|
139
|
+
def read_char(t, i):
|
|
140
|
+
i = cexpect2(t, i, '0', 'c')
|
|
141
|
+
if i >= len(t):
|
|
142
|
+
raise UnexpectedEOF(t, i)
|
|
143
|
+
return i+1, KGChar(t[i])
|
|
144
|
+
|
|
145
|
+
|
|
146
|
+
def read_sym(t, i=0, module=None):
|
|
147
|
+
p = i
|
|
148
|
+
while i < len(t) and is_symbolic(t[i]):
|
|
149
|
+
i += 1
|
|
150
|
+
x = t[p:i]
|
|
151
|
+
return i, reserved_fn_symbol_map.get(x) or KGSym(x if x.startswith('.') or module is None else f"{x}`{module}")
|
|
152
|
+
|
|
153
|
+
|
|
154
|
+
def read_op(t, i=0):
|
|
155
|
+
if cmatch2(t, i, '\\', '~') or cmatch2(t, i, '\\', '*'):
|
|
156
|
+
return i+2, KGOp(t[i:i+2], arity=0)
|
|
157
|
+
return i+1, KGOp(t[i:i+1], arity=0)
|
|
158
|
+
|
|
159
|
+
|
|
160
|
+
def read_string(t, i=0):
|
|
161
|
+
"""
|
|
162
|
+
".*" [String]
|
|
163
|
+
|
|
164
|
+
A string is (almost) any sequence of characters enclosed by
|
|
165
|
+
double quote characters. To include a double quote character in
|
|
166
|
+
a string, it has to be duplicated, so the above regex is not
|
|
167
|
+
entirely correct. A comment is a shifted string (see below).
|
|
168
|
+
Examples: ""
|
|
169
|
+
"hello, world"
|
|
170
|
+
"say ""hello""!"
|
|
171
|
+
|
|
172
|
+
Note: this comforms to the KG read_string impl.
|
|
173
|
+
perf tests show that the final join is fast for short strings
|
|
174
|
+
"""
|
|
175
|
+
r = []
|
|
176
|
+
while i < len(t):
|
|
177
|
+
c = t[i]
|
|
178
|
+
if c == '"':
|
|
179
|
+
i += 1
|
|
180
|
+
if not cmatch(t, i, '"'):
|
|
181
|
+
break
|
|
182
|
+
r.append(c)
|
|
183
|
+
i += 1
|
|
184
|
+
return i, "".join(r)
|
|
185
|
+
|
|
186
|
+
|
|
187
|
+
# Dictionary helper
|
|
188
|
+
|
|
189
|
+
def list_to_dict(a):
|
|
190
|
+
return {x[0]:x[1] for x in a}
|
|
191
|
+
|
|
192
|
+
|
|
193
|
+
# Lambda for copy operations (used in dict parsing)
|
|
194
|
+
copy_lambda = KGLambda(lambda x: copy.deepcopy(x))
|
|
195
|
+
|
|
196
|
+
|
|
197
|
+
def read_list(t, delim, i=0, module=None):
|
|
198
|
+
"""
|
|
199
|
+
Parse a list from string t starting at position i.
|
|
200
|
+
Returns a Python list (caller converts to array if needed).
|
|
201
|
+
|
|
202
|
+
L := '[' (C|L)* ']'
|
|
203
|
+
"""
|
|
204
|
+
arr = []
|
|
205
|
+
i = skip(t, i, ignore_newline=True)
|
|
206
|
+
while not cmatch(t, i, delim) and i < len(t):
|
|
207
|
+
i, q = kg_read(t, i, read_neg=True, ignore_newline=True, module=module)
|
|
208
|
+
if q is None:
|
|
209
|
+
break
|
|
210
|
+
if safe_eq(q, '['):
|
|
211
|
+
i, q = read_list(t, ']', i=i, module=module)
|
|
212
|
+
arr.append(q)
|
|
213
|
+
i = skip(t, i, ignore_newline=True)
|
|
214
|
+
if cmatch(t, i, delim):
|
|
215
|
+
i += 1
|
|
216
|
+
return i, arr
|
|
217
|
+
|
|
218
|
+
|
|
219
|
+
def kg_read(t, i, read_neg=False, ignore_newline=False, module=None):
|
|
220
|
+
"""
|
|
221
|
+
Read a Klong lexeme from string t starting at position i.
|
|
222
|
+
|
|
223
|
+
C := I | H | R | S | V | Y
|
|
224
|
+
"""
|
|
225
|
+
i = skip(t, i, ignore_newline=ignore_newline)
|
|
226
|
+
if i >= len(t):
|
|
227
|
+
return i, None
|
|
228
|
+
a = t[i]
|
|
229
|
+
if a == '\n':
|
|
230
|
+
a = ';'
|
|
231
|
+
if a in [';', '(', ')', '{', '}', ']']:
|
|
232
|
+
return i+1, a
|
|
233
|
+
elif cmatch2(t, i, '0', 'c'):
|
|
234
|
+
return read_char(t, i)
|
|
235
|
+
elif a.isnumeric() or (read_neg and (a == '-' and (i+1) < len(t) and t[i+1].isnumeric())):
|
|
236
|
+
return read_num(t, i)
|
|
237
|
+
elif a == '"':
|
|
238
|
+
return read_string(t, i+1)
|
|
239
|
+
elif a == ':' and (i+1 < len(t)):
|
|
240
|
+
aa = t[i+1]
|
|
241
|
+
if aa.isalpha() or aa == '.':
|
|
242
|
+
return read_sym(t, i=i+1, module=module)
|
|
243
|
+
elif aa.isnumeric() or aa == '"':
|
|
244
|
+
return kg_read(t, i+1, ignore_newline=ignore_newline, module=module)
|
|
245
|
+
elif aa == '{':
|
|
246
|
+
i, d = read_list(t, '}', i=i+2, module=module)
|
|
247
|
+
d = list_to_dict(d)
|
|
248
|
+
return i, KGCall(copy_lambda, args=d, arity=0)
|
|
249
|
+
elif aa == '[':
|
|
250
|
+
return i+2, ':['
|
|
251
|
+
elif aa == '|':
|
|
252
|
+
return i+2, ':|'
|
|
253
|
+
return i+2, KGOp(f":{aa}", arity=0)
|
|
254
|
+
elif safe_eq(a, '['):
|
|
255
|
+
return read_list(t, ']', i=i+1, module=module)
|
|
256
|
+
elif is_symbolic(a):
|
|
257
|
+
return read_sym(t, i, module=module)
|
|
258
|
+
return read_op(t, i)
|
|
259
|
+
|
|
260
|
+
|
|
261
|
+
def kg_read_array(t, i, backend, **kwargs):
|
|
262
|
+
"""
|
|
263
|
+
Read a value and convert lists to arrays using the provided backend.
|
|
264
|
+
|
|
265
|
+
This is a helper that wraps kg_read and handles list-to-array conversion,
|
|
266
|
+
centralizing the pattern used by the interpreter and eval_sys.
|
|
267
|
+
|
|
268
|
+
Parameters
|
|
269
|
+
----------
|
|
270
|
+
t : str
|
|
271
|
+
The string to read from.
|
|
272
|
+
i : int
|
|
273
|
+
Starting position in the string.
|
|
274
|
+
backend : BackendProvider
|
|
275
|
+
The backend to use for array conversion.
|
|
276
|
+
**kwargs
|
|
277
|
+
Additional arguments passed to kg_read (read_neg, ignore_newline, module).
|
|
278
|
+
|
|
279
|
+
Returns
|
|
280
|
+
-------
|
|
281
|
+
tuple
|
|
282
|
+
(new_position, value) where value is converted to an array if it was a list.
|
|
283
|
+
"""
|
|
284
|
+
i, a = kg_read(t, i, **kwargs)
|
|
285
|
+
if isinstance(a, list):
|
|
286
|
+
a = backend.kg_asarray(a)
|
|
287
|
+
return i, a
|
|
288
|
+
|
|
289
|
+
|
|
290
|
+
def read_cond(klong, t, i=0):
|
|
291
|
+
"""
|
|
292
|
+
# A conditional expression has two forms: :[e1;e2;e3] means "if
|
|
293
|
+
# e1 is true, evaluate to e2, else evaluate to e3".
|
|
294
|
+
# :[e1;e2:|e3;e4;e5] is short for :[e1;e2:[e3;e4;e5]], i.e. the
|
|
295
|
+
# ":|" acts as an "else-if" operator. There may be any number of
|
|
296
|
+
# ":|" operators in a conditional.
|
|
297
|
+
|
|
298
|
+
c := ':[' ( e ';' e ':|' )* e ';' e ';' e ']'
|
|
299
|
+
"""
|
|
300
|
+
r = []
|
|
301
|
+
i, n = klong._expr(t, i, ignore_newline=True)
|
|
302
|
+
r.append(n)
|
|
303
|
+
i = cexpect(t, i, ';')
|
|
304
|
+
i, n = klong._expr(t, i, ignore_newline=True)
|
|
305
|
+
r.append(n)
|
|
306
|
+
i = skip(t, i, ignore_newline=True)
|
|
307
|
+
if cmatch2(t, i, ':', '|'):
|
|
308
|
+
i, n = read_cond(klong, t, i+2)
|
|
309
|
+
r.append(n)
|
|
310
|
+
else:
|
|
311
|
+
i = cexpect(t, i, ';')
|
|
312
|
+
i, n = klong._expr(t, i, ignore_newline=True)
|
|
313
|
+
r.append(n)
|
|
314
|
+
i = skip(t, i, ignore_newline=True)
|
|
315
|
+
i = cexpect(t, i, ']')
|
|
316
|
+
return i, KGCond(r)
|
|
317
|
+
|
|
318
|
+
|
|
319
|
+
# Adverb peeking
|
|
320
|
+
|
|
321
|
+
def peek_adverb(t, i=0):
|
|
322
|
+
x = cpeek2(t, i)
|
|
323
|
+
if is_adverb(x):
|
|
324
|
+
return i+2, x
|
|
325
|
+
x = cpeek(t, i)
|
|
326
|
+
if is_adverb(x):
|
|
327
|
+
return i+1, x
|
|
328
|
+
return i, None
|
klongpy/repl.py
CHANGED
|
@@ -72,13 +72,13 @@ def append_pkg_resource_path_KLONGPATH() -> None:
|
|
|
72
72
|
os.environ['KLONGPATH'] = klongpath
|
|
73
73
|
|
|
74
74
|
|
|
75
|
-
def create_repl(debug: bool = False):
|
|
75
|
+
def create_repl(debug: bool = False, backend: Optional[str] = None, device: Optional[str] = None):
|
|
76
76
|
io_loop, io_thread, io_stop = setup_async_loop(debug=debug)
|
|
77
77
|
klong_loop, klong_thread, klong_stop = setup_async_loop(debug=debug)
|
|
78
78
|
|
|
79
79
|
append_pkg_resource_path_KLONGPATH()
|
|
80
80
|
|
|
81
|
-
klong = KlongInterpreter()
|
|
81
|
+
klong = KlongInterpreter(backend=backend, device=device)
|
|
82
82
|
shutdown_event = CallbackEvent()
|
|
83
83
|
klong['.system'] = {'ioloop': io_loop, 'klongloop': klong_loop, 'closeEvent': shutdown_event}
|
|
84
84
|
|
klongpy/sys_fn.py
CHANGED
|
@@ -12,23 +12,21 @@ from inspect import Parameter
|
|
|
12
12
|
import numpy
|
|
13
13
|
|
|
14
14
|
from .core import (KGChannel, KGChannelDir, KGLambda, KGSym, KlongException,
|
|
15
|
-
is_dict, is_empty, is_list,
|
|
15
|
+
bknp, is_dict, is_empty, is_list, kg_read_array, kg_write,
|
|
16
16
|
reserved_fn_args, reserved_fn_symbol_map, safe_eq, safe_inspect)
|
|
17
|
-
from .backend import to_numpy, get_default_backend, kg_asarray
|
|
18
17
|
|
|
19
18
|
|
|
20
|
-
def _to_display_value(x):
|
|
19
|
+
def _to_display_value(x, backend):
|
|
21
20
|
"""Convert backend tensors to numpy for cleaner display."""
|
|
22
|
-
backend = get_default_backend()
|
|
23
21
|
# Convert backend arrays (tensors) to numpy
|
|
24
22
|
if backend.is_backend_array(x):
|
|
25
|
-
return to_numpy(x)
|
|
23
|
+
return backend.to_numpy(x)
|
|
26
24
|
# Handle numpy arrays with tensors inside (object arrays)
|
|
27
25
|
if isinstance(x, numpy.ndarray) and x.dtype == object:
|
|
28
|
-
return numpy.array([_to_display_value(item) for item in x], dtype=object)
|
|
26
|
+
return numpy.array([_to_display_value(item, backend) for item in x], dtype=object)
|
|
29
27
|
# Handle lists with tensors
|
|
30
28
|
if isinstance(x, list):
|
|
31
|
-
return [_to_display_value(item) for item in x]
|
|
29
|
+
return [_to_display_value(item, backend) for item in x]
|
|
32
30
|
return x
|
|
33
31
|
|
|
34
32
|
|
|
@@ -63,11 +61,11 @@ def eval_sys_display(klong, x):
|
|
|
63
61
|
|
|
64
62
|
.d(x) [Display]
|
|
65
63
|
|
|
66
|
-
Display the object "x".
|
|
64
|
+
Display the object "x". Backend arrays are converted to numpy for cleaner output.
|
|
67
65
|
Use .bkd() for raw backend-specific display.
|
|
68
66
|
|
|
69
67
|
"""
|
|
70
|
-
x = _to_display_value(x)
|
|
68
|
+
x = _to_display_value(x, klong._backend)
|
|
71
69
|
r = kg_write(x, klong._backend, display=True)
|
|
72
70
|
klong['.sys.cout'].raw.write(r)
|
|
73
71
|
return r
|
|
@@ -303,11 +301,11 @@ def eval_sys_print(klong, x):
|
|
|
303
301
|
.p(x) [Print]
|
|
304
302
|
|
|
305
303
|
Pretty-print the object "x" (like Display) and then print a
|
|
306
|
-
newline sequence.
|
|
304
|
+
newline sequence. Backend arrays are converted to numpy for cleaner output.
|
|
307
305
|
Use .bkp() for raw backend-specific print.
|
|
308
306
|
|
|
309
307
|
"""
|
|
310
|
-
x = _to_display_value(x)
|
|
308
|
+
x = _to_display_value(x, klong._backend)
|
|
311
309
|
o = kg_write(x, klong._backend, display=True)
|
|
312
310
|
klong['.sys.cout'].raw.write(o+"\n")
|
|
313
311
|
return o
|
|
@@ -697,7 +695,7 @@ def eval_sys_random_number():
|
|
|
697
695
|
Return a random number x, such that 0 <= x < 1.
|
|
698
696
|
|
|
699
697
|
"""
|
|
700
|
-
return
|
|
698
|
+
return bknp.random.random()
|
|
701
699
|
|
|
702
700
|
|
|
703
701
|
def eval_sys_read(klong):
|
|
@@ -718,7 +716,7 @@ def eval_sys_read(klong):
|
|
|
718
716
|
f.at_eof = True
|
|
719
717
|
return None
|
|
720
718
|
else:
|
|
721
|
-
i,a =
|
|
719
|
+
i,a = kg_read_array(r, 0, klong._backend, module=klong.current_module())
|
|
722
720
|
f.raw.seek(k+i,0)
|
|
723
721
|
return a
|
|
724
722
|
|
|
@@ -753,7 +751,7 @@ def eval_sys_read_lines(klong):
|
|
|
753
751
|
f = klong['.sys.cin']
|
|
754
752
|
r = f.raw.readlines()
|
|
755
753
|
f.at_eof = True
|
|
756
|
-
return kg_asarray(r)
|
|
754
|
+
return klong._backend.kg_asarray(r)
|
|
757
755
|
|
|
758
756
|
|
|
759
757
|
def eval_sys_read_string(klong, x):
|
|
@@ -767,7 +765,8 @@ def eval_sys_read_string(klong, x):
|
|
|
767
765
|
forms.
|
|
768
766
|
|
|
769
767
|
"""
|
|
770
|
-
|
|
768
|
+
_, a = kg_read_array(x, 0, klong._backend, module=klong.current_module(), read_neg=True)
|
|
769
|
+
return a
|
|
771
770
|
|
|
772
771
|
|
|
773
772
|
def eval_sys_system(x):
|
|
@@ -853,6 +852,45 @@ def eval_sys_exit(x):
|
|
|
853
852
|
sys.exit(1)
|
|
854
853
|
|
|
855
854
|
|
|
855
|
+
def eval_sys_strict(klong):
|
|
856
|
+
"""
|
|
857
|
+
|
|
858
|
+
.strict() [Strict]
|
|
859
|
+
|
|
860
|
+
Enable strict mode for variable assignment (level 1).
|
|
861
|
+
In strict mode, functions cannot create new global variables
|
|
862
|
+
unless they are explicitly declared with the global: prefix.
|
|
863
|
+
|
|
864
|
+
Example:
|
|
865
|
+
.strict()
|
|
866
|
+
counter::0
|
|
867
|
+
increment::{counter::counter+1} :" ERROR"
|
|
868
|
+
increment::{[global:counter];counter::counter+1} :" OK"
|
|
869
|
+
|
|
870
|
+
"""
|
|
871
|
+
klong._context._strict_mode = 1
|
|
872
|
+
return 1
|
|
873
|
+
|
|
874
|
+
|
|
875
|
+
def eval_sys_unsafe(klong):
|
|
876
|
+
"""
|
|
877
|
+
|
|
878
|
+
.unsafe() [Unsafe]
|
|
879
|
+
|
|
880
|
+
Disable strict mode for variable assignment (level 0).
|
|
881
|
+
In unsafe mode, functions can create new global variables
|
|
882
|
+
without declaration (legacy behavior).
|
|
883
|
+
|
|
884
|
+
Example:
|
|
885
|
+
.unsafe()
|
|
886
|
+
f::{newvar::42} :" OK - creates global newvar"
|
|
887
|
+
f()
|
|
888
|
+
|
|
889
|
+
"""
|
|
890
|
+
klong._context._strict_mode = 0
|
|
891
|
+
return 0
|
|
892
|
+
|
|
893
|
+
|
|
856
894
|
def create_system_functions():
|
|
857
895
|
def _get_name(s):
|
|
858
896
|
i = s.index('.')
|
klongpy/sys_fn_ipc.py
CHANGED
|
@@ -8,10 +8,8 @@ import uuid
|
|
|
8
8
|
from asyncio import StreamReader, StreamWriter
|
|
9
9
|
from asyncio.exceptions import IncompleteReadError
|
|
10
10
|
|
|
11
|
-
import numpy as np
|
|
12
|
-
|
|
13
11
|
from klongpy.core import (KGCall, KGFn, KGFnWrapper, KGLambda, KGSym,
|
|
14
|
-
KlongException, get_fn_arity_str, is_list,
|
|
12
|
+
KlongException, KLONG_UNDEFINED, get_fn_arity_str, is_list,
|
|
15
13
|
reserved_fn_args, reserved_fn_symbols, reserved_fn_symbol_map)
|
|
16
14
|
|
|
17
15
|
|
|
@@ -1011,12 +1009,9 @@ def create_system_functions_ipc():
|
|
|
1011
1009
|
|
|
1012
1010
|
def create_system_var_ipc():
|
|
1013
1011
|
# populate the .srv.* handlers with undefined values
|
|
1014
|
-
# TODO: use real undefined value instead of np.inf
|
|
1015
1012
|
registry = {
|
|
1016
|
-
".srv.o":
|
|
1017
|
-
".srv.c":
|
|
1018
|
-
".srv.e":
|
|
1013
|
+
".srv.o": KLONG_UNDEFINED,
|
|
1014
|
+
".srv.c": KLONG_UNDEFINED,
|
|
1015
|
+
".srv.e": KLONG_UNDEFINED,
|
|
1019
1016
|
}
|
|
1020
1017
|
return registry
|
|
1021
|
-
|
|
1022
|
-
|