auto-editor 25.0.1__py3-none-any.whl → 25.2.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.
- auto_editor/__init__.py +1 -1
- auto_editor/__main__.py +3 -0
- auto_editor/edit.py +22 -18
- auto_editor/formats/fcp11.py +16 -26
- auto_editor/formats/fcp7.py +144 -74
- auto_editor/lang/libintrospection.py +10 -0
- auto_editor/lang/palet.py +140 -1240
- auto_editor/lang/stdenv.py +1190 -0
- auto_editor/lib/contracts.py +4 -0
- auto_editor/lib/data_structs.py +4 -2
- auto_editor/make_layers.py +14 -0
- auto_editor/render/subtitle.py +3 -1
- auto_editor/render/video.py +2 -19
- auto_editor/subcommands/palet.py +2 -0
- auto_editor/subcommands/repl.py +3 -2
- auto_editor/subcommands/test.py +3 -0
- auto_editor/timeline.py +1 -7
- auto_editor/utils/cmdkw.py +5 -11
- auto_editor/utils/types.py +1 -7
- {auto_editor-25.0.1.dist-info → auto_editor-25.2.0.dist-info}/METADATA +4 -4
- {auto_editor-25.0.1.dist-info → auto_editor-25.2.0.dist-info}/RECORD +26 -23
- {auto_editor-25.0.1.dist-info → auto_editor-25.2.0.dist-info}/WHEEL +1 -1
- {auto_editor-25.0.1.dist-info → auto_editor-25.2.0.dist-info}/top_level.txt +1 -0
- docs/build.py +53 -0
- {auto_editor-25.0.1.dist-info → auto_editor-25.2.0.dist-info}/LICENSE +0 -0
- {auto_editor-25.0.1.dist-info → auto_editor-25.2.0.dist-info}/entry_points.txt +0 -0
auto_editor/lang/palet.py
CHANGED
@@ -5,34 +5,26 @@ The syntax is inspired by the Racket Programming language.
|
|
5
5
|
|
6
6
|
from __future__ import annotations
|
7
7
|
|
8
|
-
from cmath import sqrt as complex_sqrt
|
9
8
|
from dataclasses import dataclass
|
10
9
|
from difflib import get_close_matches
|
11
10
|
from fractions import Fraction
|
12
|
-
from functools import reduce
|
13
11
|
from io import StringIO
|
14
|
-
from operator import add, ge, gt, is_, le, lt, mod, mul
|
15
|
-
from time import sleep
|
16
12
|
from typing import TYPE_CHECKING
|
17
13
|
|
18
14
|
import numpy as np
|
19
|
-
from numpy import logical_and, logical_not, logical_or, logical_xor
|
20
15
|
|
21
|
-
from auto_editor.analyze import LevelError,
|
16
|
+
from auto_editor.analyze import LevelError, mut_remove_small
|
22
17
|
from auto_editor.lib.contracts import *
|
23
18
|
from auto_editor.lib.data_structs import *
|
24
19
|
from auto_editor.lib.err import MyError
|
25
|
-
from auto_editor.utils.func import boolop
|
20
|
+
from auto_editor.utils.func import boolop
|
26
21
|
|
27
22
|
if TYPE_CHECKING:
|
28
23
|
from collections.abc import Callable
|
29
|
-
from typing import Any,
|
24
|
+
from typing import Any, NoReturn
|
30
25
|
|
31
26
|
from numpy.typing import NDArray
|
32
27
|
|
33
|
-
Number = int | float | complex | Fraction
|
34
|
-
Real = int | float | Fraction
|
35
|
-
BoolList = NDArray[np.bool_]
|
36
28
|
Node = tuple
|
37
29
|
|
38
30
|
|
@@ -68,6 +60,8 @@ str_escape = {
|
|
68
60
|
class Token:
|
69
61
|
type: str
|
70
62
|
value: Any
|
63
|
+
lineno: int
|
64
|
+
column: int
|
71
65
|
|
72
66
|
|
73
67
|
class Lexer:
|
@@ -164,21 +158,31 @@ class Lexer:
|
|
164
158
|
elif unit == "dB":
|
165
159
|
token = DB
|
166
160
|
elif unit != "i" and unit != "%":
|
167
|
-
return Token(
|
161
|
+
return Token(
|
162
|
+
VAL,
|
163
|
+
Sym(result + unit, self.lineno, self.column),
|
164
|
+
self.lineno,
|
165
|
+
self.column,
|
166
|
+
)
|
168
167
|
|
169
168
|
try:
|
170
169
|
if unit == "i":
|
171
|
-
return Token(VAL, complex(result + "j"))
|
170
|
+
return Token(VAL, complex(result + "j"), self.lineno, self.column)
|
172
171
|
elif unit == "%":
|
173
|
-
return Token(VAL, float(result) / 100)
|
172
|
+
return Token(VAL, float(result) / 100, self.lineno, self.column)
|
174
173
|
elif "/" in result:
|
175
|
-
return Token(token, Fraction(result))
|
174
|
+
return Token(token, Fraction(result), self.lineno, self.column)
|
176
175
|
elif "." in result:
|
177
|
-
return Token(token, float(result))
|
176
|
+
return Token(token, float(result), self.lineno, self.column)
|
178
177
|
else:
|
179
|
-
return Token(token, int(result))
|
178
|
+
return Token(token, int(result), self.lineno, self.column)
|
180
179
|
except ValueError:
|
181
|
-
return Token(
|
180
|
+
return Token(
|
181
|
+
VAL,
|
182
|
+
Sym(result + unit, self.lineno, self.column),
|
183
|
+
self.lineno,
|
184
|
+
self.column,
|
185
|
+
)
|
182
186
|
|
183
187
|
def hash_literal(self) -> Token:
|
184
188
|
if self.char == "\\":
|
@@ -188,7 +192,7 @@ class Lexer:
|
|
188
192
|
|
189
193
|
char = self.char
|
190
194
|
self.advance()
|
191
|
-
return Token(VAL, Char(char))
|
195
|
+
return Token(VAL, Char(char), self.lineno, self.column)
|
192
196
|
|
193
197
|
if self.char == ":":
|
194
198
|
self.advance()
|
@@ -198,14 +202,14 @@ class Lexer:
|
|
198
202
|
buf.write(self.char)
|
199
203
|
self.advance()
|
200
204
|
|
201
|
-
return Token(VAL, Keyword(buf.getvalue()))
|
205
|
+
return Token(VAL, Keyword(buf.getvalue()), self.lineno, self.column)
|
202
206
|
|
203
207
|
if self.char is not None and self.char in "([{":
|
204
208
|
brac_type = self.char
|
205
209
|
self.advance()
|
206
210
|
if self.char is None:
|
207
211
|
self.close_err(f"Expected a character after #{brac_type}")
|
208
|
-
return Token(VLIT, brac_pairs[brac_type])
|
212
|
+
return Token(VLIT, brac_pairs[brac_type], self.lineno, self.column)
|
209
213
|
|
210
214
|
buf = StringIO()
|
211
215
|
while self.char_is_norm():
|
@@ -215,10 +219,10 @@ class Lexer:
|
|
215
219
|
|
216
220
|
result = buf.getvalue()
|
217
221
|
if result in ("t", "T", "true"):
|
218
|
-
return Token(VAL, True)
|
222
|
+
return Token(VAL, True, self.lineno, self.column)
|
219
223
|
|
220
224
|
if result in ("f", "F", "false"):
|
221
|
-
return Token(VAL, False)
|
225
|
+
return Token(VAL, False, self.lineno, self.column)
|
222
226
|
|
223
227
|
self.error(f"Unknown hash literal `#{result}`")
|
224
228
|
|
@@ -239,17 +243,19 @@ class Lexer:
|
|
239
243
|
my_str = self.string()
|
240
244
|
if self.char == ".": # handle `object.method` syntax
|
241
245
|
self.advance()
|
242
|
-
return Token(
|
243
|
-
|
246
|
+
return Token(
|
247
|
+
DOT, (my_str, self.get_next_token()), self.lineno, self.column
|
248
|
+
)
|
249
|
+
return Token(VAL, my_str, self.lineno, self.column)
|
244
250
|
|
245
251
|
if self.char == "'":
|
246
252
|
self.advance()
|
247
|
-
return Token(QUOTE, "'")
|
253
|
+
return Token(QUOTE, "'", self.lineno, self.column)
|
248
254
|
|
249
255
|
if self.char in "(){}[]":
|
250
256
|
_par = self.char
|
251
257
|
self.advance()
|
252
|
-
return Token(_par, _par)
|
258
|
+
return Token(_par, _par, self.lineno, self.column)
|
253
259
|
|
254
260
|
if self.char in "+-":
|
255
261
|
_peek = self.peek()
|
@@ -347,18 +353,27 @@ class Lexer:
|
|
347
353
|
if is_method:
|
348
354
|
from auto_editor.utils.cmdkw import parse_method
|
349
355
|
|
350
|
-
return Token(
|
356
|
+
return Token(
|
357
|
+
M, parse_method(name, result, env), self.lineno, self.column
|
358
|
+
)
|
351
359
|
|
352
360
|
if self.char == ".": # handle `object.method` syntax
|
353
361
|
self.advance()
|
354
|
-
return Token(
|
362
|
+
return Token(
|
363
|
+
DOT,
|
364
|
+
(Sym(result, self.lineno, self.column), self.get_next_token()),
|
365
|
+
self.lineno,
|
366
|
+
self.column,
|
367
|
+
)
|
355
368
|
|
356
369
|
if has_illegal:
|
357
370
|
self.error(f"Symbol has illegal character(s): {result}")
|
358
371
|
|
359
|
-
return Token(
|
372
|
+
return Token(
|
373
|
+
VAL, Sym(result, self.lineno, self.column), self.lineno, self.column
|
374
|
+
)
|
360
375
|
|
361
|
-
return Token(EOF, "EOF")
|
376
|
+
return Token(EOF, "EOF", self.lineno, self.column)
|
362
377
|
|
363
378
|
|
364
379
|
###############################################################################
|
@@ -378,6 +393,7 @@ class Parser:
|
|
378
393
|
|
379
394
|
def expr(self) -> Any:
|
380
395
|
token = self.current_token
|
396
|
+
lineno, column = token.lineno, token.column
|
381
397
|
|
382
398
|
if token.type == VAL:
|
383
399
|
self.eat()
|
@@ -405,7 +421,7 @@ class Parser:
|
|
405
421
|
if token.type == M:
|
406
422
|
self.eat()
|
407
423
|
name, args, kwargs = token.value
|
408
|
-
_result = [Sym(name)] + args
|
424
|
+
_result = [Sym(name, lineno, column)] + args
|
409
425
|
for key, val in kwargs.items():
|
410
426
|
_result.append(Keyword(key))
|
411
427
|
_result.append(val)
|
@@ -421,7 +437,7 @@ class Parser:
|
|
421
437
|
|
422
438
|
if token.type == QUOTE:
|
423
439
|
self.eat()
|
424
|
-
return (Sym("quote"), self.expr())
|
440
|
+
return (Sym("quote", lineno, column), self.expr())
|
425
441
|
|
426
442
|
if token.type in brac_pairs:
|
427
443
|
self.eat()
|
@@ -453,238 +469,26 @@ class Parser:
|
|
453
469
|
|
454
470
|
###############################################################################
|
455
471
|
# #
|
456
|
-
#
|
472
|
+
# ENVIRONMENT #
|
457
473
|
# #
|
458
474
|
###############################################################################
|
459
475
|
|
460
476
|
|
461
|
-
|
462
|
-
|
463
|
-
"iterable?",
|
464
|
-
lambda v: type(v) in (str, range, list, tuple, dict, Quoted)
|
465
|
-
or isinstance(v, np.ndarray),
|
466
|
-
)
|
467
|
-
is_sequence = Contract(
|
468
|
-
"sequence?",
|
469
|
-
lambda v: type(v) in (str, range, Quoted) or isinstance(v, list | np.ndarray),
|
470
|
-
)
|
471
|
-
is_boolarr = Contract(
|
472
|
-
"bool-array?",
|
473
|
-
lambda v: isinstance(v, np.ndarray) and v.dtype.kind == "b",
|
474
|
-
)
|
475
|
-
bool_or_barr = Contract(
|
476
|
-
"(or/c bool? bool-array?)",
|
477
|
-
lambda v: type(v) is bool or is_boolarr(v),
|
478
|
-
)
|
479
|
-
is_keyw = Contract("keyword?", lambda v: type(v) is QuotedKeyword)
|
480
|
-
|
477
|
+
class Syntax:
|
478
|
+
__slots__ = "syn"
|
481
479
|
|
482
|
-
|
483
|
-
|
484
|
-
name: str
|
485
|
-
port: Any
|
486
|
-
write: Any
|
487
|
-
closed: bool
|
480
|
+
def __init__(self, syn: Callable[[Env, Node], Any]):
|
481
|
+
self.syn = syn
|
488
482
|
|
489
|
-
def
|
490
|
-
|
491
|
-
self.closed = True
|
492
|
-
self.port.close()
|
483
|
+
def __call__(self, env: Env, node: Node) -> Any:
|
484
|
+
return self.syn(env, node)
|
493
485
|
|
494
486
|
def __str__(self) -> str:
|
495
|
-
return
|
487
|
+
return "#<syntax>"
|
496
488
|
|
497
489
|
__repr__ = __str__
|
498
490
|
|
499
491
|
|
500
|
-
def initOutPort(name: str) -> OutputPort | Literal[False]:
|
501
|
-
try:
|
502
|
-
port = open(name, "w", encoding="utf-8")
|
503
|
-
except Exception:
|
504
|
-
return False
|
505
|
-
return OutputPort(name, port, port.write, False)
|
506
|
-
|
507
|
-
|
508
|
-
def raise_(msg: str | Exception) -> NoReturn:
|
509
|
-
raise MyError(msg)
|
510
|
-
|
511
|
-
|
512
|
-
def is_equal(a: object, b: object) -> bool:
|
513
|
-
if isinstance(a, np.ndarray) and isinstance(b, np.ndarray):
|
514
|
-
return np.array_equal(a, b)
|
515
|
-
return type(a) == type(b) and a == b
|
516
|
-
|
517
|
-
|
518
|
-
def equal_num(*values: object) -> bool:
|
519
|
-
return all(values[0] == val for val in values[1:])
|
520
|
-
|
521
|
-
|
522
|
-
def minus(*vals: Number) -> Number:
|
523
|
-
if len(vals) == 1:
|
524
|
-
return -vals[0]
|
525
|
-
return reduce(lambda a, b: a - b, vals)
|
526
|
-
|
527
|
-
|
528
|
-
def num_div(z: Number, *w: Number) -> Number:
|
529
|
-
if len(w) == 0:
|
530
|
-
w = (z,)
|
531
|
-
z = 1
|
532
|
-
|
533
|
-
for num in w:
|
534
|
-
if num == 0:
|
535
|
-
raise MyError("/: division by zero")
|
536
|
-
|
537
|
-
z /= num
|
538
|
-
|
539
|
-
return z
|
540
|
-
|
541
|
-
|
542
|
-
def int_div(n: int, *m: int) -> int:
|
543
|
-
if 0 in m:
|
544
|
-
raise MyError("div: division by zero")
|
545
|
-
|
546
|
-
return reduce(lambda a, b: a // b, m, n)
|
547
|
-
|
548
|
-
|
549
|
-
def _sqrt(v: Number) -> Number:
|
550
|
-
r = complex_sqrt(v)
|
551
|
-
if r.imag == 0:
|
552
|
-
if int(r.real) == r.real:
|
553
|
-
return int(r.real)
|
554
|
-
return r.real
|
555
|
-
return r
|
556
|
-
|
557
|
-
|
558
|
-
def _xor(*vals: Any) -> bool | BoolList:
|
559
|
-
if is_boolarr(vals[0]):
|
560
|
-
check_args("xor", vals, (2, None), (is_boolarr,))
|
561
|
-
return reduce(lambda a, b: boolop(a, b, logical_xor), vals)
|
562
|
-
check_args("xor", vals, (2, None), (is_bool,))
|
563
|
-
return reduce(lambda a, b: a ^ b, vals)
|
564
|
-
|
565
|
-
|
566
|
-
def string_ref(s: str, ref: int) -> Char:
|
567
|
-
try:
|
568
|
-
return Char(s[ref])
|
569
|
-
except IndexError:
|
570
|
-
raise MyError(f"string index {ref} is out of range")
|
571
|
-
|
572
|
-
|
573
|
-
def number_to_string(val: Number) -> str:
|
574
|
-
if isinstance(val, complex):
|
575
|
-
join = "" if val.imag < 0 else "+"
|
576
|
-
return f"{val.real}{join}{val.imag}i"
|
577
|
-
return f"{val}"
|
578
|
-
|
579
|
-
|
580
|
-
def palet_join(v: Any, s: str) -> str:
|
581
|
-
try:
|
582
|
-
return s.join(v)
|
583
|
-
except Exception:
|
584
|
-
raise MyError("join: expected string?")
|
585
|
-
|
586
|
-
|
587
|
-
dtype_map = {
|
588
|
-
Sym("bool"): np.bool_,
|
589
|
-
Sym("int8"): np.int8,
|
590
|
-
Sym("int16"): np.int16,
|
591
|
-
Sym("int32"): np.int32,
|
592
|
-
Sym("int64"): np.int64,
|
593
|
-
Sym("uint8"): np.uint8,
|
594
|
-
Sym("uint16"): np.uint16,
|
595
|
-
Sym("uint32"): np.uint32,
|
596
|
-
Sym("uint64"): np.uint64,
|
597
|
-
Sym("float32"): np.float32,
|
598
|
-
Sym("float64"): np.float64,
|
599
|
-
}
|
600
|
-
|
601
|
-
|
602
|
-
def _dtype_to_np(dtype: Sym) -> type[np.generic]:
|
603
|
-
np_dtype = dtype_map.get(dtype)
|
604
|
-
if np_dtype is None:
|
605
|
-
raise MyError(f"Invalid array dtype: {dtype}")
|
606
|
-
return np_dtype
|
607
|
-
|
608
|
-
|
609
|
-
def array_proc(dtype: Sym, *vals: Any) -> np.ndarray:
|
610
|
-
try:
|
611
|
-
return np.array(vals, dtype=_dtype_to_np(dtype))
|
612
|
-
except OverflowError:
|
613
|
-
raise MyError(f"number too large to be converted to {dtype}")
|
614
|
-
|
615
|
-
|
616
|
-
def make_array(dtype: Sym, size: int, v: int = 0) -> np.ndarray:
|
617
|
-
try:
|
618
|
-
return np.array([v] * size, dtype=_dtype_to_np(dtype))
|
619
|
-
except OverflowError:
|
620
|
-
raise MyError(f"number too large to be converted to {dtype}")
|
621
|
-
|
622
|
-
|
623
|
-
def minclip(oarr: BoolList, _min: int, /) -> BoolList:
|
624
|
-
arr = np.copy(oarr)
|
625
|
-
mut_remove_small(arr, _min, replace=1, with_=0)
|
626
|
-
return arr
|
627
|
-
|
628
|
-
|
629
|
-
def mincut(oarr: BoolList, _min: int, /) -> BoolList:
|
630
|
-
arr = np.copy(oarr)
|
631
|
-
mut_remove_small(arr, _min, replace=0, with_=1)
|
632
|
-
return arr
|
633
|
-
|
634
|
-
|
635
|
-
def maxclip(oarr: BoolList, _min: int, /) -> BoolList:
|
636
|
-
arr = np.copy(oarr)
|
637
|
-
mut_remove_large(arr, _min, replace=1, with_=0)
|
638
|
-
return arr
|
639
|
-
|
640
|
-
|
641
|
-
def maxcut(oarr: BoolList, _min: int, /) -> BoolList:
|
642
|
-
arr = np.copy(oarr)
|
643
|
-
mut_remove_large(arr, _min, replace=0, with_=1)
|
644
|
-
return arr
|
645
|
-
|
646
|
-
|
647
|
-
def margin(oarr: BoolList, start: int, end: int | None = None, /) -> BoolList:
|
648
|
-
arr = np.copy(oarr)
|
649
|
-
if end is None:
|
650
|
-
mut_margin(arr, start, start)
|
651
|
-
else:
|
652
|
-
mut_margin(arr, start, end)
|
653
|
-
return arr
|
654
|
-
|
655
|
-
|
656
|
-
def vector_set(vec: list, pos: int, v: Any) -> None:
|
657
|
-
try:
|
658
|
-
vec[pos] = v
|
659
|
-
except IndexError:
|
660
|
-
raise MyError(f"vector-set: Invalid index {pos}")
|
661
|
-
|
662
|
-
|
663
|
-
def vector_extend(vec: list, *more_vecs: list) -> None:
|
664
|
-
for more in more_vecs:
|
665
|
-
vec.extend(more)
|
666
|
-
|
667
|
-
|
668
|
-
def list_append(*v: Quoted) -> Quoted:
|
669
|
-
result = Quoted(tuple())
|
670
|
-
for item in v:
|
671
|
-
result.val = result.val + item.val
|
672
|
-
return result
|
673
|
-
|
674
|
-
|
675
|
-
def palet_map(proc: Proc, seq: Any) -> Any:
|
676
|
-
if type(seq) is str:
|
677
|
-
return str(map(proc, seq))
|
678
|
-
if type(seq) is Quoted:
|
679
|
-
return Quoted(tuple(map(proc, seq.val)))
|
680
|
-
if isinstance(seq, list | range):
|
681
|
-
return list(map(proc, seq))
|
682
|
-
elif isinstance(seq, np.ndarray):
|
683
|
-
vectorized_proc = np.vectorize(proc)
|
684
|
-
return vectorized_proc(seq)
|
685
|
-
return proc(seq)
|
686
|
-
|
687
|
-
|
688
492
|
def ref(seq: Any, ref: int) -> Any:
|
689
493
|
try:
|
690
494
|
if type(seq) is str:
|
@@ -708,743 +512,19 @@ def p_slice(
|
|
708
512
|
return seq[start:end:step]
|
709
513
|
|
710
514
|
|
711
|
-
|
712
|
-
|
713
|
-
)
|
714
|
-
|
715
|
-
|
716
|
-
|
717
|
-
|
718
|
-
|
719
|
-
|
720
|
-
raise MyError("hash: number of args must be even")
|
721
|
-
for key, item in zip(args[0::2], args[1::2]):
|
722
|
-
result[key] = item
|
723
|
-
return result
|
724
|
-
|
725
|
-
|
726
|
-
def hash_ref(h: dict, k: object) -> object:
|
727
|
-
try:
|
728
|
-
return h[k]
|
729
|
-
except Exception:
|
730
|
-
raise MyError("hash-ref: invalid key")
|
731
|
-
|
732
|
-
|
733
|
-
def hash_set(h: dict, k: object, v: object) -> None:
|
734
|
-
h[k] = v
|
735
|
-
|
736
|
-
|
737
|
-
def hash_remove(h: dict, v: object) -> None:
|
738
|
-
try:
|
739
|
-
del h[v]
|
740
|
-
except Exception:
|
741
|
-
pass
|
742
|
-
|
743
|
-
|
744
|
-
def palet_assert(expr: object, msg: str | bool = False) -> None:
|
745
|
-
if expr is not True:
|
746
|
-
raise MyError("assert-error" if msg is False else f"assert-error: {msg}")
|
747
|
-
|
748
|
-
|
749
|
-
def palet_system(cmd: str) -> bool:
|
750
|
-
import subprocess
|
751
|
-
|
752
|
-
try:
|
753
|
-
return subprocess.run(cmd, shell=True).returncode == 0
|
754
|
-
except Exception:
|
755
|
-
return False
|
756
|
-
|
757
|
-
|
758
|
-
###############################################################################
|
759
|
-
# #
|
760
|
-
# ENVIRONMENT #
|
761
|
-
# #
|
762
|
-
###############################################################################
|
763
|
-
|
764
|
-
|
765
|
-
class UserProc(Proc):
|
766
|
-
"""A user-defined procedure."""
|
767
|
-
|
768
|
-
__slots__ = ("env", "name", "parms", "body", "contracts", "arity")
|
769
|
-
|
770
|
-
def __init__(
|
771
|
-
self,
|
772
|
-
env: Env,
|
773
|
-
name: str,
|
774
|
-
parms: list[str],
|
775
|
-
contracts: tuple[Any, ...],
|
776
|
-
body: Node,
|
777
|
-
):
|
778
|
-
self.env = env
|
779
|
-
self.name = name
|
780
|
-
self.parms = parms
|
781
|
-
self.body = body
|
782
|
-
self.contracts = contracts
|
783
|
-
|
784
|
-
if parms and parms[-1] == "...":
|
785
|
-
parms.pop()
|
786
|
-
self.arity: tuple[int, int | None] = len(parms) - 1, None
|
787
|
-
else:
|
788
|
-
self.arity = len(parms), len(parms)
|
789
|
-
|
790
|
-
def __call__(self, *args: Any) -> Any:
|
791
|
-
check_args(self.name, args, self.arity, self.contracts)
|
792
|
-
|
793
|
-
if self.arity[1] is None:
|
794
|
-
args = tuple(
|
795
|
-
list(args[: len(self.parms) - 1]) + [list(args[len(self.parms) - 1 :])]
|
796
|
-
)
|
797
|
-
|
798
|
-
inner_env = Env(dict(zip(self.parms, args)), self.env)
|
799
|
-
|
800
|
-
for item in self.body[0:-1]:
|
801
|
-
my_eval(inner_env, item)
|
802
|
-
|
803
|
-
return my_eval(inner_env, self.body[-1])
|
804
|
-
|
805
|
-
|
806
|
-
@dataclass(slots=True)
|
807
|
-
class KeywordUserProc:
|
808
|
-
env: Env
|
809
|
-
name: str
|
810
|
-
parms: list[str]
|
811
|
-
kw_parms: list[str]
|
812
|
-
body: Node
|
813
|
-
arity: tuple[int, None]
|
814
|
-
contracts: list[Any] | None = None
|
815
|
-
|
816
|
-
def __call__(self, *args: Any, **kwargs: Any) -> Any:
|
817
|
-
env = {}
|
818
|
-
all_parms = self.parms + self.kw_parms
|
819
|
-
for i, arg in enumerate(args):
|
820
|
-
if i >= len(all_parms):
|
821
|
-
raise MyError("Too many arguments")
|
822
|
-
env[all_parms[i]] = arg
|
823
|
-
|
824
|
-
for key, val in kwargs.items():
|
825
|
-
if key in env:
|
826
|
-
raise MyError(
|
827
|
-
f"Keyword: {key} already fulfilled by positional argument."
|
828
|
-
)
|
829
|
-
else:
|
830
|
-
env[key] = val
|
831
|
-
|
832
|
-
inner_env = Env(env, self.env)
|
833
|
-
|
834
|
-
for item in self.body[0:-1]:
|
835
|
-
my_eval(inner_env, item)
|
836
|
-
|
837
|
-
return my_eval(inner_env, self.body[-1])
|
838
|
-
|
839
|
-
def __str__(self) -> str:
|
840
|
-
return self.name
|
841
|
-
|
842
|
-
def __repr__(self) -> str:
|
843
|
-
return f"#<kw-proc:{self.name}>"
|
844
|
-
|
845
|
-
|
846
|
-
class Syntax:
|
847
|
-
__slots__ = "syn"
|
848
|
-
|
849
|
-
def __init__(self, syn: Callable[[Env, Node], Any]):
|
850
|
-
self.syn = syn
|
851
|
-
|
852
|
-
def __call__(self, env: Env, node: Node) -> Any:
|
853
|
-
return self.syn(env, node)
|
854
|
-
|
855
|
-
def __str__(self) -> str:
|
856
|
-
return "#<syntax>"
|
857
|
-
|
858
|
-
__repr__ = __str__
|
859
|
-
|
860
|
-
|
861
|
-
def check_for_syntax(env: Env, node: Node) -> tuple[Sym, Any]:
|
862
|
-
name = node[0]
|
863
|
-
if len(node) < 2:
|
864
|
-
raise MyError(f"{name}: bad syntax")
|
865
|
-
|
866
|
-
if len(node) == 2:
|
867
|
-
raise MyError(f"{name}: missing body")
|
868
|
-
|
869
|
-
assert isinstance(node[1], tuple)
|
870
|
-
assert isinstance(node[1][0], tuple)
|
871
|
-
|
872
|
-
var = node[1][0][0]
|
873
|
-
if type(var) is not Sym:
|
874
|
-
raise MyError(f"{name}: binding must be an identifier")
|
875
|
-
my_iter = my_eval(env, node[1][0][1])
|
876
|
-
|
877
|
-
if not is_iterable(my_iter):
|
878
|
-
if type(my_iter) is int:
|
879
|
-
return var, range(my_iter)
|
880
|
-
raise MyError(f"{name}: got non-iterable in iter slot")
|
881
|
-
|
882
|
-
return var, my_iter
|
883
|
-
|
884
|
-
|
885
|
-
def syn_lambda(env: Env, node: Node) -> UserProc:
|
886
|
-
if len(node) < 3:
|
887
|
-
raise MyError(f"{node[0]}: too few terms")
|
888
|
-
|
889
|
-
if type(node[1]) is not tuple:
|
890
|
-
raise MyError(f"{node[0]}: bad syntax")
|
891
|
-
|
892
|
-
parms: list[str] = []
|
893
|
-
for item in node[1]:
|
894
|
-
if type(item) is not Sym:
|
895
|
-
raise MyError(f"{node[0]}: must be an identifier")
|
896
|
-
|
897
|
-
parms.append(f"{item}")
|
898
|
-
|
899
|
-
return UserProc(env, "", parms, (), node[2:])
|
900
|
-
|
901
|
-
|
902
|
-
def syn_define(env: Env, node: Node) -> None:
|
903
|
-
if len(node) < 3:
|
904
|
-
raise MyError(f"{node[0]}: too few terms")
|
905
|
-
|
906
|
-
if type(node[1]) is tuple:
|
907
|
-
term = node[1]
|
908
|
-
body = node[2:]
|
909
|
-
|
910
|
-
if not term or type(term[0]) is not Sym:
|
911
|
-
raise MyError(f"{node[0]}: proc-binding must be an identifier")
|
912
|
-
|
913
|
-
n = term[0].val
|
914
|
-
parms: list[str] = []
|
915
|
-
kparms: list[str] = []
|
916
|
-
kw_only = False
|
917
|
-
|
918
|
-
for item in term[1:]:
|
919
|
-
if kw_only:
|
920
|
-
if type(item) is Sym:
|
921
|
-
raise MyError(f"{node[0]}: {item} must be a keyword")
|
922
|
-
if type(item) is not Keyword:
|
923
|
-
raise MyError(f"{node[0]}: must be a keyword")
|
924
|
-
kparms.append(item.val)
|
925
|
-
else:
|
926
|
-
if type(item) is Keyword:
|
927
|
-
kw_only = True
|
928
|
-
kparms.append(item.val)
|
929
|
-
elif type(item) is Sym:
|
930
|
-
parms.append(item.val)
|
931
|
-
else:
|
932
|
-
raise MyError(f"{node[0]}: must be an identifier")
|
933
|
-
|
934
|
-
if kw_only:
|
935
|
-
env[n] = KeywordUserProc(env, n, parms, kparms, body, (len(parms), None))
|
936
|
-
else:
|
937
|
-
env[n] = UserProc(env, n, parms, (), body)
|
938
|
-
return None
|
939
|
-
|
940
|
-
elif type(node[1]) is not Sym:
|
941
|
-
raise MyError(f"{node[0]}: must be an identifier")
|
942
|
-
|
943
|
-
if len(node) > 3:
|
944
|
-
raise MyError(f"{node[0]}: multiple expressions after identifier")
|
945
|
-
|
946
|
-
n = node[1].val
|
947
|
-
|
948
|
-
if (
|
949
|
-
type(node[2]) is tuple
|
950
|
-
and node[2]
|
951
|
-
and type(node[2][0]) is Sym
|
952
|
-
and node[2][0].val in ("lambda", "λ")
|
953
|
-
):
|
954
|
-
terms = node[2][1]
|
955
|
-
body = node[2][2:]
|
956
|
-
|
957
|
-
parms = []
|
958
|
-
for item in terms:
|
959
|
-
if type(item) is not Sym:
|
960
|
-
raise MyError(f"{node[0]}: must be an identifier")
|
961
|
-
|
962
|
-
parms.append(f"{item}")
|
963
|
-
|
964
|
-
env[n] = UserProc(env, n, parms, (), body)
|
965
|
-
|
966
|
-
else:
|
967
|
-
for item in node[2:-1]:
|
968
|
-
my_eval(env, item)
|
969
|
-
env[n] = my_eval(env, node[-1])
|
970
|
-
|
971
|
-
|
972
|
-
def syn_definec(env: Env, node: Node) -> None:
|
973
|
-
if len(node) < 3:
|
974
|
-
raise MyError(f"{node[0]}: too few terms")
|
975
|
-
|
976
|
-
if type(node[1]) is not tuple:
|
977
|
-
raise MyError(f"{node[0]} only allows procedure declarations")
|
978
|
-
|
979
|
-
if not node[1] or type(node[1][0]) is not Sym:
|
980
|
-
raise MyError(f"{node[0]}: bad proc-binding syntax")
|
981
|
-
|
982
|
-
n = node[1][0].val
|
983
|
-
|
984
|
-
contracts: list[Any] = []
|
985
|
-
parms: list[str] = []
|
986
|
-
for item in node[1][1:]:
|
987
|
-
if item == Sym("->"):
|
988
|
-
break
|
989
|
-
if type(item) is not tuple or len(item) != 2:
|
990
|
-
raise MyError(f"{node[0]}: bad var-binding syntax")
|
991
|
-
if type(item[0]) is not Sym:
|
992
|
-
raise MyError(f"{node[0]}: binding must be identifier")
|
993
|
-
|
994
|
-
con = my_eval(env, item[1])
|
995
|
-
if not is_cont(con):
|
996
|
-
raise MyError(f"{node[0]}: {print_str(con)} is not a valid contract")
|
997
|
-
|
998
|
-
parms.append(f"{item[0]}")
|
999
|
-
contracts.append(con)
|
1000
|
-
|
1001
|
-
env[n] = UserProc(env, n, parms, tuple(contracts), node[2:])
|
1002
|
-
return None
|
1003
|
-
|
1004
|
-
|
1005
|
-
def guard_term(node: Node, n: int, u: int) -> None:
|
1006
|
-
if n == u:
|
1007
|
-
if len(node) != n:
|
1008
|
-
raise MyError(
|
1009
|
-
f"{node[0]}: Expects exactly {n-1} term{'s' if n > 2 else ''}"
|
1010
|
-
)
|
1011
|
-
return None
|
1012
|
-
if len(node) < n:
|
1013
|
-
raise MyError(f"{node[0]}: Expects at least {n-1} term{'s' if n > 2 else ''}")
|
1014
|
-
if len(node) > u:
|
1015
|
-
raise MyError(f"{node[0]}: Expects at most {u-1} term{'s' if u > 2 else ''}")
|
1016
|
-
|
1017
|
-
|
1018
|
-
def syn_set(env: Env, node: Node) -> None:
|
1019
|
-
guard_term(node, 3, 3)
|
1020
|
-
|
1021
|
-
if type(node[1]) is Sym:
|
1022
|
-
name = node[1].val
|
1023
|
-
if name not in env:
|
1024
|
-
raise MyError(f"{node[0]}: Can't set variable `{name}` before definition")
|
1025
|
-
env[name] = my_eval(env, node[2])
|
1026
|
-
return None
|
1027
|
-
|
1028
|
-
if type(node[1]) is tuple and len(node[1]) == 3 and node[1][0] == Sym("@r"):
|
1029
|
-
base = my_eval(env, node[1][1])
|
1030
|
-
name = node[1][2].val
|
1031
|
-
for i, item in enumerate(base.attrs[0::2]):
|
1032
|
-
if name == item:
|
1033
|
-
result = my_eval(env, node[2])
|
1034
|
-
check_args(item, (result,), (1, 1), (base.attrs[i * 2 + 1],))
|
1035
|
-
base.values[i] = result
|
1036
|
-
return None
|
1037
|
-
|
1038
|
-
raise MyError(f"{node[0]}: {base.name} has no attribute `{name}`")
|
1039
|
-
|
1040
|
-
raise MyError(f"{node[0]}: Expected identifier, got {print_str(node[1])}")
|
1041
|
-
|
1042
|
-
|
1043
|
-
def syn_incf(env: Env, node: Node) -> None:
|
1044
|
-
guard_term(node, 2, 3)
|
1045
|
-
|
1046
|
-
incre_by = 1
|
1047
|
-
if len(node) == 3:
|
1048
|
-
incre_by = my_eval(env, node[2])
|
1049
|
-
if not is_num(incre_by):
|
1050
|
-
raise MyError(f"{node[0]}: Expected number? got: {print_str(incre_by)}")
|
1051
|
-
|
1052
|
-
if type(node[1]) is Sym:
|
1053
|
-
name = node[1].val
|
1054
|
-
|
1055
|
-
if type(env[name]) is NotFound:
|
1056
|
-
raise MyError(f"{node[0]}: `{name}` is not defined")
|
1057
|
-
if not is_num(env[name]):
|
1058
|
-
raise MyError(f"{node[0]}: `{name}` is not a number?")
|
1059
|
-
env[name] += incre_by
|
1060
|
-
return None
|
1061
|
-
|
1062
|
-
if type(node[1]) is tuple and len(node[1]) == 3 and node[1][0] == Sym("@r"):
|
1063
|
-
base = my_eval(env, node[1][1])
|
1064
|
-
if type(base) is not PaletClass:
|
1065
|
-
raise MyError(f"{node[0]}: must be a class instance")
|
1066
|
-
if type(node[1][2]) is not Sym:
|
1067
|
-
raise MyError(f"{node[0]}: class attribute must be an identifier")
|
1068
|
-
name = node[1][2].val
|
1069
|
-
for i, item in enumerate(base.attrs[0::2]):
|
1070
|
-
if name == item:
|
1071
|
-
if not is_num(base.values[i]):
|
1072
|
-
raise MyError(f"{node[0]}: `{name}` is not a number?")
|
1073
|
-
|
1074
|
-
check_args(
|
1075
|
-
name, (base.values[i] + incre_by,), (1, 1), (base.attrs[i * 2 + 1],)
|
1076
|
-
)
|
1077
|
-
base.values[i] += incre_by
|
1078
|
-
return None
|
1079
|
-
raise MyError(f"{node[0]}: {base.name} has no attribute `{name}`")
|
1080
|
-
|
1081
|
-
raise MyError(f"{node[0]}: Expected identifier, got {print_str(node[1])}")
|
1082
|
-
|
1083
|
-
|
1084
|
-
def syn_decf(env: Env, node: Node) -> None:
|
1085
|
-
guard_term(node, 2, 3)
|
1086
|
-
|
1087
|
-
incre_by = 1
|
1088
|
-
if len(node) == 3:
|
1089
|
-
incre_by = my_eval(env, node[2])
|
1090
|
-
if not is_num(incre_by):
|
1091
|
-
raise MyError(f"{node[0]}: Expected number? got: {print_str(incre_by)}")
|
1092
|
-
|
1093
|
-
if type(node[1]) is Sym:
|
1094
|
-
name = node[1].val
|
1095
|
-
|
1096
|
-
if type(env[name]) is NotFound:
|
1097
|
-
raise MyError(f"{node[0]}: `{name}` is not defined")
|
1098
|
-
if not is_num(env[name]):
|
1099
|
-
raise MyError(f"{node[0]}: `{name}` is not a number?")
|
1100
|
-
env[name] -= incre_by
|
1101
|
-
return None
|
1102
|
-
|
1103
|
-
if type(node[1]) is tuple and len(node[1]) == 3 and node[1][0] == Sym("@r"):
|
1104
|
-
base = my_eval(env, node[1][1])
|
1105
|
-
if type(base) is not PaletClass:
|
1106
|
-
raise MyError(f"{node[0]}: must be a class instance")
|
1107
|
-
if type(node[1][2]) is not Sym:
|
1108
|
-
raise MyError(f"{node[0]}: class attribute must be an identifier")
|
1109
|
-
name = node[1][2].val
|
1110
|
-
for i, item in enumerate(base.attrs[0::2]):
|
1111
|
-
if name == item:
|
1112
|
-
if not is_num(base.values[i]):
|
1113
|
-
raise MyError(f"{node[0]}: `{name}` is not a number?")
|
1114
|
-
|
1115
|
-
check_args(
|
1116
|
-
name, (base.values[i] - incre_by,), (1, 1), (base.attrs[i * 2 + 1],)
|
1117
|
-
)
|
1118
|
-
base.values[i] -= incre_by
|
1119
|
-
return None
|
1120
|
-
raise MyError(f"{node[0]}: {base.name} has no attribute `{name}`")
|
1121
|
-
|
1122
|
-
raise MyError(f"{node[0]}: Expected identifier, got {print_str(node[1])}")
|
1123
|
-
|
1124
|
-
|
1125
|
-
def syn_strappend(env: Env, node: Node) -> None:
|
1126
|
-
guard_term(node, 3, 3)
|
1127
|
-
|
1128
|
-
if type(node[1]) is not Sym:
|
1129
|
-
raise MyError(f"{node[0]}: Expected identifier, got {print_str(node[1])}")
|
1130
|
-
name = node[1].val
|
1131
|
-
|
1132
|
-
if type(env[name]) is NotFound:
|
1133
|
-
raise MyError(f"{node[0]}: `{name}` is not defined")
|
1134
|
-
if not is_str(env[name]):
|
1135
|
-
raise MyError(f"{node[0]}: `{name}` is not a string?")
|
1136
|
-
|
1137
|
-
if not is_str(num := my_eval(env, node[2])):
|
1138
|
-
raise MyError(f"{node[0]}: Expected string? got: {print_str(num)}")
|
1139
|
-
env[name] += num
|
1140
|
-
|
1141
|
-
|
1142
|
-
def syn_for(env: Env, node: Node) -> None:
|
1143
|
-
var, my_iter = check_for_syntax(env, node)
|
1144
|
-
|
1145
|
-
if isinstance(my_iter, np.ndarray) and my_iter.dtype == np.bool_:
|
1146
|
-
for item in my_iter:
|
1147
|
-
env[var.val] = int(item)
|
1148
|
-
for c in node[2:]:
|
1149
|
-
my_eval(env, c)
|
1150
|
-
else:
|
1151
|
-
for item in my_iter:
|
1152
|
-
env[var.val] = item
|
1153
|
-
for c in node[2:]:
|
1154
|
-
my_eval(env, c)
|
1155
|
-
|
1156
|
-
|
1157
|
-
def syn_for_items(env: Env, node: Node) -> None:
|
1158
|
-
if len(node) < 2:
|
1159
|
-
raise MyError(f"{node[0]}: bad syntax")
|
1160
|
-
|
1161
|
-
if type(node[1]) is not tuple or len(node[1]) != 3:
|
1162
|
-
raise MyError(f"{node[0]}: Invalid id body")
|
1163
|
-
|
1164
|
-
key, val, dic = node[1]
|
1165
|
-
if type(key) is not Sym or type(val) is not Sym:
|
1166
|
-
raise MyError(f"{node[0]}: key and val must be identifiers")
|
1167
|
-
|
1168
|
-
dic = my_eval(env, dic)
|
1169
|
-
if type(dic) is not dict:
|
1170
|
-
raise MyError(f"{node[0]}: dict must be a hash?")
|
1171
|
-
|
1172
|
-
for k, v in dic.items():
|
1173
|
-
env[key.val] = k
|
1174
|
-
env[val.val] = v
|
1175
|
-
for c in node[2:]:
|
1176
|
-
my_eval(env, c)
|
1177
|
-
|
1178
|
-
|
1179
|
-
def syn_quote(env: Env, node: Node) -> Any:
|
1180
|
-
guard_term(node, 2, 2)
|
1181
|
-
if type(node[1]) is Keyword:
|
1182
|
-
return QuotedKeyword(node[1])
|
1183
|
-
if type(node[1]) is tuple:
|
1184
|
-
return Quoted(node[1])
|
1185
|
-
return node[1]
|
1186
|
-
|
1187
|
-
|
1188
|
-
def syn_if(env: Env, node: Node) -> Any:
|
1189
|
-
guard_term(node, 4, 4)
|
1190
|
-
test_expr = my_eval(env, node[1])
|
1191
|
-
|
1192
|
-
if type(test_expr) is not bool:
|
1193
|
-
raise MyError(
|
1194
|
-
f"{node[0]} test-expr: expected bool?, got {print_str(test_expr)}"
|
1195
|
-
)
|
1196
|
-
|
1197
|
-
return my_eval(env, node[2] if test_expr else node[3])
|
1198
|
-
|
1199
|
-
|
1200
|
-
def syn_when(env: Env, node: Node) -> Any:
|
1201
|
-
if len(node) < 3:
|
1202
|
-
raise MyError(f"{node[0]}: Expected at least 2 terms")
|
1203
|
-
test_expr = my_eval(env, node[1])
|
1204
|
-
|
1205
|
-
if type(test_expr) is not bool:
|
1206
|
-
raise MyError(
|
1207
|
-
f"{node[0]} test-expr: expected bool?, got {print_str(test_expr)}"
|
1208
|
-
)
|
1209
|
-
|
1210
|
-
if test_expr:
|
1211
|
-
for item in node[2:-1]:
|
1212
|
-
my_eval(env, item)
|
1213
|
-
return my_eval(env, node[-1])
|
1214
|
-
return None
|
1215
|
-
|
1216
|
-
|
1217
|
-
def syn_and(env: Env, node: Node) -> Any:
|
1218
|
-
if len(node) == 1:
|
1219
|
-
raise MyError(f"{node[0]}: Expected at least 1 term")
|
1220
|
-
|
1221
|
-
first = my_eval(env, node[1])
|
1222
|
-
if first is False:
|
1223
|
-
return False
|
1224
|
-
if first is True:
|
1225
|
-
for n in node[2:]:
|
1226
|
-
val = my_eval(env, n)
|
1227
|
-
if val is False:
|
1228
|
-
return False
|
1229
|
-
if val is not True:
|
1230
|
-
raise MyError(f"{node[0]} args must be bool?")
|
1231
|
-
return True
|
1232
|
-
|
1233
|
-
if is_boolarr(first):
|
1234
|
-
vals = [first] + [my_eval(env, n) for n in node[2:]]
|
1235
|
-
check_args(node[0], vals, (2, None), (is_boolarr,))
|
1236
|
-
return reduce(lambda a, b: boolop(a, b, logical_and), vals)
|
1237
|
-
|
1238
|
-
raise MyError(f"{node[0]} expects (or/c bool? bool-array?)")
|
1239
|
-
|
1240
|
-
|
1241
|
-
def syn_or(env: Env, node: Node) -> Any:
|
1242
|
-
if len(node) == 1:
|
1243
|
-
raise MyError(f"{node[0]}: Expected at least 1 term")
|
1244
|
-
|
1245
|
-
first = my_eval(env, node[1])
|
1246
|
-
if first is True:
|
1247
|
-
return True
|
1248
|
-
if first is False:
|
1249
|
-
for n in node[2:]:
|
1250
|
-
val = my_eval(env, n)
|
1251
|
-
if val is True:
|
1252
|
-
return True
|
1253
|
-
if val is not False:
|
1254
|
-
raise MyError(f"{node[0]} args must be bool?")
|
1255
|
-
return False
|
1256
|
-
|
1257
|
-
if is_boolarr(first):
|
1258
|
-
vals = [first] + [my_eval(env, n) for n in node[2:]]
|
1259
|
-
check_args(node[0], vals, (2, None), (is_boolarr,))
|
1260
|
-
return reduce(lambda a, b: boolop(a, b, logical_or), vals)
|
1261
|
-
|
1262
|
-
raise MyError(f"{node[0]} expects (or/c bool? bool-array?)")
|
1263
|
-
|
1264
|
-
|
1265
|
-
def syn_delete(env: Env, node: Node) -> None:
|
1266
|
-
guard_term(node, 2, 2)
|
1267
|
-
if type(node[1]) is not Sym:
|
1268
|
-
raise MyError(f"{node[0]}: Expected identifier for first term")
|
1269
|
-
|
1270
|
-
del env[node[1].val]
|
1271
|
-
|
1272
|
-
|
1273
|
-
def syn_rename(env: Env, node: Node) -> None:
|
1274
|
-
guard_term(node, 3, 3)
|
1275
|
-
|
1276
|
-
first = node[1]
|
1277
|
-
if type(first) is not Sym:
|
1278
|
-
raise MyError(f"{node[0]}: Expected identifier for first term")
|
1279
|
-
|
1280
|
-
sec = node[2]
|
1281
|
-
if type(sec) is not Sym:
|
1282
|
-
raise MyError(f"{node[0]}: Expected identifier for second term")
|
1283
|
-
|
1284
|
-
if first.val not in env:
|
1285
|
-
raise MyError(f"{node[0]}: Original identifier does not exist")
|
1286
|
-
|
1287
|
-
env[sec.val] = env[first.val]
|
1288
|
-
del env[first.val]
|
1289
|
-
|
1290
|
-
|
1291
|
-
def syn_cond(env: Env, node: Node) -> Any:
|
1292
|
-
for test_expr in node[1:]:
|
1293
|
-
if type(test_expr) is not tuple or not test_expr:
|
1294
|
-
raise MyError(f"{node[0]}: bad syntax, clause is not a test-value pair")
|
1295
|
-
|
1296
|
-
if test_expr[0] == Sym("else"):
|
1297
|
-
if len(test_expr) == 1:
|
1298
|
-
raise MyError(f"{node[0]}: missing expression in else clause")
|
1299
|
-
test_clause = True
|
1300
|
-
else:
|
1301
|
-
test_clause = my_eval(env, test_expr[0])
|
1302
|
-
if type(test_clause) is not bool:
|
1303
|
-
raise MyError(
|
1304
|
-
f"{node[0]} test-expr: expected bool?, got {print_str(test_clause)}"
|
1305
|
-
)
|
1306
|
-
|
1307
|
-
if test_clause:
|
1308
|
-
if len(test_expr) == 1:
|
1309
|
-
return True
|
1310
|
-
|
1311
|
-
for rest_clause in test_expr[1:-1]:
|
1312
|
-
my_eval(env, rest_clause)
|
1313
|
-
return my_eval(env, test_expr[-1])
|
1314
|
-
|
1315
|
-
return None
|
1316
|
-
|
1317
|
-
|
1318
|
-
def syn_case(env: Env, node: Node) -> Any:
|
1319
|
-
val_expr = my_eval(env, node[1])
|
1320
|
-
for case_clause in node[2:]:
|
1321
|
-
if type(case_clause) is not tuple or len(case_clause) != 2:
|
1322
|
-
raise MyError("case: bad syntax")
|
1323
|
-
if type(case_clause[0]) is tuple:
|
1324
|
-
for case in case_clause[0]:
|
1325
|
-
if is_equal(case, val_expr):
|
1326
|
-
return my_eval(env, case_clause[1])
|
1327
|
-
elif type(case_clause[0]) is Sym and case_clause[0].val == "else":
|
1328
|
-
return my_eval(env, case_clause[1])
|
1329
|
-
else:
|
1330
|
-
raise MyError("case: bad syntax")
|
1331
|
-
return None
|
1332
|
-
|
1333
|
-
|
1334
|
-
def syn_let(env: Env, node: Node) -> Any:
|
1335
|
-
if len(node) < 2:
|
1336
|
-
raise MyError(f"{node[0]}: Expected at least 1 term")
|
1337
|
-
|
1338
|
-
if type(node[1]) is Sym:
|
1339
|
-
raise MyError(f"{node[0]}: Named-let form is not supported")
|
1340
|
-
|
1341
|
-
for var_ids in node[1]:
|
1342
|
-
if type(var_ids) is not tuple or len(var_ids) != 2:
|
1343
|
-
raise MyError(f"{node[0]}: Expected two terms: `id` and `val-expr`")
|
1344
|
-
|
1345
|
-
new_maps: dict[str, Any] = {}
|
1346
|
-
for var, val in node[1]:
|
1347
|
-
if type(var) is not Sym:
|
1348
|
-
raise MyError(f"{node[0]}: Expected symbol for `id` term")
|
1349
|
-
new_maps[var.val] = my_eval(env, val)
|
1350
|
-
|
1351
|
-
inner_env = Env(new_maps, env)
|
1352
|
-
for item in node[2:-1]:
|
1353
|
-
my_eval(inner_env, item)
|
1354
|
-
return my_eval(inner_env, node[-1])
|
1355
|
-
|
1356
|
-
|
1357
|
-
def syn_let_star(env: Env, node: Node) -> Any:
|
1358
|
-
if len(node) < 2:
|
1359
|
-
raise MyError(f"{node[0]}: Expected at least 1 term")
|
1360
|
-
|
1361
|
-
for var_ids in node[1]:
|
1362
|
-
if len(var_ids) != 2:
|
1363
|
-
raise MyError(f"{node[0]}: Expected two terms: `id` and `val-expr`")
|
1364
|
-
|
1365
|
-
inner_env = Env({}, env)
|
1366
|
-
|
1367
|
-
for var, val in node[1]:
|
1368
|
-
if type(var) is not Sym:
|
1369
|
-
raise MyError(f"{node[0]}: Expected symbol for `id` term")
|
1370
|
-
inner_env[var.val] = my_eval(inner_env, val)
|
1371
|
-
|
1372
|
-
for item in node[2:-1]:
|
1373
|
-
my_eval(inner_env, item)
|
1374
|
-
return my_eval(inner_env, node[-1])
|
1375
|
-
|
1376
|
-
|
1377
|
-
def syn_import(env: Env, node: Node) -> None:
|
1378
|
-
guard_term(node, 2, 2)
|
1379
|
-
|
1380
|
-
if type(node[1]) is not Sym:
|
1381
|
-
raise MyError("class name must be an identifier")
|
1382
|
-
|
1383
|
-
module = node[1].val
|
1384
|
-
error = MyError(f"No module named `{module}`")
|
1385
|
-
|
1386
|
-
if module != "math":
|
1387
|
-
raise error
|
1388
|
-
try:
|
1389
|
-
obj = __import__("auto_editor.lang.libmath", fromlist=["lang"])
|
1390
|
-
except ImportError:
|
1391
|
-
raise error
|
1392
|
-
|
1393
|
-
env.update(obj.all())
|
1394
|
-
|
1395
|
-
|
1396
|
-
def syn_class(env: Env, node: Node) -> None:
|
1397
|
-
if len(node) < 2:
|
1398
|
-
raise MyError(f"{node[0]}: Expects at least 1 term")
|
1399
|
-
|
1400
|
-
if type(node[1]) is not Sym:
|
1401
|
-
raise MyError("class name must be an identifier")
|
1402
|
-
|
1403
|
-
attr_len = len(node) - 2
|
1404
|
-
attrs: Any = [None] * (attr_len * 2)
|
1405
|
-
contracts = [None] * attr_len
|
1406
|
-
|
1407
|
-
for i, item in enumerate(node[2:]):
|
1408
|
-
if type(item) is not tuple or len(item) != 2:
|
1409
|
-
raise MyError(f"{node[0]}: Invalid syntax")
|
1410
|
-
|
1411
|
-
contracts[i] = my_eval(env, item[1])
|
1412
|
-
attrs[i * 2] = item[0].val
|
1413
|
-
attrs[i * 2 + 1] = contracts[i]
|
1414
|
-
|
1415
|
-
name = node[1].val
|
1416
|
-
pred = name + "?"
|
1417
|
-
attrs = tuple(attrs)
|
1418
|
-
|
1419
|
-
env[name] = Proc(
|
1420
|
-
name,
|
1421
|
-
lambda *args: PaletClass(name, attrs, list(args)),
|
1422
|
-
(attr_len, attr_len),
|
1423
|
-
*contracts,
|
1424
|
-
)
|
1425
|
-
env[pred] = Proc(
|
1426
|
-
pred,
|
1427
|
-
lambda v: type(v) is PaletClass and v.name == name and v.attrs == attrs,
|
1428
|
-
(1, 1),
|
1429
|
-
)
|
1430
|
-
|
1431
|
-
|
1432
|
-
def attr(env: Env, node: Node) -> Any:
|
1433
|
-
guard_term(node, 3, 3)
|
1434
|
-
|
1435
|
-
if type(node[2]) is not Sym:
|
1436
|
-
raise MyError("@r: attribute must be an identifier")
|
1437
|
-
|
1438
|
-
base = my_eval(env, node[1])
|
1439
|
-
if type(base) is PaletClass:
|
1440
|
-
if type(name := node[2]) is not Sym:
|
1441
|
-
raise MyError("@r: class attribute must be an identifier")
|
515
|
+
is_iterable = Contract(
|
516
|
+
"iterable?",
|
517
|
+
lambda v: type(v) in (str, range, list, tuple, dict, Quoted)
|
518
|
+
or isinstance(v, np.ndarray),
|
519
|
+
)
|
520
|
+
is_boolarr = Contract(
|
521
|
+
"bool-array?",
|
522
|
+
lambda v: isinstance(v, np.ndarray) and v.dtype.kind == "b",
|
523
|
+
)
|
1442
524
|
|
1443
|
-
for i, item in enumerate(base.attrs[0::2]):
|
1444
|
-
if name.val == item:
|
1445
|
-
return base.values[i]
|
1446
525
|
|
1447
|
-
|
526
|
+
def raise_(msg: str | Exception) -> NoReturn:
|
527
|
+
raise MyError(msg)
|
1448
528
|
|
1449
529
|
|
1450
530
|
def edit_none() -> np.ndarray:
|
@@ -1554,16 +634,41 @@ def edit_subtitle(pattern, stream=0, **kwargs):
|
|
1554
634
|
return raise_(e) if levels.strict else levels.all()
|
1555
635
|
|
1556
636
|
|
637
|
+
class StackTraceManager:
|
638
|
+
def __init__(self) -> None:
|
639
|
+
self.stack: list[Sym] = []
|
640
|
+
|
641
|
+
def push(self, sym: Sym) -> None:
|
642
|
+
self.stack.append(sym)
|
643
|
+
|
644
|
+
def pop(self) -> None:
|
645
|
+
if self.stack:
|
646
|
+
self.stack.pop()
|
647
|
+
|
648
|
+
def get_stacktrace(self) -> str:
|
649
|
+
return "\n".join(
|
650
|
+
f" at {sym.val} ({sym.lineno}:{sym.column})"
|
651
|
+
for sym in reversed(self.stack)
|
652
|
+
)
|
653
|
+
|
654
|
+
|
655
|
+
stack_trace_manager = StackTraceManager()
|
656
|
+
|
657
|
+
|
1557
658
|
def my_eval(env: Env, node: object) -> Any:
|
659
|
+
def make_trace(sym: Sym) -> str:
|
660
|
+
return f" at {sym.val} ({sym.lineno}:{sym.column})"
|
661
|
+
|
1558
662
|
if type(node) is Sym:
|
1559
663
|
val = env.get(node.val)
|
1560
664
|
if type(val) is NotFound:
|
665
|
+
stacktrace = make_trace(node)
|
1561
666
|
if mat := get_close_matches(node.val, env.data):
|
1562
667
|
raise MyError(
|
1563
|
-
f"variable `{node.val}` not found. Did you mean: {mat[0]}"
|
668
|
+
f"variable `{node.val}` not found. Did you mean: {mat[0]}\n{stacktrace}"
|
1564
669
|
)
|
1565
670
|
raise MyError(
|
1566
|
-
f"variable `{node.val}` not found. Did you mean a string literal
|
671
|
+
f"variable `{node.val}` not found. Did you mean a string literal.\n{stacktrace}"
|
1567
672
|
)
|
1568
673
|
return val
|
1569
674
|
|
@@ -1575,44 +680,56 @@ def my_eval(env: Env, node: object) -> Any:
|
|
1575
680
|
raise MyError("Illegal () expression")
|
1576
681
|
|
1577
682
|
oper = my_eval(env, node[0])
|
1578
|
-
if
|
1579
|
-
|
1580
|
-
...No one wants to write (aref a x y) when they could write a[x,y].
|
1581
|
-
In this particular case there is a way to finesse our way out of the
|
1582
|
-
problem. If we treat data structures as if they were functions on indexes,
|
1583
|
-
we could write (a x y) instead, which is even shorter than the Perl form.
|
1584
|
-
"""
|
1585
|
-
if is_iterable(oper):
|
1586
|
-
length = len(node[1:])
|
1587
|
-
if length > 3:
|
1588
|
-
raise MyError(f"{print_str(node[0])}: slice expects 1 argument")
|
1589
|
-
if length in (2, 3):
|
1590
|
-
return p_slice(oper, *(my_eval(env, c) for c in node[1:]))
|
1591
|
-
if length == 1:
|
1592
|
-
return ref(oper, my_eval(env, node[1]))
|
683
|
+
if isinstance(node[0], Sym):
|
684
|
+
stack_trace_manager.push(node[0])
|
1593
685
|
|
1594
|
-
|
1595
|
-
|
1596
|
-
|
686
|
+
try:
|
687
|
+
if not callable(oper):
|
688
|
+
"""
|
689
|
+
...No one wants to write (aref a x y) when they could write a[x,y].
|
690
|
+
In this particular case there is a way to finesse our way out of the
|
691
|
+
problem. If we treat data structures as if they were functions on indexes,
|
692
|
+
we could write (a x y) instead, which is even shorter than the Perl form.
|
693
|
+
"""
|
694
|
+
if is_iterable(oper):
|
695
|
+
length = len(node[1:])
|
696
|
+
if length > 3:
|
697
|
+
raise MyError(f"{print_str(node[0])}: slice expects 1 argument")
|
698
|
+
if length in (2, 3):
|
699
|
+
return p_slice(oper, *(my_eval(env, c) for c in node[1:]))
|
700
|
+
if length == 1:
|
701
|
+
return ref(oper, my_eval(env, node[1]))
|
1597
702
|
|
1598
|
-
|
1599
|
-
|
703
|
+
raise MyError(
|
704
|
+
f"{print_str(oper)} is not a function. Tried to run with args: {print_str(node[1:])}"
|
705
|
+
)
|
1600
706
|
|
1601
|
-
|
1602
|
-
|
1603
|
-
|
1604
|
-
|
1605
|
-
|
1606
|
-
|
707
|
+
if type(oper) is Syntax:
|
708
|
+
return oper(env, node)
|
709
|
+
|
710
|
+
i = 1
|
711
|
+
args: list[Any] = []
|
712
|
+
kwargs: dict[str, Any] = {}
|
713
|
+
while i < len(node):
|
714
|
+
result = my_eval(env, node[i])
|
715
|
+
if type(result) is Keyword:
|
716
|
+
i += 1
|
717
|
+
if i >= len(node):
|
718
|
+
raise MyError("Keyword need argument")
|
719
|
+
kwargs[result.val] = my_eval(env, node[i])
|
720
|
+
else:
|
721
|
+
args.append(result)
|
1607
722
|
i += 1
|
1608
|
-
if i >= len(node):
|
1609
|
-
raise MyError("Keyword need argument")
|
1610
|
-
kwargs[result.val] = my_eval(env, node[i])
|
1611
|
-
else:
|
1612
|
-
args.append(result)
|
1613
|
-
i += 1
|
1614
723
|
|
1615
|
-
|
724
|
+
return oper(*args, **kwargs)
|
725
|
+
except MyError as e:
|
726
|
+
error_msg = str(e)
|
727
|
+
if not error_msg.endswith(make_trace(node[0])):
|
728
|
+
error_msg += f"\n{make_trace(node[0])}"
|
729
|
+
raise MyError(error_msg)
|
730
|
+
finally:
|
731
|
+
if isinstance(node[0], Sym):
|
732
|
+
stack_trace_manager.pop()
|
1616
733
|
|
1617
734
|
return node
|
1618
735
|
|
@@ -1620,11 +737,6 @@ def my_eval(env: Env, node: object) -> Any:
|
|
1620
737
|
# fmt: off
|
1621
738
|
env = Env({})
|
1622
739
|
env.update({
|
1623
|
-
# constants
|
1624
|
-
"true": True,
|
1625
|
-
"false": False,
|
1626
|
-
"all": Sym("all"),
|
1627
|
-
# edit procedures
|
1628
740
|
"none": Proc("none", edit_none, (0, 0)),
|
1629
741
|
"all/e": Proc("all/e", edit_all, (0, 0)),
|
1630
742
|
"audio-levels": Proc("audio-levels", audio_levels, (1, 1), is_nat),
|
@@ -1641,218 +753,6 @@ env.update({
|
|
1641
753
|
is_str, is_nat, is_bool, orc(is_nat, is_void),
|
1642
754
|
{"pattern": 0, "stream": 1, "ignore-case": 2, "max-count": 3}
|
1643
755
|
),
|
1644
|
-
# syntax
|
1645
|
-
"lambda": Syntax(syn_lambda),
|
1646
|
-
"λ": Syntax(syn_lambda),
|
1647
|
-
"define": Syntax(syn_define),
|
1648
|
-
"define/c": Syntax(syn_definec),
|
1649
|
-
"set!": Syntax(syn_set),
|
1650
|
-
"incf": Syntax(syn_incf),
|
1651
|
-
"decf": Syntax(syn_decf),
|
1652
|
-
"&=": Syntax(syn_strappend),
|
1653
|
-
"quote": Syntax(syn_quote),
|
1654
|
-
"if": Syntax(syn_if),
|
1655
|
-
"when": Syntax(syn_when),
|
1656
|
-
"cond": Syntax(syn_cond),
|
1657
|
-
"case": Syntax(syn_case),
|
1658
|
-
"let": Syntax(syn_let),
|
1659
|
-
"let*": Syntax(syn_let_star),
|
1660
|
-
"import": Syntax(syn_import),
|
1661
|
-
"class": Syntax(syn_class),
|
1662
|
-
"@r": Syntax(attr),
|
1663
|
-
# loops
|
1664
|
-
"for": Syntax(syn_for),
|
1665
|
-
"for-items": Syntax(syn_for_items),
|
1666
|
-
# contracts
|
1667
|
-
"number?": is_num,
|
1668
|
-
"real?": is_real,
|
1669
|
-
"int?": is_int,
|
1670
|
-
"float?": is_float,
|
1671
|
-
"frac?": is_frac,
|
1672
|
-
"complex?": Contract("complex?", lambda v: type(v) is complex),
|
1673
|
-
"nat?": is_nat,
|
1674
|
-
"nat1?": is_nat1,
|
1675
|
-
"threshold?": is_threshold,
|
1676
|
-
"any": any_p,
|
1677
|
-
"bool?": is_bool,
|
1678
|
-
"void?": is_void,
|
1679
|
-
"symbol?": (is_symbol := Contract("symbol?", lambda v: type(v) is Sym)),
|
1680
|
-
"string?": is_str,
|
1681
|
-
"char?": (is_char := Contract("char?", lambda v: type(v) is Char)),
|
1682
|
-
"list?": (is_list := Contract("list?", lambda v: type(v) is Quoted or type(v) is tuple)),
|
1683
|
-
"vector?": (is_vector := Contract("vector?", lambda v: type(v) is list)),
|
1684
|
-
"array?": (is_array := Contract("array?", lambda v: isinstance(v, np.ndarray))),
|
1685
|
-
"bool-array?": is_boolarr,
|
1686
|
-
"range?": (is_range := Contract("range?", lambda v: type(v) is range)),
|
1687
|
-
"iterable?": is_iterable,
|
1688
|
-
"sequence?": is_sequence,
|
1689
|
-
"procedure?": is_proc,
|
1690
|
-
"contract?": is_cont,
|
1691
|
-
"hash?": (is_hash := Contract("hash?", lambda v: isinstance(v, dict))),
|
1692
|
-
"begin": Proc("begin", lambda *x: x[-1] if x else None, (0, None)),
|
1693
|
-
"void": Proc("void", lambda *v: None, (0, 0)),
|
1694
|
-
# control / b-arrays
|
1695
|
-
"not": Proc("not", lambda v: not v if type(v) is bool else logical_not(v), (1, 1), bool_or_barr),
|
1696
|
-
"and": Syntax(syn_and),
|
1697
|
-
"or": Syntax(syn_or),
|
1698
|
-
"xor": Proc("xor", _xor, (2, None), bool_or_barr),
|
1699
|
-
# booleans
|
1700
|
-
">": Proc(">", gt, (2, 2), is_real),
|
1701
|
-
">=": Proc(">=", ge, (2, 2), is_real),
|
1702
|
-
"<": Proc("<", lt, (2, 2), is_real),
|
1703
|
-
"<=": Proc("<=", le, (2, 2), is_real),
|
1704
|
-
"=": Proc("=", equal_num, (1, None), is_num),
|
1705
|
-
"eq?": Proc("eq?", is_, (2, 2)),
|
1706
|
-
"equal?": Proc("equal?", is_equal, (2, 2)),
|
1707
|
-
"zero?": UserProc(env, "zero?", ["z"], (is_num,), ((Sym("="), Sym("z"), 0),)),
|
1708
|
-
"positive?": UserProc(env, "positive?", ["x"], (is_real,), ((Sym(">"), Sym("x"), 0),)),
|
1709
|
-
"negative?": UserProc(env, "negative?", ["x"], (is_real,), ((Sym("<"), Sym("x"), 0),)),
|
1710
|
-
"even?": UserProc(
|
1711
|
-
env, "even?", ["n"], (is_int,), ((Sym("zero?"), (Sym("mod"), Sym("n"), 2)),)),
|
1712
|
-
"odd?": UserProc(
|
1713
|
-
env, "odd?", ["n"], (is_int,), ((Sym("not"), (Sym("even?"), Sym("n"))),)),
|
1714
|
-
">=/c": Proc(">=/c", gte_c, (1, 1), is_real),
|
1715
|
-
">/c": Proc(">/c", gt_c, (1, 1), is_real),
|
1716
|
-
"<=/c": Proc("<=/c", lte_c, (1, 1), is_real),
|
1717
|
-
"</c": Proc("</c", lt_c, (1, 1), is_real),
|
1718
|
-
"between/c": Proc("between/c", between_c, (2, 2), is_real),
|
1719
|
-
# numbers
|
1720
|
-
"+": Proc("+", lambda *v: sum(v), (0, None), is_num),
|
1721
|
-
"-": Proc("-", minus, (1, None), is_num),
|
1722
|
-
"*": Proc("*", lambda *v: reduce(mul, v, 1), (0, None), is_num),
|
1723
|
-
"/": Proc("/", num_div, (1, None), is_num),
|
1724
|
-
"div": Proc("div", int_div, (2, None), is_int),
|
1725
|
-
"add1": Proc("add1", lambda z: z + 1, (1, 1), is_num),
|
1726
|
-
"sub1": Proc("sub1", lambda z: z - 1, (1, 1), is_num),
|
1727
|
-
"sqrt": Proc("sqrt", _sqrt, (1, 1), is_num),
|
1728
|
-
"real-part": Proc("real-part", lambda v: v.real, (1, 1), is_num),
|
1729
|
-
"imag-part": Proc("imag-part", lambda v: v.imag, (1, 1), is_num),
|
1730
|
-
# reals
|
1731
|
-
"pow": Proc("pow", pow, (2, 2), is_real),
|
1732
|
-
"abs": Proc("abs", abs, (1, 1), is_real),
|
1733
|
-
"round": Proc("round", round, (1, 1), is_real),
|
1734
|
-
"max": Proc("max", lambda *v: max(v), (1, None), is_real),
|
1735
|
-
"min": Proc("min", lambda *v: min(v), (1, None), is_real),
|
1736
|
-
"max-seq": Proc("max-seq", max, (1, 1), is_sequence),
|
1737
|
-
"min-seq": Proc("min-seq", min, (1, 1), is_sequence),
|
1738
|
-
"mod": Proc("mod", mod, (2, 2), is_int),
|
1739
|
-
"modulo": Proc("modulo", mod, (2, 2), is_int),
|
1740
|
-
# symbols
|
1741
|
-
"symbol->string": Proc("symbol->string", str, (1, 1), is_symbol),
|
1742
|
-
"string->symbol": Proc("string->symbol", Sym, (1, 1), is_str),
|
1743
|
-
# strings
|
1744
|
-
"string": Proc("string", lambda *v: reduce(add, v, ""), (0, None), is_char),
|
1745
|
-
"&": Proc("&", lambda *v: reduce(add, v, ""), (0, None), is_str),
|
1746
|
-
"split": Proc("split", str.split, (1, 2), is_str, is_str),
|
1747
|
-
"strip": Proc("strip", str.strip, (1, 1), is_str),
|
1748
|
-
"str-repeat": Proc("str-repeat", mul, (2, 2), is_str, is_int),
|
1749
|
-
"startswith": Proc("startswith", str.startswith, (2, 2), is_str),
|
1750
|
-
"endswith": Proc("endswith", str.endswith, (2, 2), is_str),
|
1751
|
-
"replace": Proc("replace", str.replace, (3, 4), is_str, is_str, is_str, is_int),
|
1752
|
-
"title": Proc("title", str.title, (1, 1), is_str),
|
1753
|
-
"lower": Proc("lower", str.lower, (1, 1), is_str),
|
1754
|
-
"upper": Proc("upper", str.upper, (1, 1), is_str),
|
1755
|
-
"join": Proc("join", palet_join, (2, 2), is_vector, is_str),
|
1756
|
-
# format
|
1757
|
-
"char->int": Proc("char->int", lambda c: ord(c.val), (1, 1), is_char),
|
1758
|
-
"int->char": Proc("int->char", Char, (1, 1), is_int),
|
1759
|
-
"~a": Proc("~a", lambda *v: "".join([display_str(a) for a in v]), (0, None)),
|
1760
|
-
"~s": Proc("~s", lambda *v: " ".join([display_str(a) for a in v]), (0, None)),
|
1761
|
-
"~v": Proc("~v", lambda *v: " ".join([print_str(a) for a in v]), (0, None)),
|
1762
|
-
# keyword
|
1763
|
-
"keyword?": is_keyw,
|
1764
|
-
"keyword->string": Proc("keyword->string", lambda v: v.val.val, (1, 1), is_keyw),
|
1765
|
-
"string->keyword": Proc("string->keyword", QuotedKeyword, (1, 1), is_str),
|
1766
|
-
# lists
|
1767
|
-
"list": Proc("list", lambda *a: Quoted(a), (0, None)),
|
1768
|
-
"append": Proc("append", list_append, (0, None), is_list),
|
1769
|
-
# vectors
|
1770
|
-
"vector": Proc("vector", lambda *a: list(a), (0, None)),
|
1771
|
-
"make-vector": Proc(
|
1772
|
-
"make-vector", lambda size, a=0: [a] * size, (1, 2), is_nat, any_p
|
1773
|
-
),
|
1774
|
-
"add!": Proc("add!", list.append, (2, 2), is_vector, any_p),
|
1775
|
-
"pop!": Proc("pop!", list.pop, (1, 1), is_vector),
|
1776
|
-
"vec-set!": Proc("vec-set!", vector_set, (3, 3), is_vector, is_int, any_p),
|
1777
|
-
"vec-append": Proc("vec-append", lambda *v: reduce(add, v, []), (0, None), is_vector),
|
1778
|
-
"vec-extend!": Proc("vec-extend!", vector_extend, (2, None), is_vector),
|
1779
|
-
"sort": Proc("sort", sorted, (1, 1), is_vector),
|
1780
|
-
"sort!": Proc("sort!", list.sort, (1, 1), is_vector),
|
1781
|
-
# arrays
|
1782
|
-
"array": Proc("array", array_proc, (2, None), is_symbol, is_real),
|
1783
|
-
"make-array": Proc("make-array", make_array, (2, 3), is_symbol, is_nat, is_real),
|
1784
|
-
"array-splice!": Proc(
|
1785
|
-
"array-splice!", splice, (2, 4), is_array, is_real, is_int, is_int
|
1786
|
-
),
|
1787
|
-
"array-copy": Proc("array-copy", np.copy, (1, 1), is_array),
|
1788
|
-
"count-nonzero": Proc("count-nonzero", np.count_nonzero, (1, 1), is_array),
|
1789
|
-
# bool arrays
|
1790
|
-
"bool-array": Proc(
|
1791
|
-
"bool-array", lambda *a: np.array(a, dtype=np.bool_), (1, None), is_nat
|
1792
|
-
),
|
1793
|
-
"margin": Proc("margin", margin, (2, 3), is_boolarr, is_int),
|
1794
|
-
"mincut": Proc("mincut", mincut, (2, 2), is_boolarr, is_nat),
|
1795
|
-
"minclip": Proc("minclip", minclip, (2, 2), is_boolarr, is_nat),
|
1796
|
-
"maxcut": Proc("maxcut", maxcut, (2, 2), is_boolarr, is_nat),
|
1797
|
-
"maxclip": Proc("maxclip", maxclip, (2, 2), is_boolarr, is_nat),
|
1798
|
-
# ranges
|
1799
|
-
"range": Proc("range", range, (1, 3), is_int, is_int, int_not_zero),
|
1800
|
-
# generic iterables
|
1801
|
-
"len": Proc("len", len, (1, 1), is_iterable),
|
1802
|
-
"reverse": Proc("reverse", lambda v: v[::-1], (1, 1), is_sequence),
|
1803
|
-
"ref": Proc("ref", ref, (2, 2), is_sequence, is_int),
|
1804
|
-
"slice": Proc("slice", p_slice, (2, 4), is_sequence, is_int),
|
1805
|
-
# procedures
|
1806
|
-
"map": Proc("map", palet_map, (2, 2), is_proc, is_sequence),
|
1807
|
-
"apply": Proc("apply", lambda p, s: p(*s), (2, 2), is_proc, is_sequence),
|
1808
|
-
"and/c": Proc("and/c", andc, (1, None), is_cont),
|
1809
|
-
"or/c": Proc("or/c", orc, (1, None), is_cont),
|
1810
|
-
"not/c": Proc("not/c", notc, (1, 1), is_cont),
|
1811
|
-
# hashs
|
1812
|
-
"hash": Proc("hash", palet_hash, (0, None)),
|
1813
|
-
"hash-ref": Proc("hash", hash_ref, (2, 2), is_hash, any_p),
|
1814
|
-
"hash-set!": Proc("hash-set!", hash_set, (3, 3), is_hash, any_p, any_p),
|
1815
|
-
"has-key?": Proc("has-key?", lambda h, k: k in h, (2, 2), is_hash, any_p),
|
1816
|
-
"hash-remove!": Proc("hash-remove!", hash_remove, (2, 2), is_hash, any_p),
|
1817
|
-
"hash-update!": UserProc(env, "hash-update!", ["h", "v", "up"], (is_hash, any_p),
|
1818
|
-
(
|
1819
|
-
(Sym("hash-set!"), Sym("h"), Sym("v"), (Sym("up"), (Sym("h"), Sym("v"))),),
|
1820
|
-
),
|
1821
|
-
),
|
1822
|
-
# i/o
|
1823
|
-
"open-output-file": Proc("open-output-file", initOutPort, (1, 1), is_str),
|
1824
|
-
"output-port?": (op := Contract("output-port?", lambda v: type(v) is OutputPort)),
|
1825
|
-
"close-port": Proc("close-port", OutputPort.close, (1, 1), op),
|
1826
|
-
"closed?": Proc("closed?", lambda o: o.closed, (1, 1), op),
|
1827
|
-
# printing
|
1828
|
-
"display": Proc("display",
|
1829
|
-
lambda v, f=None: print(display_str(v), end="", file=f), (1, 2), any_p, op),
|
1830
|
-
"displayln": Proc("displayln",
|
1831
|
-
lambda v, f=None: print(display_str(v), file=f), (1, 2), any_p, op),
|
1832
|
-
"print": Proc("print",
|
1833
|
-
lambda v, f=None: print(print_str(v), end="", file=f), (1, 2), any_p, op),
|
1834
|
-
"println": Proc("println",
|
1835
|
-
lambda v, f=None: print(print_str(v), file=f), (1, 2), any_p, op),
|
1836
|
-
# actions
|
1837
|
-
"assert": Proc("assert", palet_assert, (1, 2), any_p, orc(is_str, False)),
|
1838
|
-
"error": Proc("error", raise_, (1, 1), is_str),
|
1839
|
-
"sleep": Proc("sleep", sleep, (1, 1), is_int_or_float),
|
1840
|
-
"system": Proc("system", palet_system, (1, 1), is_str),
|
1841
|
-
# conversions
|
1842
|
-
"number->string": Proc("number->string", number_to_string, (1, 1), is_num),
|
1843
|
-
"string->vector": Proc(
|
1844
|
-
"string->vector", lambda s: [Char(c) for c in s], (1, 1), is_str
|
1845
|
-
),
|
1846
|
-
"range->vector": Proc("range->vector", list, (1, 1), is_range),
|
1847
|
-
# reflexion
|
1848
|
-
"var-exists?": Proc("var-exists?", lambda sym: sym.val in env, (1, 1), is_symbol),
|
1849
|
-
"rename": Syntax(syn_rename),
|
1850
|
-
"delete": Syntax(syn_delete),
|
1851
|
-
"eval": Proc("eval",
|
1852
|
-
lambda tl: my_eval(env, tl.val) if type(tl) is Quoted
|
1853
|
-
else (my_eval(env, tl) if type(tl) is Sym else tl),
|
1854
|
-
(1, 1)
|
1855
|
-
),
|
1856
756
|
})
|
1857
757
|
# fmt: on
|
1858
758
|
|