auto-editor 23.38.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/lang/palet.py CHANGED
@@ -27,7 +27,7 @@ from auto_editor.utils.func import boolop, mut_margin
27
27
 
28
28
  if TYPE_CHECKING:
29
29
  from collections.abc import Callable
30
- from typing import Any, NoReturn
30
+ from typing import Any, Literal, NoReturn
31
31
 
32
32
  from numpy.typing import NDArray
33
33
 
@@ -49,7 +49,7 @@ class ClosingError(MyError):
49
49
  LPAREN, RPAREN, LBRAC, RBRAC, LCUR, RCUR, EOF = "(", ")", "[", "]", "{", "}", "EOF"
50
50
  VAL, QUOTE, SEC, DB, DOT, VLIT = "VAL", "QUOTE", "SEC", "DB", "DOT", "VLIT"
51
51
  SEC_UNITS = ("s", "sec", "secs", "second", "seconds")
52
- METHODS = ("audio:", "motion:", "pixeldiff:", "subtitle:", "none:", "all/e:")
52
+ METHODS = ("audio:", "motion:", "pixeldiff:", "subtitle:")
53
53
  brac_pairs = {LPAREN: RPAREN, LBRAC: RBRAC, LCUR: RCUR}
54
54
 
55
55
  str_escape = {
@@ -458,43 +458,15 @@ class Parser:
458
458
  ###############################################################################
459
459
 
460
460
 
461
- def check_args(
462
- o: str,
463
- values: list | tuple,
464
- arity: tuple[int, int | None],
465
- cont: list[Contract] | None,
466
- ) -> None:
467
- lower, upper = arity
468
- amount = len(values)
469
-
470
- assert not (upper is not None and lower > upper)
471
- base = f"`{o}` has an arity mismatch. Expected "
472
-
473
- if lower == upper and len(values) != lower:
474
- raise MyError(f"{base}{lower}, got {amount}")
475
- if upper is None and amount < lower:
476
- raise MyError(f"{base}at least {lower}, got {amount}")
477
- if upper is not None and (amount > upper or amount < lower):
478
- raise MyError(f"{base}between {lower} and {upper}, got {amount}")
479
-
480
- if cont is None:
481
- return
482
-
483
- for i, val in enumerate(values):
484
- check = cont[-1] if i >= len(cont) else cont[i]
485
- if not check_contract(check, val):
486
- exp = f"{check}" if callable(check) else print_str(check)
487
- raise MyError(f"`{o}` expected a {exp}, got {print_str(val)}")
488
-
489
-
490
461
  is_cont = Contract("contract?", is_contract)
491
462
  is_iterable = Contract(
492
463
  "iterable?",
493
- lambda v: type(v) in (str, range) or isinstance(v, (list, dict, np.ndarray)),
464
+ lambda v: type(v) in (str, range, Quoted)
465
+ or isinstance(v, (list, dict, np.ndarray)),
494
466
  )
495
467
  is_sequence = Contract(
496
468
  "sequence?",
497
- 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)),
498
470
  )
499
471
  is_boolarr = Contract(
500
472
  "bool-array?",
@@ -504,9 +476,32 @@ bool_or_barr = Contract(
504
476
  "(or/c bool? bool-array?)",
505
477
  lambda v: type(v) is bool or is_boolarr(v),
506
478
  )
507
- is_keyw = Contract(
508
- "keyword?", lambda v: type(v) is list and len(v) == 2 and type(v[1]) is Keyword
509
- )
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)
510
505
 
511
506
 
512
507
  def raise_(msg: str) -> None:
@@ -565,9 +560,9 @@ def _sqrt(v: Number) -> Number:
565
560
 
566
561
  def _xor(*vals: Any) -> bool | BoolList:
567
562
  if is_boolarr(vals[0]):
568
- check_args("xor", vals, (2, None), [is_boolarr])
563
+ check_args("xor", vals, (2, None), (is_boolarr,))
569
564
  return reduce(lambda a, b: boolop(a, b, logical_xor), vals)
570
- check_args("xor", vals, (2, None), [is_bool])
565
+ check_args("xor", vals, (2, None), (is_bool,))
571
566
  return reduce(lambda a, b: a ^ b, vals)
572
567
 
573
568
 
@@ -593,6 +588,13 @@ def number_to_string(val: Number) -> str:
593
588
  return f"{val}"
594
589
 
595
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
+
596
598
  dtype_map = {
597
599
  Sym("bool"): np.bool_,
598
600
  Sym("int8"): np.int8,
@@ -655,11 +657,11 @@ def maxcut(oarr: BoolList, _min: int) -> BoolList:
655
657
 
656
658
  def margin(a: int, b: Any, c: Any = None) -> BoolList:
657
659
  if c is None:
658
- check_args("margin", [a, b], (2, 2), [is_int, is_boolarr])
660
+ check_args("margin", [a, b], (2, 2), (is_int, is_boolarr))
659
661
  oarr = b
660
662
  start, end = a, a
661
663
  else:
662
- check_args("margin", [a, b, c], (3, 3), [is_int, is_int, is_boolarr])
664
+ check_args("margin", [a, b, c], (3, 3), (is_int, is_int, is_boolarr))
663
665
  oarr = c
664
666
  start, end = a, b
665
667
 
@@ -680,21 +682,14 @@ def vector_extend(vec: list, *more_vecs: list) -> None:
680
682
  vec.extend(more)
681
683
 
682
684
 
683
- def palet_map(proc: Proc, seq: str | list | range | NDArray) -> Any:
685
+ def palet_map(proc: Proc, seq: Any) -> Any:
684
686
  if type(seq) is str:
685
- return str(map(proc.proc, seq))
687
+ return str(map(proc, seq))
688
+ if type(seq) is Quoted:
689
+ return Quoted(list(map(proc, seq.val)))
686
690
  if isinstance(seq, (list, range)):
687
- return list(map(proc.proc, seq))
688
-
689
- if isinstance(seq, np.ndarray):
690
- if proc.arity[0] != 0:
691
- raise MyError("map: procedure must take at least one arg")
692
- check_args(proc.name, [0], (1, 1), None)
693
- return proc.proc(seq)
694
-
695
-
696
- def apply(proc: Proc, seq: str | list | range) -> Any:
697
- return reduce(proc.proc, seq)
691
+ return list(map(proc, seq))
692
+ return proc(seq)
698
693
 
699
694
 
700
695
  def ref(seq: Any, ref: int) -> Any:
@@ -784,8 +779,8 @@ class UserProc(Proc):
784
779
  env: Env,
785
780
  name: str,
786
781
  parms: list[str],
782
+ contracts: tuple[Any, ...],
787
783
  body: list,
788
- contracts: list[Any] | None = None,
789
784
  ):
790
785
  self.env = env
791
786
  self.name = name
@@ -800,6 +795,8 @@ class UserProc(Proc):
800
795
  self.arity = len(parms), len(parms)
801
796
 
802
797
  def __call__(self, *args: Any) -> Any:
798
+ check_args(self.name, args, self.arity, self.contracts)
799
+
803
800
  if self.arity[1] is None:
804
801
  args = tuple(
805
802
  list(args[: len(self.parms) - 1]) + [list(args[len(self.parms) - 1 :])]
@@ -923,7 +920,7 @@ def syn_lambda(env: Env, node: list) -> UserProc:
923
920
 
924
921
  parms.append(f"{item}")
925
922
 
926
- return UserProc(env, "", parms, node[2:])
923
+ return UserProc(env, "", parms, (), node[2:])
927
924
 
928
925
 
929
926
  def syn_define(env: Env, node: list) -> None:
@@ -947,7 +944,7 @@ def syn_define(env: Env, node: list) -> None:
947
944
  if type(item) is Sym:
948
945
  raise MyError(f"{node[0]}: {item} must be a keyword")
949
946
  if type(item) is not Keyword:
950
- raise MyError(f"{node[0]}: must be an identifier or keyword")
947
+ raise MyError(f"{node[0]}: must be a keyword")
951
948
  kparms.append(item.val)
952
949
  else:
953
950
  if type(item) is Keyword:
@@ -961,7 +958,7 @@ def syn_define(env: Env, node: list) -> None:
961
958
  if kw_only:
962
959
  env[n] = KeywordProc(env, n, parms, kparms, body, (len(parms), None))
963
960
  else:
964
- env[n] = UserProc(env, n, parms, body)
961
+ env[n] = UserProc(env, n, parms, (), body)
965
962
  return None
966
963
 
967
964
  elif type(node[1]) is not Sym:
@@ -988,7 +985,7 @@ def syn_define(env: Env, node: list) -> None:
988
985
 
989
986
  parms.append(f"{item}")
990
987
 
991
- env[n] = UserProc(env, n, parms, body)
988
+ env[n] = UserProc(env, n, parms, (), body)
992
989
 
993
990
  else:
994
991
  for item in node[2:-1]:
@@ -1008,7 +1005,7 @@ def syn_definec(env: Env, node: list) -> None:
1008
1005
 
1009
1006
  n = node[1][0].val
1010
1007
 
1011
- contracts: list[Proc | Contract] = []
1008
+ contracts: list[Any] = []
1012
1009
  parms: list[str] = []
1013
1010
  for item in node[1][1:]:
1014
1011
  if item == Sym("->"):
@@ -1025,7 +1022,7 @@ def syn_definec(env: Env, node: list) -> None:
1025
1022
  parms.append(f"{item[0]}")
1026
1023
  contracts.append(con)
1027
1024
 
1028
- env[n] = UserProc(env, n, parms, node[2:], contracts)
1025
+ env[n] = UserProc(env, n, parms, tuple(contracts), node[2:])
1029
1026
  return None
1030
1027
 
1031
1028
 
@@ -1126,10 +1123,12 @@ def syn_for(env: Env, node: list) -> None:
1126
1123
  my_eval(env, c)
1127
1124
 
1128
1125
 
1129
- def syn_quote(env: Env, node: list) -> list:
1126
+ def syn_quote(env: Env, node: list) -> Any:
1130
1127
  guard_term(node, 2, 2)
1131
- if type(node[1]) is list or type(node[1]) is Keyword:
1132
- return [list, node[1]]
1128
+ if type(node[1]) is Keyword:
1129
+ return QuotedKeyword(node[1])
1130
+ if type(node[1]) is list:
1131
+ return Quoted(node[1])
1133
1132
  return node[1]
1134
1133
 
1135
1134
 
@@ -1180,7 +1179,7 @@ def syn_and(env: Env, node: list) -> Any:
1180
1179
 
1181
1180
  if is_boolarr(first):
1182
1181
  vals = [first] + [my_eval(env, n) for n in node[2:]]
1183
- check_args(node[0], vals, (2, None), [is_boolarr])
1182
+ check_args(node[0], vals, (2, None), (is_boolarr,))
1184
1183
  return reduce(lambda a, b: boolop(a, b, logical_and), vals)
1185
1184
 
1186
1185
  raise MyError(f"{node[0]} expects (or/c bool? bool-array?)")
@@ -1204,7 +1203,7 @@ def syn_or(env: Env, node: list) -> Any:
1204
1203
 
1205
1204
  if is_boolarr(first):
1206
1205
  vals = [first] + [my_eval(env, n) for n in node[2:]]
1207
- check_args(node[0], vals, (2, None), [is_boolarr])
1206
+ check_args(node[0], vals, (2, None), (is_boolarr,))
1208
1207
  return reduce(lambda a, b: boolop(a, b, logical_or), vals)
1209
1208
 
1210
1209
  raise MyError(f"{node[0]} expects (or/c bool? bool-array?)")
@@ -1329,12 +1328,26 @@ def syn_class(env: Env, node: list) -> Any:
1329
1328
  def attr(env: Env, node: list) -> Any:
1330
1329
  guard_term(node, 3, 3)
1331
1330
 
1332
- if not isinstance(node[2], Sym):
1331
+ if type(node[2]) is not Sym:
1333
1332
  raise MyError("@r: attribute must be an identifier")
1334
1333
 
1335
1334
  return my_eval(env, [node[2], node[1]])
1336
1335
 
1337
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
+
1338
1351
  def my_eval(env: Env, node: object) -> Any:
1339
1352
  if type(node) is Sym:
1340
1353
  val = env.get(node.val)
@@ -1353,10 +1366,9 @@ def my_eval(env: Env, node: object) -> Any:
1353
1366
  raise MyError("Can't use edit methods if there's no input files")
1354
1367
  return edit_method(node.val, env["@filesetup"], env)
1355
1368
 
1356
- if isinstance(node, list):
1369
+ if type(node) is list:
1357
1370
  if not node:
1358
1371
  raise MyError("Illegal () expression")
1359
-
1360
1372
  if node[0] is list: # Handle vector literal
1361
1373
  return [my_eval(env, item) for item in node[1]]
1362
1374
 
@@ -1382,13 +1394,7 @@ def my_eval(env: Env, node: object) -> Any:
1382
1394
  if type(oper) is Syntax:
1383
1395
  return oper(env, node)
1384
1396
 
1385
- values = [my_eval(env, c) for c in node[1:]]
1386
- if type(oper) is Contract:
1387
- check_args(oper.name, values, (1, 1), None)
1388
- else:
1389
- check_args(oper.name, values, oper.arity, oper.contracts)
1390
-
1391
- return oper(*values)
1397
+ return oper(*(my_eval(env, c) for c in node[1:]))
1392
1398
 
1393
1399
  return node
1394
1400
 
@@ -1400,6 +1406,9 @@ env.update({
1400
1406
  "true": True,
1401
1407
  "false": False,
1402
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)),
1403
1412
  # syntax
1404
1413
  "lambda": Syntax(syn_lambda),
1405
1414
  "λ": Syntax(syn_lambda),
@@ -1424,10 +1433,11 @@ env.update({
1424
1433
  "number?": is_num,
1425
1434
  "real?": is_real,
1426
1435
  "int?": is_int,
1427
- "uint?": is_uint,
1428
- "nat?": is_nat,
1429
1436
  "float?": is_float,
1430
1437
  "frac?": is_frac,
1438
+ "complex?": Contract("complex?", lambda v: type(v) is complex),
1439
+ "nat?": is_nat,
1440
+ "nat1?": is_nat1,
1431
1441
  "threshold?": is_threshold,
1432
1442
  "any": any_p,
1433
1443
  "bool?": is_bool,
@@ -1435,7 +1445,7 @@ env.update({
1435
1445
  "symbol?": (is_symbol := Contract("symbol?", lambda v: type(v) is Sym)),
1436
1446
  "string?": is_str,
1437
1447
  "char?": (is_char := Contract("char?", lambda v: type(v) is Char)),
1438
- "vector?": (is_vector := Contract("vector?", lambda v: isinstance(v, list))),
1448
+ "vector?": (is_vector := Contract("vector?", lambda v: type(v) is list)),
1439
1449
  "array?": (is_array := Contract("array?", lambda v: isinstance(v, np.ndarray))),
1440
1450
  "bool-array?": is_boolarr,
1441
1451
  "range?": (is_range := Contract("range?", lambda v: type(v) is range)),
@@ -1447,156 +1457,162 @@ env.update({
1447
1457
  "begin": Proc("begin", lambda *x: x[-1] if x else None, (0, None)),
1448
1458
  "void": Proc("void", lambda *v: None, (0, 0)),
1449
1459
  # control / b-arrays
1450
- "not": Proc("not", lambda v: not v if type(v) is bool else logical_not(v), (1, 1), [bool_or_barr]),
1460
+ "not": Proc("not", lambda v: not v if type(v) is bool else logical_not(v), (1, 1), bool_or_barr),
1451
1461
  "and": Syntax(syn_and),
1452
1462
  "or": Syntax(syn_or),
1453
- "xor": Proc("xor", _xor, (2, None), [bool_or_barr]),
1463
+ "xor": Proc("xor", _xor, (2, None), bool_or_barr),
1454
1464
  # booleans
1455
- ">": Proc(">", lambda a, b: a > b, (2, 2), [is_real, is_real]),
1456
- ">=": Proc(">=", lambda a, b: a >= b, (2, 2), [is_real, is_real]),
1457
- "<": Proc("<", lambda a, b: a < b, (2, 2), [is_real, is_real]),
1458
- "<=": Proc("<=", lambda a, b: a <= b, (2, 2), [is_real, is_real]),
1459
- "=": Proc("=", equal_num, (1, None), [is_num]),
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),
1460
1470
  "eq?": Proc("eq?", lambda a, b: a is b, (2, 2)),
1461
1471
  "equal?": Proc("equal?", is_equal, (2, 2)),
1462
- "zero?": UserProc(env, "zero?", ["z"], [[Sym("="), Sym("z"), 0]], [is_num]),
1463
- "positive?": UserProc(
1464
- env, "positive?", ["x"], [[Sym(">"), Sym("x"), 0]], [is_real]
1465
- ),
1466
- "negative?": UserProc(
1467
- env, "negative?", ["x"], [[Sym("<"), Sym("x"), 0]], [is_real]
1468
- ),
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]]),
1469
1475
  "even?": UserProc(
1470
- env, "even?", ["n"], [[Sym("zero?"), [Sym("mod"), Sym("n"), 2]]], [is_int]
1476
+ env, "even?", ["n"], (is_int,), [[Sym("zero?"), [Sym("mod"), Sym("n"), 2]]]
1471
1477
  ),
1472
1478
  "odd?": UserProc(
1473
- env, "odd?", ["n"], [[Sym("not"), [Sym("even?"), Sym("n")]]], [is_int]
1479
+ env, "odd?", ["n"], (is_int,), [[Sym("not"), [Sym("even?"), Sym("n")]]]
1474
1480
  ),
1475
- ">=/c": Proc(">=/c", gte_c, (1, 1), [is_real]),
1476
- ">/c": Proc(">/c", gt_c, (1, 1), [is_real]),
1477
- "<=/c": Proc("<=/c", lte_c, (1, 1), [is_real]),
1478
- "</c": Proc("</c", lt_c, (1, 1), [is_real]),
1479
- "between/c": Proc("between/c", between_c, (2, 2), [is_real, is_real]),
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),
1480
1486
  # numbers
1481
- "+": Proc("+", lambda *v: sum(v), (0, None), [is_num]),
1482
- "-": Proc("-", minus, (1, None), [is_num]),
1483
- "*": Proc("*", mul, (0, None), [is_num]),
1484
- "/": Proc("/", num_div, (1, None), [is_num]),
1485
- "div": Proc("div", int_div, (2, None), [is_int]),
1486
- "add1": Proc("add1", lambda z: z + 1, (1, 1), [is_num]),
1487
- "sub1": Proc("sub1", lambda z: z - 1, (1, 1), [is_num]),
1488
- "sqrt": Proc("sqrt", _sqrt, (1, 1), [is_num]),
1489
- "real-part": Proc("real-part", lambda v: v.real, (1, 1), [is_num]),
1490
- "imag-part": Proc("imag-part", lambda v: v.imag, (1, 1), [is_num]),
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),
1491
1497
  # reals
1492
- "pow": Proc("pow", pow, (2, 2), [is_real]),
1493
- "exp": Proc("exp", math.exp, (1, 1), [is_real]),
1494
- "abs": Proc("abs", abs, (1, 1), [is_real]),
1495
- "ceil": Proc("ceil", math.ceil, (1, 1), [is_real]),
1496
- "floor": Proc("floor", math.floor, (1, 1), [is_real]),
1497
- "round": Proc("round", round, (1, 1), [is_real]),
1498
- "max": Proc("max", lambda *v: max(v), (1, None), [is_real]),
1499
- "min": Proc("min", lambda *v: min(v), (1, None), [is_real]),
1500
- "sin": Proc("sin", math.sin, (1, 1), [is_real]),
1501
- "cos": Proc("cos", math.cos, (1, 1), [is_real]),
1502
- "log": Proc("log", math.log, (1, 2), [is_real, is_real]),
1503
- "tan": Proc("tan", math.tan, (1, 1), [is_real]),
1504
- "mod": Proc("mod", lambda a, b: a % b, (2, 2), [is_int]),
1505
- "modulo": Proc("modulo", lambda a, b: a % b, (2, 2), [is_int]),
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),
1506
1512
  # symbols
1507
- "symbol->string": Proc("symbol->string", str, (1, 1), [is_symbol]),
1508
- "string->symbol": Proc("string->symbol", Sym, (1, 1), [is_str]),
1513
+ "symbol->string": Proc("symbol->string", str, (1, 1), is_symbol),
1514
+ "string->symbol": Proc("string->symbol", Sym, (1, 1), is_str),
1509
1515
  # strings
1510
- "string": Proc("string", string_append, (0, None), [is_char]),
1511
- "&": Proc("&", string_append, (0, None), [is_str]),
1512
- "split": Proc("split", str.split, (1, 2), [is_str, is_str]),
1513
- "strip": Proc("strip", str.strip, (1, 1), [is_str]),
1514
- "str-repeat": Proc("str-repeat", lambda s, a: s * a, (2, 2), [is_str, is_int]),
1515
- "startswith": Proc("startswith", str.startswith, (2, 2), [is_str, is_str]),
1516
- "endswith": Proc("endswith", str.endswith, (2, 2), [is_str, is_str]),
1517
- "replace": Proc("replace", str.replace, (3, 4), [is_str, is_str, is_str, is_int]),
1518
- "title": Proc("title", str.title, (1, 1), [is_str]),
1519
- "lower": Proc("lower", str.lower, (1, 1), [is_str]),
1520
- "upper": Proc("upper", str.upper, (1, 1), [is_str]),
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),
1521
1528
  # format
1522
- "char->int": Proc("char->int", lambda c: ord(c.val), (1, 1), [is_char]),
1523
- "int->char": Proc("int->char", Char, (1, 1), [is_int]),
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),
1524
1531
  "~a": Proc("~a", lambda *v: "".join([display_str(a) for a in v]), (0, None)),
1525
1532
  "~s": Proc("~s", lambda *v: " ".join([display_str(a) for a in v]), (0, None)),
1526
1533
  "~v": Proc("~v", lambda *v: " ".join([print_str(a) for a in v]), (0, None)),
1527
1534
  # keyword
1528
1535
  "keyword?": is_keyw,
1529
- "keyword->string": Proc("keyword->string", lambda k: k[1].val, (1, 1), [is_keyw]),
1530
- "string->keyword": Proc("string->keyword", lambda s: [list, Keyword(s)], (1, 1), [is_str]),
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),
1531
1538
  # vectors
1532
1539
  "vector": Proc("vector", lambda *a: list(a), (0, None)),
1533
1540
  "make-vector": Proc(
1534
- "make-vector", lambda size, a=0: [a] * size, (1, 2), [is_uint, any_p]
1541
+ "make-vector", lambda size, a=0: [a] * size, (1, 2), is_nat, any_p
1535
1542
  ),
1536
- "vector-append": Proc("vector-append", vector_append, (0, None), [is_vector]),
1537
- "vector-pop!": Proc("vector-pop!", list.pop, (1, 1), [is_vector]),
1538
- "vector-add!": Proc("vector-add!", list.append, (2, 2), [is_vector, any_p]),
1539
- "vector-set!": Proc("vector-set!", vector_set, (3, 3), [is_vector, is_int, any_p]),
1540
- "vector-extend!": Proc("vector-extend!", vector_extend, (2, None), [is_vector]),
1541
- "sort": Proc("sort", sorted, (1, 1), [is_vector]),
1542
- "sort!": Proc("sort!", list.sort, (1, 1), [is_vector]),
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),
1543
1550
  # arrays
1544
- "array": Proc("array", array_proc, (2, None), [is_symbol, is_real]),
1545
- "make-array": Proc("make-array", make_array, (2, 3), [is_symbol, is_uint, is_real]),
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),
1546
1553
  "array-splice!": Proc(
1547
- "array-splice!", splice, (2, 4), [is_array, is_real, is_int, is_int]
1554
+ "array-splice!", splice, (2, 4), is_array, is_real, is_int, is_int
1548
1555
  ),
1549
- "array-copy": Proc("array-copy", np.copy, (1, 1), [is_array]),
1550
- "count-nonzero": Proc("count-nonzero", np.count_nonzero, (1, 1), [is_array]),
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),
1551
1558
  # bool arrays
1552
1559
  "bool-array": Proc(
1553
- "bool-array", lambda *a: np.array(a, dtype=np.bool_), (1, None), [is_uint]
1560
+ "bool-array", lambda *a: np.array(a, dtype=np.bool_), (1, None), is_nat
1554
1561
  ),
1555
- "margin": Proc("margin", margin, (2, 3), None),
1556
- "mincut": Proc("mincut", mincut, (2, 2), [is_boolarr, is_uint]),
1557
- "minclip": Proc("minclip", minclip, (2, 2), [is_boolarr, is_uint]),
1558
- "maxcut": Proc("maxcut", maxcut, (2, 2), [is_boolarr, is_uint]),
1559
- "maxclip": Proc("maxclip", maxclip, (2, 2), [is_boolarr, is_uint]),
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),
1560
1567
  # ranges
1561
- "range": Proc("range", range, (1, 3), [is_int, is_int, int_not_zero]),
1568
+ "range": Proc("range", range, (1, 3), is_int, is_int, int_not_zero),
1562
1569
  # generic iterables
1563
- "len": Proc("len", len, (1, 1), [is_iterable]),
1564
- "reverse": Proc("reverse", lambda v: v[::-1], (1, 1), [is_sequence]),
1565
- "ref": Proc("ref", ref, (2, 2), [is_sequence, is_int]),
1566
- "slice": Proc("slice", p_slice, (2, 4), [is_sequence, is_int]),
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),
1567
1574
  # procedures
1568
- "map": Proc("map", palet_map, (2, 2), [is_proc, is_sequence]),
1569
- "apply": Proc("apply", apply, (2, 2), [is_proc, is_sequence]),
1570
- "and/c": Proc("and/c", andc, (1, None), [is_cont]),
1571
- "or/c": Proc("or/c", orc, (1, None), [is_cont]),
1572
- "not/c": Proc("not/c", notc, (1, 1), [is_cont]),
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),
1573
1580
  # hashs
1574
1581
  "hash": Proc("hash", palet_hash, (0, None)),
1575
- "hash-ref": Proc("hash", hash_ref, (2, 2), [is_hash, any_p]),
1576
- "hash-set!": Proc("hash-set!", hash_set, (3, 3), [is_hash, any_p, any_p]),
1577
- "has-key?": Proc("has-key?", lambda h, k: k in h, (2, 2), [is_hash, any_p]),
1578
- "hash-remove!": Proc("hash-remove!", hash_remove, (2, 2), [is_hash, any_p]),
1579
- "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),
1580
1587
  [[Sym("hash-set!"), Sym("h"), Sym("v"), [Sym("up"), [Sym("hash-ref"), Sym("h"), Sym("v")]]]],
1581
- [is_hash, any_p, any_p],
1582
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),
1583
1603
  # actions
1584
- "assert": Proc("assert", palet_assert, (1, 2), [any_p, orc(is_str, False)]),
1585
- "display": Proc("display", lambda v: print(display_str(v), end=""), (1, 1)),
1586
- "displayln": Proc("displayln", lambda v: print(display_str(v)), (1, 1)),
1587
- "error": Proc("error", raise_, (1, 1), [is_str]),
1588
- "sleep": Proc("sleep", sleep, (1, 1), [is_int_or_float]),
1589
- "print": Proc("print", lambda v: print(print_str(v), end=""), (1, 1)),
1590
- "println": Proc("println", lambda v: print(print_str(v)), (1, 1)),
1591
- "system": Proc("system", palet_system, (1, 1), [is_str]),
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),
1592
1608
  # conversions
1593
- "number->string": Proc("number->string", number_to_string, (1, 1), [is_num]),
1609
+ "number->string": Proc("number->string", number_to_string, (1, 1), is_num),
1594
1610
  "string->vector": Proc(
1595
- "string->vector", lambda s: [Char(c) for c in s], (1, 1), [is_str]
1611
+ "string->vector", lambda s: [Char(c) for c in s], (1, 1), is_str
1596
1612
  ),
1597
- "range->vector": Proc("range->vector", list, (1, 1), [is_range]),
1613
+ "range->vector": Proc("range->vector", list, (1, 1), is_range),
1598
1614
  # reflexion
1599
- "var-exists?": Proc("var-exists?", lambda sym: sym.val in env, (1, 1), [is_symbol]),
1615
+ "var-exists?": Proc("var-exists?", lambda sym: sym.val in env, (1, 1), is_symbol),
1600
1616
  "rename": Syntax(syn_rename),
1601
1617
  "delete": Syntax(syn_delete),
1602
1618
  })