auto-editor 23.35.1__py3-none-any.whl → 23.40.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.
- auto_editor/__init__.py +2 -2
- auto_editor/analyze.py +19 -23
- auto_editor/ffwrapper.py +4 -5
- auto_editor/formats/fcp7.py +37 -0
- auto_editor/help.py +10 -10
- auto_editor/lang/palet.py +387 -265
- auto_editor/lib/contracts.py +82 -45
- auto_editor/lib/data_structs.py +72 -4
- auto_editor/make_layers.py +24 -15
- auto_editor/render/video.py +2 -5
- auto_editor/subcommands/repl.py +4 -3
- auto_editor/subcommands/test.py +3 -3
- auto_editor/timeline.py +16 -16
- auto_editor/utils/container.py +67 -78
- auto_editor/utils/encoder.py +133 -195
- {auto_editor-23.35.1.dist-info → auto_editor-23.40.1.dist-info}/METADATA +35 -10
- {auto_editor-23.35.1.dist-info → auto_editor-23.40.1.dist-info}/RECORD +22 -22
- {auto_editor-23.35.1.dist-info → auto_editor-23.40.1.dist-info}/LICENSE +0 -0
- {auto_editor-23.35.1.dist-info → auto_editor-23.40.1.dist-info}/WHEEL +0 -0
- {auto_editor-23.35.1.dist-info → auto_editor-23.40.1.dist-info}/entry_points.txt +0 -0
- {auto_editor-23.35.1.dist-info → auto_editor-23.40.1.dist-info}/top_level.txt +0 -0
- {auto_editor-23.35.1.dist-info → auto_editor-23.40.1.dist-info}/zip-safe +0 -0
auto_editor/lang/palet.py
CHANGED
@@ -8,7 +8,7 @@ from __future__ import annotations
|
|
8
8
|
|
9
9
|
import cmath
|
10
10
|
import math
|
11
|
-
import
|
11
|
+
from dataclasses import dataclass
|
12
12
|
from difflib import get_close_matches
|
13
13
|
from fractions import Fraction
|
14
14
|
from functools import reduce
|
@@ -17,6 +17,7 @@ from time import sleep
|
|
17
17
|
from typing import TYPE_CHECKING
|
18
18
|
|
19
19
|
import numpy as np
|
20
|
+
from numpy import logical_and, logical_not, logical_or, logical_xor
|
20
21
|
|
21
22
|
from auto_editor.analyze import edit_method, mut_remove_large, mut_remove_small
|
22
23
|
from auto_editor.lib.contracts import *
|
@@ -26,7 +27,7 @@ from auto_editor.utils.func import boolop, mut_margin
|
|
26
27
|
|
27
28
|
if TYPE_CHECKING:
|
28
29
|
from collections.abc import Callable
|
29
|
-
from typing import Any, NoReturn
|
30
|
+
from typing import Any, Literal, NoReturn
|
30
31
|
|
31
32
|
from numpy.typing import NDArray
|
32
33
|
|
@@ -45,11 +46,10 @@ class ClosingError(MyError):
|
|
45
46
|
# #
|
46
47
|
###############################################################################
|
47
48
|
|
48
|
-
SEC_UNITS = ("s", "sec", "secs", "second", "seconds")
|
49
|
-
VAL, QUOTE, SEC, DB, PER, DOT = "VAL", "QUOTE", "SEC", "DB", "PER", "DOT"
|
50
49
|
LPAREN, RPAREN, LBRAC, RBRAC, LCUR, RCUR, EOF = "(", ")", "[", "]", "{", "}", "EOF"
|
51
|
-
VLIT = "VLIT"
|
52
|
-
|
50
|
+
VAL, QUOTE, SEC, DB, DOT, VLIT = "VAL", "QUOTE", "SEC", "DB", "DOT", "VLIT"
|
51
|
+
SEC_UNITS = ("s", "sec", "secs", "second", "seconds")
|
52
|
+
METHODS = ("audio:", "motion:", "pixeldiff:", "subtitle:")
|
53
53
|
brac_pairs = {LPAREN: RPAREN, LBRAC: RBRAC, LCUR: RCUR}
|
54
54
|
|
55
55
|
str_escape = {
|
@@ -65,17 +65,10 @@ str_escape = {
|
|
65
65
|
}
|
66
66
|
|
67
67
|
|
68
|
+
@dataclass(slots=True)
|
68
69
|
class Token:
|
69
|
-
|
70
|
-
|
71
|
-
def __init__(self, type: str, value: Any):
|
72
|
-
self.type = type
|
73
|
-
self.value = value
|
74
|
-
|
75
|
-
def __str__(self) -> str:
|
76
|
-
return f"(Token {print_str(self.type)} {print_str(self.value)})"
|
77
|
-
|
78
|
-
__repr__ = __str__
|
70
|
+
type: str
|
71
|
+
value: Any
|
79
72
|
|
80
73
|
|
81
74
|
class Lexer:
|
@@ -171,19 +164,16 @@ class Lexer:
|
|
171
164
|
token = SEC
|
172
165
|
elif unit == "dB":
|
173
166
|
token = DB
|
174
|
-
elif unit
|
175
|
-
token = PER
|
176
|
-
elif unit != "i":
|
167
|
+
elif unit != "i" and unit != "%":
|
177
168
|
return Token(VAL, Sym(result + unit))
|
178
169
|
|
179
170
|
try:
|
180
171
|
if unit == "i":
|
181
172
|
return Token(VAL, complex(result + "j"))
|
173
|
+
elif unit == "%":
|
174
|
+
return Token(VAL, float(result) / 100)
|
182
175
|
elif "/" in result:
|
183
|
-
|
184
|
-
if val.denominator == 1:
|
185
|
-
return Token(token, val.numerator)
|
186
|
-
return Token(token, val)
|
176
|
+
return Token(token, Fraction(result))
|
187
177
|
elif "." in result:
|
188
178
|
return Token(token, float(result))
|
189
179
|
else:
|
@@ -201,6 +191,16 @@ class Lexer:
|
|
201
191
|
self.advance()
|
202
192
|
return Token(VAL, Char(char))
|
203
193
|
|
194
|
+
if self.char == ":":
|
195
|
+
self.advance()
|
196
|
+
buf = StringIO()
|
197
|
+
while self.char_is_norm():
|
198
|
+
assert self.char is not None
|
199
|
+
buf.write(self.char)
|
200
|
+
self.advance()
|
201
|
+
|
202
|
+
return Token(VAL, Keyword(buf.getvalue()))
|
203
|
+
|
204
204
|
if self.char is not None and self.char in "([{":
|
205
205
|
brac_type = self.char
|
206
206
|
self.advance()
|
@@ -368,14 +368,12 @@ class Lexer:
|
|
368
368
|
###############################################################################
|
369
369
|
|
370
370
|
|
371
|
+
@dataclass(slots=True)
|
371
372
|
class Method:
|
372
|
-
|
373
|
-
|
374
|
-
def __init__(self, val: str):
|
375
|
-
self.val = val
|
373
|
+
val: str
|
376
374
|
|
377
375
|
def __str__(self) -> str:
|
378
|
-
return f
|
376
|
+
return f"#<method:{self.val}>"
|
379
377
|
|
380
378
|
__repr__ = __str__
|
381
379
|
|
@@ -405,6 +403,7 @@ class Parser:
|
|
405
403
|
self.eat()
|
406
404
|
return [list, lit_arr]
|
407
405
|
|
406
|
+
# Handle unhygienic macros in next four cases
|
408
407
|
if token.type == SEC:
|
409
408
|
self.eat()
|
410
409
|
return [Sym("round"), [Sym("*"), token.value, Sym("timebase")]]
|
@@ -413,10 +412,6 @@ class Parser:
|
|
413
412
|
self.eat()
|
414
413
|
return [Sym("pow"), 10, [Sym("/"), token.value, 20]]
|
415
414
|
|
416
|
-
if token.type == PER:
|
417
|
-
self.eat()
|
418
|
-
return [Sym("/"), token.value, 100.0]
|
419
|
-
|
420
415
|
if token.type == DOT:
|
421
416
|
self.eat()
|
422
417
|
if type(token.value[1].value) is not Sym:
|
@@ -463,43 +458,15 @@ class Parser:
|
|
463
458
|
###############################################################################
|
464
459
|
|
465
460
|
|
466
|
-
def check_args(
|
467
|
-
o: str,
|
468
|
-
values: list | tuple,
|
469
|
-
arity: tuple[int, int | None],
|
470
|
-
cont: list[Contract] | None,
|
471
|
-
) -> None:
|
472
|
-
lower, upper = arity
|
473
|
-
amount = len(values)
|
474
|
-
if upper is not None and lower > upper:
|
475
|
-
raise ValueError("lower must be less than upper")
|
476
|
-
if lower == upper and len(values) != lower:
|
477
|
-
raise MyError(f"{o}: Arity mismatch. Expected {lower}, got {amount}")
|
478
|
-
|
479
|
-
if upper is None and amount < lower:
|
480
|
-
raise MyError(f"{o}: Arity mismatch. Expected at least {lower}, got {amount}")
|
481
|
-
if upper is not None and (amount > upper or amount < lower):
|
482
|
-
raise MyError(
|
483
|
-
f"{o}: Arity mismatch. Expected between {lower} and {upper}, got {amount}"
|
484
|
-
)
|
485
|
-
|
486
|
-
if cont is None:
|
487
|
-
return
|
488
|
-
|
489
|
-
for i, val in enumerate(values):
|
490
|
-
check = cont[-1] if i >= len(cont) else cont[i]
|
491
|
-
if not check_contract(check, val):
|
492
|
-
raise MyError(f"{o} expected a {check.name}, got {print_str(val)}")
|
493
|
-
|
494
|
-
|
495
461
|
is_cont = Contract("contract?", is_contract)
|
496
462
|
is_iterable = Contract(
|
497
463
|
"iterable?",
|
498
|
-
lambda v: type(v) in (str, range
|
464
|
+
lambda v: type(v) in (str, range, Quoted)
|
465
|
+
or isinstance(v, (list, dict, np.ndarray)),
|
499
466
|
)
|
500
467
|
is_sequence = Contract(
|
501
468
|
"sequence?",
|
502
|
-
lambda v: type(v) in (str, range) or isinstance(v, (list, np.ndarray)),
|
469
|
+
lambda v: type(v) in (str, range, Quoted) or isinstance(v, (list, np.ndarray)),
|
503
470
|
)
|
504
471
|
is_boolarr = Contract(
|
505
472
|
"bool-array?",
|
@@ -509,6 +476,32 @@ bool_or_barr = Contract(
|
|
509
476
|
"(or/c bool? bool-array?)",
|
510
477
|
lambda v: type(v) is bool or is_boolarr(v),
|
511
478
|
)
|
479
|
+
is_keyw = Contract("keyword?", lambda v: type(v) is QuotedKeyword)
|
480
|
+
|
481
|
+
|
482
|
+
@dataclass(slots=True)
|
483
|
+
class OutputPort:
|
484
|
+
name: str
|
485
|
+
port: Any
|
486
|
+
write: Any
|
487
|
+
closed: bool
|
488
|
+
|
489
|
+
def close(self) -> None:
|
490
|
+
if not self.closed:
|
491
|
+
self.port.close()
|
492
|
+
|
493
|
+
def __str__(self) -> str:
|
494
|
+
return f"#<output-port:{self.name}>"
|
495
|
+
|
496
|
+
__repr__ = __str__
|
497
|
+
|
498
|
+
|
499
|
+
def initOutPort(name: str) -> OutputPort | Literal[False]:
|
500
|
+
try:
|
501
|
+
port = open(name, "w", encoding="utf-8")
|
502
|
+
except Exception:
|
503
|
+
return False
|
504
|
+
return OutputPort(name, port, port.write, False)
|
512
505
|
|
513
506
|
|
514
507
|
def raise_(msg: str) -> None:
|
@@ -544,13 +537,8 @@ def num_div(z: Number, *w: Number) -> Number:
|
|
544
537
|
if num == 0:
|
545
538
|
raise MyError("/: division by zero")
|
546
539
|
|
547
|
-
if type(num) is int:
|
548
|
-
num = Fraction(num)
|
549
|
-
|
550
540
|
z /= num
|
551
541
|
|
552
|
-
if type(z) is Fraction and z.denominator == 1:
|
553
|
-
return z.numerator
|
554
542
|
return z
|
555
543
|
|
556
544
|
|
@@ -572,9 +560,9 @@ def _sqrt(v: Number) -> Number:
|
|
572
560
|
|
573
561
|
def _xor(*vals: Any) -> bool | BoolList:
|
574
562
|
if is_boolarr(vals[0]):
|
575
|
-
check_args("xor", vals, (2, None),
|
576
|
-
return reduce(lambda a, b: boolop(a, b,
|
577
|
-
check_args("xor", vals, (2, None),
|
563
|
+
check_args("xor", vals, (2, None), (is_boolarr,))
|
564
|
+
return reduce(lambda a, b: boolop(a, b, logical_xor), vals)
|
565
|
+
check_args("xor", vals, (2, None), (is_bool,))
|
578
566
|
return reduce(lambda a, b: a ^ b, vals)
|
579
567
|
|
580
568
|
|
@@ -600,6 +588,13 @@ def number_to_string(val: Number) -> str:
|
|
600
588
|
return f"{val}"
|
601
589
|
|
602
590
|
|
591
|
+
def palet_join(v: Any, s: str) -> str:
|
592
|
+
try:
|
593
|
+
return s.join(v)
|
594
|
+
except Exception:
|
595
|
+
raise MyError("join: expected string?")
|
596
|
+
|
597
|
+
|
603
598
|
dtype_map = {
|
604
599
|
Sym("bool"): np.bool_,
|
605
600
|
Sym("int8"): np.int8,
|
@@ -662,11 +657,11 @@ def maxcut(oarr: BoolList, _min: int) -> BoolList:
|
|
662
657
|
|
663
658
|
def margin(a: int, b: Any, c: Any = None) -> BoolList:
|
664
659
|
if c is None:
|
665
|
-
check_args("margin", [a, b], (2, 2),
|
660
|
+
check_args("margin", [a, b], (2, 2), (is_int, is_boolarr))
|
666
661
|
oarr = b
|
667
662
|
start, end = a, a
|
668
663
|
else:
|
669
|
-
check_args("margin", [a, b, c], (3, 3),
|
664
|
+
check_args("margin", [a, b, c], (3, 3), (is_int, is_int, is_boolarr))
|
670
665
|
oarr = c
|
671
666
|
start, end = a, b
|
672
667
|
|
@@ -687,28 +682,14 @@ def vector_extend(vec: list, *more_vecs: list) -> None:
|
|
687
682
|
vec.extend(more)
|
688
683
|
|
689
684
|
|
690
|
-
def
|
691
|
-
try:
|
692
|
-
return random.randrange(*args)
|
693
|
-
except ValueError:
|
694
|
-
raise MyError("randrange: got empty range")
|
695
|
-
|
696
|
-
|
697
|
-
def palet_map(proc: Proc, seq: str | list | range | NDArray) -> Any:
|
685
|
+
def palet_map(proc: Proc, seq: Any) -> Any:
|
698
686
|
if type(seq) is str:
|
699
|
-
return str(map(proc
|
687
|
+
return str(map(proc, seq))
|
688
|
+
if type(seq) is Quoted:
|
689
|
+
return Quoted(list(map(proc, seq.val)))
|
700
690
|
if isinstance(seq, (list, range)):
|
701
|
-
return list(map(proc
|
702
|
-
|
703
|
-
if isinstance(seq, np.ndarray):
|
704
|
-
if proc.arity[0] != 0:
|
705
|
-
raise MyError("map: procedure must take at least one arg")
|
706
|
-
check_args(proc.name, [0], (1, 1), None)
|
707
|
-
return proc.proc(seq)
|
708
|
-
|
709
|
-
|
710
|
-
def apply(proc: Proc, seq: str | list | range) -> Any:
|
711
|
-
return reduce(proc.proc, seq)
|
691
|
+
return list(map(proc, seq))
|
692
|
+
return proc(seq)
|
712
693
|
|
713
694
|
|
714
695
|
def ref(seq: Any, ref: int) -> Any:
|
@@ -791,41 +772,99 @@ def palet_system(cmd: str) -> bool:
|
|
791
772
|
class UserProc(Proc):
|
792
773
|
"""A user-defined procedure."""
|
793
774
|
|
794
|
-
__slots__ = ("env", "
|
775
|
+
__slots__ = ("env", "name", "parms", "body", "contracts", "arity")
|
795
776
|
|
796
777
|
def __init__(
|
797
778
|
self,
|
798
779
|
env: Env,
|
799
780
|
name: str,
|
800
|
-
parms: list,
|
781
|
+
parms: list[str],
|
782
|
+
contracts: tuple[Any, ...],
|
801
783
|
body: list,
|
802
|
-
contracts: list[Any] | None = None,
|
803
|
-
eat_last: bool = False,
|
804
784
|
):
|
805
785
|
self.env = env
|
806
|
-
self.parms = [f"{p}" for p in parms]
|
807
|
-
self.body = body
|
808
786
|
self.name = name
|
787
|
+
self.parms = parms
|
788
|
+
self.body = body
|
789
|
+
self.contracts = contracts
|
809
790
|
|
810
|
-
if
|
791
|
+
if parms and parms[-1] == "...":
|
792
|
+
parms.pop()
|
811
793
|
self.arity: tuple[int, int | None] = len(parms) - 1, None
|
812
794
|
else:
|
813
795
|
self.arity = len(parms), len(parms)
|
814
796
|
|
815
|
-
self.contracts = contracts
|
816
|
-
|
817
797
|
def __call__(self, *args: Any) -> Any:
|
798
|
+
check_args(self.name, args, self.arity, self.contracts)
|
799
|
+
|
818
800
|
if self.arity[1] is None:
|
819
|
-
|
820
|
-
|
801
|
+
args = tuple(
|
802
|
+
list(args[: len(self.parms) - 1]) + [list(args[len(self.parms) - 1 :])]
|
803
|
+
)
|
821
804
|
|
822
805
|
inner_env = Env(dict(zip(self.parms, args)), self.env)
|
823
806
|
|
824
807
|
for item in self.body[0:-1]:
|
825
808
|
my_eval(inner_env, item)
|
826
|
-
result = my_eval(inner_env, self.body[-1])
|
827
809
|
|
828
|
-
return
|
810
|
+
return my_eval(inner_env, self.body[-1])
|
811
|
+
|
812
|
+
|
813
|
+
@dataclass(slots=True)
|
814
|
+
class KeywordProc:
|
815
|
+
env: Env
|
816
|
+
name: str
|
817
|
+
parms: list[str]
|
818
|
+
kw_parms: list[str]
|
819
|
+
body: list
|
820
|
+
arity: tuple[int, None]
|
821
|
+
contracts: list[Any] | None = None
|
822
|
+
|
823
|
+
def __call__(self, *args: Any) -> Any:
|
824
|
+
env = {}
|
825
|
+
|
826
|
+
for i, parm in enumerate(self.parms):
|
827
|
+
if type(args[i]) is Keyword:
|
828
|
+
raise MyError(f"Invalid keyword `{args[i]}`")
|
829
|
+
env[parm] = args[i]
|
830
|
+
|
831
|
+
remain_args = args[len(self.parms) :]
|
832
|
+
|
833
|
+
allow_pos = True
|
834
|
+
pos_index = 0
|
835
|
+
key = ""
|
836
|
+
for arg in remain_args:
|
837
|
+
if type(arg) is Keyword:
|
838
|
+
if key:
|
839
|
+
raise MyError("Expected value for keyword but got another keyword")
|
840
|
+
key = arg.val
|
841
|
+
allow_pos = False
|
842
|
+
elif key:
|
843
|
+
env[key] = arg
|
844
|
+
key = ""
|
845
|
+
else:
|
846
|
+
if not allow_pos:
|
847
|
+
raise MyError("Positional argument not allowed here")
|
848
|
+
if pos_index >= len(self.kw_parms):
|
849
|
+
base = f"`{self.name}` has an arity mismatch. Expected"
|
850
|
+
upper = len(self.parms) + len(self.kw_parms)
|
851
|
+
raise MyError(f"{base} at most {upper}")
|
852
|
+
|
853
|
+
env[self.kw_parms[pos_index]] = arg
|
854
|
+
pos_index += 1
|
855
|
+
|
856
|
+
inner_env = Env(env, self.env)
|
857
|
+
|
858
|
+
for item in self.body[0:-1]:
|
859
|
+
my_eval(inner_env, item)
|
860
|
+
|
861
|
+
return my_eval(inner_env, self.body[-1])
|
862
|
+
|
863
|
+
def __str__(self) -> str:
|
864
|
+
return self.name
|
865
|
+
|
866
|
+
def __repr__(self) -> str:
|
867
|
+
return f"#<kw-proc:{self.name}>"
|
829
868
|
|
830
869
|
|
831
870
|
class Syntax:
|
@@ -868,62 +907,97 @@ def check_for_syntax(env: Env, node: list) -> tuple[Sym, Any]:
|
|
868
907
|
|
869
908
|
|
870
909
|
def syn_lambda(env: Env, node: list) -> UserProc:
|
871
|
-
if
|
910
|
+
if len(node) < 3:
|
911
|
+
raise MyError(f"{node[0]}: too few terms")
|
912
|
+
|
913
|
+
if type(node[1]) is not list:
|
872
914
|
raise MyError(f"{node[0]}: bad syntax")
|
873
915
|
|
874
|
-
|
916
|
+
parms: list[str] = []
|
917
|
+
for item in node[1]:
|
918
|
+
if type(item) is not Sym:
|
919
|
+
raise MyError(f"{node[0]}: must be an identifier")
|
920
|
+
|
921
|
+
parms.append(f"{item}")
|
922
|
+
|
923
|
+
return UserProc(env, "", parms, (), node[2:])
|
875
924
|
|
876
925
|
|
877
926
|
def syn_define(env: Env, node: list) -> None:
|
878
927
|
if len(node) < 3:
|
879
|
-
raise MyError(f"{node[0]}: too few
|
928
|
+
raise MyError(f"{node[0]}: too few terms")
|
929
|
+
|
930
|
+
if type(node[1]) is list:
|
931
|
+
term = node[1]
|
932
|
+
body = node[2:]
|
880
933
|
|
881
|
-
|
882
|
-
if not node[1] or type(node[1][0]) is not Sym:
|
934
|
+
if not term or type(term[0]) is not Sym:
|
883
935
|
raise MyError(f"{node[0]}: proc-binding must be an identifier")
|
884
936
|
|
885
|
-
n =
|
937
|
+
n = term[0].val
|
938
|
+
parms: list[str] = []
|
939
|
+
kparms: list[str] = []
|
940
|
+
kw_only = False
|
941
|
+
|
942
|
+
for item in term[1:]:
|
943
|
+
if kw_only:
|
944
|
+
if type(item) is Sym:
|
945
|
+
raise MyError(f"{node[0]}: {item} must be a keyword")
|
946
|
+
if type(item) is not Keyword:
|
947
|
+
raise MyError(f"{node[0]}: must be a keyword")
|
948
|
+
kparms.append(item.val)
|
949
|
+
else:
|
950
|
+
if type(item) is Keyword:
|
951
|
+
kw_only = True
|
952
|
+
kparms.append(item.val)
|
953
|
+
elif type(item) is Sym:
|
954
|
+
parms.append(item.val)
|
955
|
+
else:
|
956
|
+
raise MyError(f"{node[0]}: must be an identifier")
|
886
957
|
|
887
|
-
|
888
|
-
|
889
|
-
eat_last = True
|
890
|
-
parameters = node[1][1:-1]
|
958
|
+
if kw_only:
|
959
|
+
env[n] = KeywordProc(env, n, parms, kparms, body, (len(parms), None))
|
891
960
|
else:
|
892
|
-
|
893
|
-
|
894
|
-
body = node[2:]
|
895
|
-
env[n] = UserProc(env, n, parameters, body, eat_last=eat_last)
|
961
|
+
env[n] = UserProc(env, n, parms, (), body)
|
896
962
|
return None
|
963
|
+
|
897
964
|
elif type(node[1]) is not Sym:
|
898
965
|
raise MyError(f"{node[0]}: must be an identifier")
|
899
966
|
|
900
|
-
n = node[1].val
|
901
|
-
|
902
967
|
if len(node) > 3:
|
903
|
-
raise MyError(f"{node[0]}:
|
968
|
+
raise MyError(f"{node[0]}: multiple expressions after identifier")
|
969
|
+
|
970
|
+
n = node[1].val
|
904
971
|
|
905
972
|
if (
|
906
|
-
|
973
|
+
type(node[2]) is list
|
907
974
|
and node[2]
|
908
975
|
and type(node[2][0]) is Sym
|
909
976
|
and node[2][0].val in ("lambda", "λ")
|
910
977
|
):
|
911
|
-
|
978
|
+
terms = node[2][1]
|
912
979
|
body = node[2][2:]
|
913
|
-
|
980
|
+
|
981
|
+
parms = []
|
982
|
+
for item in terms:
|
983
|
+
if type(item) is not Sym:
|
984
|
+
raise MyError(f"{node[0]}: must be an identifier")
|
985
|
+
|
986
|
+
parms.append(f"{item}")
|
987
|
+
|
988
|
+
env[n] = UserProc(env, n, parms, (), body)
|
989
|
+
|
914
990
|
else:
|
915
991
|
for item in node[2:-1]:
|
916
992
|
my_eval(env, item)
|
917
993
|
env[n] = my_eval(env, node[-1])
|
918
994
|
|
919
|
-
return None
|
920
|
-
|
921
995
|
|
922
996
|
def syn_definec(env: Env, node: list) -> None:
|
923
997
|
if len(node) < 3:
|
924
|
-
raise MyError(f"{node[0]}:
|
998
|
+
raise MyError(f"{node[0]}: too few terms")
|
925
999
|
|
926
|
-
if
|
1000
|
+
if type(node[1]) is not list:
|
927
1001
|
raise MyError(f"{node[0]} only allows procedure declarations")
|
928
1002
|
|
929
1003
|
if not node[1] or type(node[1][0]) is not Sym:
|
@@ -931,22 +1005,24 @@ def syn_definec(env: Env, node: list) -> None:
|
|
931
1005
|
|
932
1006
|
n = node[1][0].val
|
933
1007
|
|
934
|
-
contracts: list[
|
935
|
-
|
1008
|
+
contracts: list[Any] = []
|
1009
|
+
parms: list[str] = []
|
936
1010
|
for item in node[1][1:]:
|
937
|
-
if
|
1011
|
+
if item == Sym("->"):
|
1012
|
+
break
|
1013
|
+
if type(item) is not list or len(item) != 2:
|
938
1014
|
raise MyError(f"{node[0]}: bad var-binding syntax")
|
939
1015
|
if type(item[0]) is not Sym:
|
940
1016
|
raise MyError(f"{node[0]}: binding must be identifier")
|
941
1017
|
|
942
|
-
parameters.append(item[0])
|
943
1018
|
con = my_eval(env, item[1])
|
944
1019
|
if not is_cont(con):
|
945
1020
|
raise MyError(f"{node[0]}: {print_str(con)} is not a valid contract")
|
946
1021
|
|
1022
|
+
parms.append(f"{item[0]}")
|
947
1023
|
contracts.append(con)
|
948
1024
|
|
949
|
-
env[n] = UserProc(env, n,
|
1025
|
+
env[n] = UserProc(env, n, parms, tuple(contracts), node[2:])
|
950
1026
|
return None
|
951
1027
|
|
952
1028
|
|
@@ -1015,6 +1091,23 @@ def syn_decf(env: Env, node: list) -> None:
|
|
1015
1091
|
env[name] -= 1
|
1016
1092
|
|
1017
1093
|
|
1094
|
+
def syn_strappend(env: Env, node: list) -> None:
|
1095
|
+
guard_term(node, 3, 3)
|
1096
|
+
|
1097
|
+
if type(node[1]) is not Sym:
|
1098
|
+
raise MyError(f"{node[0]}: Expected identifier, got {print_str(node[1])}")
|
1099
|
+
name = node[1].val
|
1100
|
+
|
1101
|
+
if env[name] is None:
|
1102
|
+
raise MyError(f"{node[0]}: `{name}` is not defined")
|
1103
|
+
if not is_str(env[name]):
|
1104
|
+
raise MyError(f"{node[0]}: `{name}` is not a string?")
|
1105
|
+
|
1106
|
+
if not is_str(num := my_eval(env, node[2])):
|
1107
|
+
raise MyError(f"{node[0]}: Expected string? got: {print_str(num)}")
|
1108
|
+
env[name] += num
|
1109
|
+
|
1110
|
+
|
1018
1111
|
def syn_for(env: Env, node: list) -> None:
|
1019
1112
|
var, my_iter = check_for_syntax(env, node)
|
1020
1113
|
|
@@ -1030,8 +1123,12 @@ def syn_for(env: Env, node: list) -> None:
|
|
1030
1123
|
my_eval(env, c)
|
1031
1124
|
|
1032
1125
|
|
1033
|
-
def syn_quote(env: Env, node: list) ->
|
1126
|
+
def syn_quote(env: Env, node: list) -> Any:
|
1034
1127
|
guard_term(node, 2, 2)
|
1128
|
+
if type(node[1]) is Keyword:
|
1129
|
+
return QuotedKeyword(node[1])
|
1130
|
+
if type(node[1]) is list:
|
1131
|
+
return Quoted(node[1])
|
1035
1132
|
return node[1]
|
1036
1133
|
|
1037
1134
|
|
@@ -1082,8 +1179,8 @@ def syn_and(env: Env, node: list) -> Any:
|
|
1082
1179
|
|
1083
1180
|
if is_boolarr(first):
|
1084
1181
|
vals = [first] + [my_eval(env, n) for n in node[2:]]
|
1085
|
-
check_args(node[0], vals, (2, None),
|
1086
|
-
return reduce(lambda a, b: boolop(a, b,
|
1182
|
+
check_args(node[0], vals, (2, None), (is_boolarr,))
|
1183
|
+
return reduce(lambda a, b: boolop(a, b, logical_and), vals)
|
1087
1184
|
|
1088
1185
|
raise MyError(f"{node[0]} expects (or/c bool? bool-array?)")
|
1089
1186
|
|
@@ -1106,8 +1203,8 @@ def syn_or(env: Env, node: list) -> Any:
|
|
1106
1203
|
|
1107
1204
|
if is_boolarr(first):
|
1108
1205
|
vals = [first] + [my_eval(env, n) for n in node[2:]]
|
1109
|
-
check_args(node[0], vals, (2, None),
|
1110
|
-
return reduce(lambda a, b: boolop(a, b,
|
1206
|
+
check_args(node[0], vals, (2, None), (is_boolarr,))
|
1207
|
+
return reduce(lambda a, b: boolop(a, b, logical_or), vals)
|
1111
1208
|
|
1112
1209
|
raise MyError(f"{node[0]} expects (or/c bool? bool-array?)")
|
1113
1210
|
|
@@ -1224,15 +1321,33 @@ def syn_let_star(env: Env, node: list) -> Any:
|
|
1224
1321
|
return my_eval(inner_env, node[-1])
|
1225
1322
|
|
1226
1323
|
|
1324
|
+
def syn_class(env: Env, node: list) -> Any:
|
1325
|
+
...
|
1326
|
+
|
1327
|
+
|
1227
1328
|
def attr(env: Env, node: list) -> Any:
|
1228
1329
|
guard_term(node, 3, 3)
|
1229
1330
|
|
1230
|
-
if
|
1331
|
+
if type(node[2]) is not Sym:
|
1231
1332
|
raise MyError("@r: attribute must be an identifier")
|
1232
1333
|
|
1233
1334
|
return my_eval(env, [node[2], node[1]])
|
1234
1335
|
|
1235
1336
|
|
1337
|
+
def edit_none() -> np.ndarray:
|
1338
|
+
if "@levels" not in env:
|
1339
|
+
raise MyError("Can't use `none` if there's no input media")
|
1340
|
+
|
1341
|
+
return env["@levels"].none()
|
1342
|
+
|
1343
|
+
|
1344
|
+
def edit_all() -> np.ndarray:
|
1345
|
+
if "@levels" not in env:
|
1346
|
+
raise MyError("Can't use `all/e` if there's no input media")
|
1347
|
+
|
1348
|
+
return env["@levels"].all()
|
1349
|
+
|
1350
|
+
|
1236
1351
|
def my_eval(env: Env, node: object) -> Any:
|
1237
1352
|
if type(node) is Sym:
|
1238
1353
|
val = env.get(node.val)
|
@@ -1251,10 +1366,9 @@ def my_eval(env: Env, node: object) -> Any:
|
|
1251
1366
|
raise MyError("Can't use edit methods if there's no input files")
|
1252
1367
|
return edit_method(node.val, env["@filesetup"], env)
|
1253
1368
|
|
1254
|
-
if
|
1369
|
+
if type(node) is list:
|
1255
1370
|
if not node:
|
1256
1371
|
raise MyError("Illegal () expression")
|
1257
|
-
|
1258
1372
|
if node[0] is list: # Handle vector literal
|
1259
1373
|
return [my_eval(env, item) for item in node[1]]
|
1260
1374
|
|
@@ -1280,13 +1394,7 @@ def my_eval(env: Env, node: object) -> Any:
|
|
1280
1394
|
if type(oper) is Syntax:
|
1281
1395
|
return oper(env, node)
|
1282
1396
|
|
1283
|
-
|
1284
|
-
if type(oper) is Contract:
|
1285
|
-
check_args(oper.name, values, (1, 1), None)
|
1286
|
-
else:
|
1287
|
-
check_args(oper.name, values, oper.arity, oper.contracts)
|
1288
|
-
|
1289
|
-
return oper(*values)
|
1397
|
+
return oper(*(my_eval(env, c) for c in node[1:]))
|
1290
1398
|
|
1291
1399
|
return node
|
1292
1400
|
|
@@ -1298,6 +1406,9 @@ env.update({
|
|
1298
1406
|
"true": True,
|
1299
1407
|
"false": False,
|
1300
1408
|
"all": Sym("all"),
|
1409
|
+
# edit procedures
|
1410
|
+
"none": Proc("none", edit_none, (0, 0)),
|
1411
|
+
"all/e": Proc("all/e", edit_all, (0, 0)),
|
1301
1412
|
# syntax
|
1302
1413
|
"lambda": Syntax(syn_lambda),
|
1303
1414
|
"λ": Syntax(syn_lambda),
|
@@ -1306,6 +1417,7 @@ env.update({
|
|
1306
1417
|
"set!": Syntax(syn_set),
|
1307
1418
|
"incf": Syntax(syn_incf),
|
1308
1419
|
"decf": Syntax(syn_decf),
|
1420
|
+
"&=": Syntax(syn_strappend),
|
1309
1421
|
"quote": Syntax(syn_quote),
|
1310
1422
|
"if": Syntax(syn_if),
|
1311
1423
|
"when": Syntax(syn_when),
|
@@ -1313,6 +1425,7 @@ env.update({
|
|
1313
1425
|
"case": Syntax(syn_case),
|
1314
1426
|
"let": Syntax(syn_let),
|
1315
1427
|
"let*": Syntax(syn_let_star),
|
1428
|
+
#"class": Syntax(syn_class),
|
1316
1429
|
"@r": Syntax(attr),
|
1317
1430
|
# loops
|
1318
1431
|
"for": Syntax(syn_for),
|
@@ -1320,10 +1433,11 @@ env.update({
|
|
1320
1433
|
"number?": is_num,
|
1321
1434
|
"real?": is_real,
|
1322
1435
|
"int?": is_int,
|
1323
|
-
"uint?": is_uint,
|
1324
|
-
"nat?": is_nat,
|
1325
1436
|
"float?": is_float,
|
1326
1437
|
"frac?": is_frac,
|
1438
|
+
"complex?": Contract("complex?", lambda v: type(v) is complex),
|
1439
|
+
"nat?": is_nat,
|
1440
|
+
"nat1?": is_nat1,
|
1327
1441
|
"threshold?": is_threshold,
|
1328
1442
|
"any": any_p,
|
1329
1443
|
"bool?": is_bool,
|
@@ -1331,7 +1445,7 @@ env.update({
|
|
1331
1445
|
"symbol?": (is_symbol := Contract("symbol?", lambda v: type(v) is Sym)),
|
1332
1446
|
"string?": is_str,
|
1333
1447
|
"char?": (is_char := Contract("char?", lambda v: type(v) is Char)),
|
1334
|
-
"vector?": (is_vector := Contract("vector?", lambda v:
|
1448
|
+
"vector?": (is_vector := Contract("vector?", lambda v: type(v) is list)),
|
1335
1449
|
"array?": (is_array := Contract("array?", lambda v: isinstance(v, np.ndarray))),
|
1336
1450
|
"bool-array?": is_boolarr,
|
1337
1451
|
"range?": (is_range := Contract("range?", lambda v: type(v) is range)),
|
@@ -1343,157 +1457,162 @@ env.update({
|
|
1343
1457
|
"begin": Proc("begin", lambda *x: x[-1] if x else None, (0, None)),
|
1344
1458
|
"void": Proc("void", lambda *v: None, (0, 0)),
|
1345
1459
|
# control / b-arrays
|
1346
|
-
"not": Proc(
|
1347
|
-
"not",
|
1348
|
-
lambda v: not v if type(v) is bool else np.logical_not(v),
|
1349
|
-
(1, 1),
|
1350
|
-
[bool_or_barr],
|
1351
|
-
),
|
1460
|
+
"not": Proc("not", lambda v: not v if type(v) is bool else logical_not(v), (1, 1), bool_or_barr),
|
1352
1461
|
"and": Syntax(syn_and),
|
1353
1462
|
"or": Syntax(syn_or),
|
1354
|
-
"xor": Proc("xor", _xor, (2, None),
|
1463
|
+
"xor": Proc("xor", _xor, (2, None), bool_or_barr),
|
1355
1464
|
# booleans
|
1356
|
-
">": Proc(">", lambda a, b: a > b, (2, 2),
|
1357
|
-
">=": Proc(">=", lambda a, b: a >= b, (2, 2),
|
1358
|
-
"<": Proc("<", lambda a, b: a < b, (2, 2),
|
1359
|
-
"<=": Proc("<=", lambda a, b: a <= b, (2, 2),
|
1360
|
-
"=": Proc("=", equal_num, (1, None),
|
1465
|
+
">": Proc(">", lambda a, b: a > b, (2, 2), is_real),
|
1466
|
+
">=": Proc(">=", lambda a, b: a >= b, (2, 2), is_real),
|
1467
|
+
"<": Proc("<", lambda a, b: a < b, (2, 2), is_real),
|
1468
|
+
"<=": Proc("<=", lambda a, b: a <= b, (2, 2), is_real),
|
1469
|
+
"=": Proc("=", equal_num, (1, None), is_num),
|
1361
1470
|
"eq?": Proc("eq?", lambda a, b: a is b, (2, 2)),
|
1362
1471
|
"equal?": Proc("equal?", is_equal, (2, 2)),
|
1363
|
-
"zero?": UserProc(env, "zero?", ["z"], [[Sym("="), Sym("z"), 0]]
|
1364
|
-
"positive?": UserProc(
|
1365
|
-
|
1366
|
-
),
|
1367
|
-
"negative?": UserProc(
|
1368
|
-
env, "negative?", ["x"], [[Sym("<"), Sym("x"), 0]], [is_real]
|
1369
|
-
),
|
1472
|
+
"zero?": UserProc(env, "zero?", ["z"], (is_num,), [[Sym("="), Sym("z"), 0]]),
|
1473
|
+
"positive?": UserProc(env, "positive?", ["x"], (is_real,), [[Sym(">"), Sym("x"), 0]]),
|
1474
|
+
"negative?": UserProc(env, "negative?", ["x"], (is_real,), [[Sym("<"), Sym("x"), 0]]),
|
1370
1475
|
"even?": UserProc(
|
1371
|
-
env, "even?", ["n"], [[Sym("zero?"), [Sym("mod"), Sym("n"), 2]]]
|
1476
|
+
env, "even?", ["n"], (is_int,), [[Sym("zero?"), [Sym("mod"), Sym("n"), 2]]]
|
1372
1477
|
),
|
1373
1478
|
"odd?": UserProc(
|
1374
|
-
env, "odd?", ["n"], [[Sym("not"), [Sym("even?"), Sym("n")]]]
|
1479
|
+
env, "odd?", ["n"], (is_int,), [[Sym("not"), [Sym("even?"), Sym("n")]]]
|
1375
1480
|
),
|
1376
|
-
">=/c": Proc(">=/c", gte_c, (1, 1),
|
1377
|
-
">/c": Proc(">/c", gt_c, (1, 1),
|
1378
|
-
"<=/c": Proc("<=/c", lte_c, (1, 1),
|
1379
|
-
"</c": Proc("</c", lt_c, (1, 1),
|
1380
|
-
"between/c": Proc("between/c", between_c, (2, 2),
|
1481
|
+
">=/c": Proc(">=/c", gte_c, (1, 1), is_real),
|
1482
|
+
">/c": Proc(">/c", gt_c, (1, 1), is_real),
|
1483
|
+
"<=/c": Proc("<=/c", lte_c, (1, 1), is_real),
|
1484
|
+
"</c": Proc("</c", lt_c, (1, 1), is_real),
|
1485
|
+
"between/c": Proc("between/c", between_c, (2, 2), is_real),
|
1381
1486
|
# numbers
|
1382
|
-
"+": Proc("+", lambda *v: sum(v), (0, None),
|
1383
|
-
"-": Proc("-", minus, (1, None),
|
1384
|
-
"*": Proc("*", mul, (0, None),
|
1385
|
-
"/": Proc("/", num_div, (1, None),
|
1386
|
-
"div": Proc("div", int_div, (2, None),
|
1387
|
-
"add1": Proc("add1", lambda z: z + 1, (1, 1),
|
1388
|
-
"sub1": Proc("sub1", lambda z: z - 1, (1, 1),
|
1389
|
-
"sqrt": Proc("sqrt", _sqrt, (1, 1),
|
1390
|
-
"real-part": Proc("real-part", lambda v: v.real, (1, 1),
|
1391
|
-
"imag-part": Proc("imag-part", lambda v: v.imag, (1, 1),
|
1487
|
+
"+": Proc("+", lambda *v: sum(v), (0, None), is_num),
|
1488
|
+
"-": Proc("-", minus, (1, None), is_num),
|
1489
|
+
"*": Proc("*", mul, (0, None), is_num),
|
1490
|
+
"/": Proc("/", num_div, (1, None), is_num),
|
1491
|
+
"div": Proc("div", int_div, (2, None), is_int),
|
1492
|
+
"add1": Proc("add1", lambda z: z + 1, (1, 1), is_num),
|
1493
|
+
"sub1": Proc("sub1", lambda z: z - 1, (1, 1), is_num),
|
1494
|
+
"sqrt": Proc("sqrt", _sqrt, (1, 1), is_num),
|
1495
|
+
"real-part": Proc("real-part", lambda v: v.real, (1, 1), is_num),
|
1496
|
+
"imag-part": Proc("imag-part", lambda v: v.imag, (1, 1), is_num),
|
1392
1497
|
# reals
|
1393
|
-
"pow": Proc("pow", pow, (2, 2),
|
1394
|
-
"exp": Proc("exp", math.exp, (1, 1),
|
1395
|
-
"abs": Proc("abs", abs, (1, 1),
|
1396
|
-
"ceil": Proc("ceil", math.ceil, (1, 1),
|
1397
|
-
"floor": Proc("floor", math.floor, (1, 1),
|
1398
|
-
"round": Proc("round", round, (1, 1),
|
1399
|
-
"max": Proc("max", lambda *v: max(v), (1, None),
|
1400
|
-
"min": Proc("min", lambda *v: min(v), (1, None),
|
1401
|
-
"sin": Proc("sin", math.sin, (1, 1),
|
1402
|
-
"cos": Proc("cos", math.cos, (1, 1),
|
1403
|
-
"log": Proc("log", math.log, (1, 2),
|
1404
|
-
"tan": Proc("tan", math.tan, (1, 1),
|
1405
|
-
"mod": Proc("mod", lambda a, b: a % b, (2, 2),
|
1406
|
-
"modulo": Proc("modulo", lambda a, b: a % b, (2, 2),
|
1498
|
+
"pow": Proc("pow", pow, (2, 2), is_real),
|
1499
|
+
"exp": Proc("exp", math.exp, (1, 1), is_real),
|
1500
|
+
"abs": Proc("abs", abs, (1, 1), is_real),
|
1501
|
+
"ceil": Proc("ceil", math.ceil, (1, 1), is_real),
|
1502
|
+
"floor": Proc("floor", math.floor, (1, 1), is_real),
|
1503
|
+
"round": Proc("round", round, (1, 1), is_real),
|
1504
|
+
"max": Proc("max", lambda *v: max(v), (1, None), is_real),
|
1505
|
+
"min": Proc("min", lambda *v: min(v), (1, None), is_real),
|
1506
|
+
"sin": Proc("sin", math.sin, (1, 1), is_real),
|
1507
|
+
"cos": Proc("cos", math.cos, (1, 1), is_real),
|
1508
|
+
"log": Proc("log", math.log, (1, 2), is_real),
|
1509
|
+
"tan": Proc("tan", math.tan, (1, 1), is_real),
|
1510
|
+
"mod": Proc("mod", lambda a, b: a % b, (2, 2), is_int),
|
1511
|
+
"modulo": Proc("modulo", lambda a, b: a % b, (2, 2), is_int),
|
1407
1512
|
# symbols
|
1408
|
-
"symbol->string": Proc("symbol->string", str, (1, 1),
|
1409
|
-
"string->symbol": Proc("string->symbol", Sym, (1, 1),
|
1513
|
+
"symbol->string": Proc("symbol->string", str, (1, 1), is_symbol),
|
1514
|
+
"string->symbol": Proc("string->symbol", Sym, (1, 1), is_str),
|
1410
1515
|
# strings
|
1411
|
-
"string": Proc("string", string_append, (0, None),
|
1412
|
-
"
|
1413
|
-
"split": Proc("split", str.split, (1, 2),
|
1414
|
-
"strip": Proc("strip", str.strip, (1, 1),
|
1415
|
-
"str-repeat": Proc("str-repeat", lambda s, a: s * a, (2, 2),
|
1416
|
-
"startswith": Proc("startswith", str.startswith, (2, 2),
|
1417
|
-
"endswith": Proc("endswith", str.endswith, (2, 2),
|
1418
|
-
"replace": Proc("replace", str.replace, (3, 4),
|
1419
|
-
"title": Proc("title", str.title, (1, 1),
|
1420
|
-
"lower": Proc("lower", str.lower, (1, 1),
|
1421
|
-
"upper": Proc("upper", str.upper, (1, 1),
|
1516
|
+
"string": Proc("string", string_append, (0, None), is_char),
|
1517
|
+
"&": Proc("&", string_append, (0, None), is_str),
|
1518
|
+
"split": Proc("split", str.split, (1, 2), is_str, is_str),
|
1519
|
+
"strip": Proc("strip", str.strip, (1, 1), is_str),
|
1520
|
+
"str-repeat": Proc("str-repeat", lambda s, a: s * a, (2, 2), is_str, is_int),
|
1521
|
+
"startswith": Proc("startswith", str.startswith, (2, 2), is_str),
|
1522
|
+
"endswith": Proc("endswith", str.endswith, (2, 2), is_str),
|
1523
|
+
"replace": Proc("replace", str.replace, (3, 4), is_str, is_str, is_str, is_int),
|
1524
|
+
"title": Proc("title", str.title, (1, 1), is_str),
|
1525
|
+
"lower": Proc("lower", str.lower, (1, 1), is_str),
|
1526
|
+
"upper": Proc("upper", str.upper, (1, 1), is_str),
|
1527
|
+
"join": Proc("join", palet_join, (2, 2), is_vector, is_str),
|
1422
1528
|
# format
|
1423
|
-
"char->int": Proc("char->int", lambda c: ord(c.val), (1, 1),
|
1424
|
-
"int->char": Proc("int->char", Char, (1, 1),
|
1529
|
+
"char->int": Proc("char->int", lambda c: ord(c.val), (1, 1), is_char),
|
1530
|
+
"int->char": Proc("int->char", Char, (1, 1), is_int),
|
1425
1531
|
"~a": Proc("~a", lambda *v: "".join([display_str(a) for a in v]), (0, None)),
|
1426
1532
|
"~s": Proc("~s", lambda *v: " ".join([display_str(a) for a in v]), (0, None)),
|
1427
1533
|
"~v": Proc("~v", lambda *v: " ".join([print_str(a) for a in v]), (0, None)),
|
1534
|
+
# keyword
|
1535
|
+
"keyword?": is_keyw,
|
1536
|
+
"keyword->string": Proc("keyword->string", lambda v: v.val.val, (1, 1), is_keyw),
|
1537
|
+
"string->keyword": Proc("string->keyword", QuotedKeyword, (1, 1), is_str),
|
1428
1538
|
# vectors
|
1429
1539
|
"vector": Proc("vector", lambda *a: list(a), (0, None)),
|
1430
1540
|
"make-vector": Proc(
|
1431
|
-
"make-vector", lambda size, a=0: [a] * size, (1, 2),
|
1541
|
+
"make-vector", lambda size, a=0: [a] * size, (1, 2), is_nat, any_p
|
1432
1542
|
),
|
1433
|
-
"
|
1434
|
-
"
|
1435
|
-
"
|
1436
|
-
"
|
1437
|
-
"
|
1438
|
-
"sort": Proc("sort", sorted, (1, 1),
|
1439
|
-
"sort!": Proc("sort!", list.sort, (1, 1),
|
1543
|
+
"add!": Proc("add!", list.append, (2, 2), is_vector, any_p),
|
1544
|
+
"pop!": Proc("pop!", list.pop, (1, 1), is_vector),
|
1545
|
+
"vec-set!": Proc("vec-set!", vector_set, (3, 3), is_vector, is_int, any_p),
|
1546
|
+
"vec-append": Proc("vec-append", vector_append, (0, None), is_vector),
|
1547
|
+
"vec-extend!": Proc("vec-extend!", vector_extend, (2, None), is_vector),
|
1548
|
+
"sort": Proc("sort", sorted, (1, 1), is_vector),
|
1549
|
+
"sort!": Proc("sort!", list.sort, (1, 1), is_vector),
|
1440
1550
|
# arrays
|
1441
|
-
"array": Proc("array", array_proc, (2, None),
|
1442
|
-
"make-array": Proc("make-array", make_array, (2, 3),
|
1551
|
+
"array": Proc("array", array_proc, (2, None), is_symbol, is_real),
|
1552
|
+
"make-array": Proc("make-array", make_array, (2, 3), is_symbol, is_nat, is_real),
|
1443
1553
|
"array-splice!": Proc(
|
1444
|
-
"array-splice!", splice, (2, 4),
|
1554
|
+
"array-splice!", splice, (2, 4), is_array, is_real, is_int, is_int
|
1445
1555
|
),
|
1446
|
-
"array-copy": Proc("array-copy", np.copy, (1, 1),
|
1447
|
-
"count-nonzero": Proc("count-nonzero", np.count_nonzero, (1, 1),
|
1556
|
+
"array-copy": Proc("array-copy", np.copy, (1, 1), is_array),
|
1557
|
+
"count-nonzero": Proc("count-nonzero", np.count_nonzero, (1, 1), is_array),
|
1448
1558
|
# bool arrays
|
1449
1559
|
"bool-array": Proc(
|
1450
|
-
"bool-array", lambda *a: np.array(a, dtype=np.bool_), (1, None),
|
1560
|
+
"bool-array", lambda *a: np.array(a, dtype=np.bool_), (1, None), is_nat
|
1451
1561
|
),
|
1452
|
-
"margin": Proc("margin", margin, (2, 3)
|
1453
|
-
"mincut": Proc("mincut", mincut, (2, 2),
|
1454
|
-
"minclip": Proc("minclip", minclip, (2, 2),
|
1455
|
-
"maxcut": Proc("maxcut", maxcut, (2, 2),
|
1456
|
-
"maxclip": Proc("maxclip", maxclip, (2, 2),
|
1562
|
+
"margin": Proc("margin", margin, (2, 3)),
|
1563
|
+
"mincut": Proc("mincut", mincut, (2, 2), is_boolarr, is_nat),
|
1564
|
+
"minclip": Proc("minclip", minclip, (2, 2), is_boolarr, is_nat),
|
1565
|
+
"maxcut": Proc("maxcut", maxcut, (2, 2), is_boolarr, is_nat),
|
1566
|
+
"maxclip": Proc("maxclip", maxclip, (2, 2), is_boolarr, is_nat),
|
1457
1567
|
# ranges
|
1458
|
-
"range": Proc("range", range, (1, 3),
|
1568
|
+
"range": Proc("range", range, (1, 3), is_int, is_int, int_not_zero),
|
1459
1569
|
# generic iterables
|
1460
|
-
"len": Proc("len", len, (1, 1),
|
1461
|
-
"reverse": Proc("reverse", lambda v: v[::-1], (1, 1),
|
1462
|
-
"ref": Proc("ref", ref, (2, 2),
|
1463
|
-
"slice": Proc("slice", p_slice, (2, 4),
|
1570
|
+
"len": Proc("len", len, (1, 1), is_iterable),
|
1571
|
+
"reverse": Proc("reverse", lambda v: v[::-1], (1, 1), is_sequence),
|
1572
|
+
"ref": Proc("ref", ref, (2, 2), is_sequence, is_int),
|
1573
|
+
"slice": Proc("slice", p_slice, (2, 4), is_sequence, is_int),
|
1464
1574
|
# procedures
|
1465
|
-
"map": Proc("map", palet_map, (2, 2),
|
1466
|
-
"apply": Proc("apply",
|
1467
|
-
"and/c": Proc("and/c", andc, (1, None),
|
1468
|
-
"or/c": Proc("or/c", orc, (1, None),
|
1469
|
-
"not/c": Proc("not/c", notc, (1, 1),
|
1575
|
+
"map": Proc("map", palet_map, (2, 2), is_proc, is_sequence),
|
1576
|
+
"apply": Proc("apply", lambda p, s: p(*s), (2, 2), is_proc, is_sequence),
|
1577
|
+
"and/c": Proc("and/c", andc, (1, None), is_cont),
|
1578
|
+
"or/c": Proc("or/c", orc, (1, None), is_cont),
|
1579
|
+
"not/c": Proc("not/c", notc, (1, 1), is_cont),
|
1470
1580
|
# hashs
|
1471
1581
|
"hash": Proc("hash", palet_hash, (0, None)),
|
1472
|
-
"hash-ref": Proc("hash", hash_ref, (2, 2),
|
1473
|
-
"hash-set!": Proc("hash-set!", hash_set, (3, 3),
|
1474
|
-
"has-key?": Proc("has-key?", lambda h, k: k in h, (2, 2),
|
1475
|
-
"hash-remove!": Proc("hash-remove!", hash_remove, (2, 2),
|
1476
|
-
"hash-update!": UserProc(env, "hash-update!", ["h", "v", "up"],
|
1582
|
+
"hash-ref": Proc("hash", hash_ref, (2, 2), is_hash, any_p),
|
1583
|
+
"hash-set!": Proc("hash-set!", hash_set, (3, 3), is_hash, any_p, any_p),
|
1584
|
+
"has-key?": Proc("has-key?", lambda h, k: k in h, (2, 2), is_hash, any_p),
|
1585
|
+
"hash-remove!": Proc("hash-remove!", hash_remove, (2, 2), is_hash, any_p),
|
1586
|
+
"hash-update!": UserProc(env, "hash-update!", ["h", "v", "up"], (is_hash, any_p),
|
1477
1587
|
[[Sym("hash-set!"), Sym("h"), Sym("v"), [Sym("up"), [Sym("hash-ref"), Sym("h"), Sym("v")]]]],
|
1478
|
-
[is_hash, any_p, any_p],
|
1479
1588
|
),
|
1589
|
+
# i/o
|
1590
|
+
"open-output-file": Proc("open-output-file", initOutPort, (1, 1), is_str),
|
1591
|
+
"output-port?": (op := Contract("output-port?", lambda v: type(v) is OutputPort)),
|
1592
|
+
"close-port": Proc("close-port", OutputPort.close, (1, 1), op),
|
1593
|
+
"closed?": Proc("closed?", lambda o: o.closed, (1, 1), op),
|
1594
|
+
# printing
|
1595
|
+
"display": Proc("display",
|
1596
|
+
lambda v, f=None: print(display_str(v), end="", file=f), (1, 2), any_p, op),
|
1597
|
+
"displayln": Proc("displayln",
|
1598
|
+
lambda v, f=None: print(display_str(v), file=f), (1, 2), any_p, op),
|
1599
|
+
"print": Proc("print",
|
1600
|
+
lambda v, f=None: print(print_str(v), end="", file=f), (1, 2), any_p, op),
|
1601
|
+
"println": Proc("println",
|
1602
|
+
lambda v, f=None: print(print_str(v), file=f), (1, 2), any_p, op),
|
1480
1603
|
# actions
|
1481
|
-
"assert": Proc("assert", palet_assert, (1, 2),
|
1482
|
-
"
|
1483
|
-
"
|
1484
|
-
"
|
1485
|
-
"sleep": Proc("sleep", sleep, (1, 1), [is_int_or_float]),
|
1486
|
-
"print": Proc("print", lambda v: print(print_str(v), end=""), (1, 1)),
|
1487
|
-
"println": Proc("println", lambda v: print(print_str(v)), (1, 1)),
|
1488
|
-
"system": Proc("system", palet_system, (1, 1)),
|
1604
|
+
"assert": Proc("assert", palet_assert, (1, 2), any_p, orc(is_str, False)),
|
1605
|
+
"error": Proc("error", raise_, (1, 1), is_str),
|
1606
|
+
"sleep": Proc("sleep", sleep, (1, 1), is_int_or_float),
|
1607
|
+
"system": Proc("system", palet_system, (1, 1), is_str),
|
1489
1608
|
# conversions
|
1490
|
-
"number->string": Proc("number->string", number_to_string, (1, 1),
|
1609
|
+
"number->string": Proc("number->string", number_to_string, (1, 1), is_num),
|
1491
1610
|
"string->vector": Proc(
|
1492
|
-
"string->vector", lambda s: [Char(c) for c in s], (1, 1),
|
1611
|
+
"string->vector", lambda s: [Char(c) for c in s], (1, 1), is_str
|
1493
1612
|
),
|
1494
|
-
"range->vector": Proc("range->vector", list, (1, 1),
|
1613
|
+
"range->vector": Proc("range->vector", list, (1, 1), is_range),
|
1495
1614
|
# reflexion
|
1496
|
-
"var-exists?": Proc("var-exists?", lambda sym: sym.val in env, (1, 1),
|
1615
|
+
"var-exists?": Proc("var-exists?", lambda sym: sym.val in env, (1, 1), is_symbol),
|
1497
1616
|
"rename": Syntax(syn_rename),
|
1498
1617
|
"delete": Syntax(syn_delete),
|
1499
1618
|
})
|
@@ -1504,4 +1623,7 @@ def interpret(env: Env, parser: Parser) -> list:
|
|
1504
1623
|
result = []
|
1505
1624
|
while parser.current_token.type != EOF:
|
1506
1625
|
result.append(my_eval(env, parser.expr()))
|
1626
|
+
|
1627
|
+
if type(result[-1]) is Keyword:
|
1628
|
+
raise MyError(f"Keyword misused in expression. `{result[-1]}`")
|
1507
1629
|
return result
|