tengwar 0.3.2__py3-none-any.whl → 0.3.4__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.
- tengwar/__init__.py +1 -1
- tengwar/interpreter.py +147 -25
- {tengwar-0.3.2.dist-info → tengwar-0.3.4.dist-info}/METADATA +1 -1
- {tengwar-0.3.2.dist-info → tengwar-0.3.4.dist-info}/RECORD +8 -8
- {tengwar-0.3.2.dist-info → tengwar-0.3.4.dist-info}/WHEEL +0 -0
- {tengwar-0.3.2.dist-info → tengwar-0.3.4.dist-info}/entry_points.txt +0 -0
- {tengwar-0.3.2.dist-info → tengwar-0.3.4.dist-info}/licenses/LICENSE +0 -0
- {tengwar-0.3.2.dist-info → tengwar-0.3.4.dist-info}/top_level.txt +0 -0
tengwar/__init__.py
CHANGED
tengwar/interpreter.py
CHANGED
|
@@ -74,6 +74,15 @@ class TengwarVector(TengwarValue):
|
|
|
74
74
|
def __eq__(self, other): return isinstance(other, TengwarVector) and self.elements == other.elements
|
|
75
75
|
|
|
76
76
|
|
|
77
|
+
class TengwarLazy(TengwarValue):
|
|
78
|
+
"""Lazy sequence — uses a generator factory for composable lazy ops."""
|
|
79
|
+
def __init__(self, make_gen):
|
|
80
|
+
self._make_gen = make_gen # callable that returns a fresh generator
|
|
81
|
+
def __iter__(self):
|
|
82
|
+
return self._make_gen()
|
|
83
|
+
def __repr__(self): return '<lazy-seq>'
|
|
84
|
+
|
|
85
|
+
|
|
77
86
|
class TengwarClosure(TengwarValue):
|
|
78
87
|
def __init__(self, params: list, body, env: 'Environment', name: str = ""):
|
|
79
88
|
self.params = params
|
|
@@ -528,6 +537,8 @@ class Interpreter:
|
|
|
528
537
|
return TengwarFloat(math.sqrt(args[0].value))
|
|
529
538
|
|
|
530
539
|
def _builtin_mod(self, args):
|
|
540
|
+
if args[1].value == 0:
|
|
541
|
+
raise RuntimeError_("Modulo by zero")
|
|
531
542
|
return TengwarInt(args[0].value % args[1].value)
|
|
532
543
|
|
|
533
544
|
def _builtin_len(self, args):
|
|
@@ -627,15 +638,30 @@ class Interpreter:
|
|
|
627
638
|
return TengwarVector(vec.elements[start:end])
|
|
628
639
|
|
|
629
640
|
def _builtin_map(self, args):
|
|
630
|
-
fn,
|
|
631
|
-
if
|
|
632
|
-
|
|
633
|
-
|
|
641
|
+
fn, seq = args[0], args[1]
|
|
642
|
+
if isinstance(seq, TengwarLazy):
|
|
643
|
+
interp = self
|
|
644
|
+
parent = seq._make_gen
|
|
645
|
+
def make_gen():
|
|
646
|
+
for val in parent():
|
|
647
|
+
yield interp._call_function(fn, [val])
|
|
648
|
+
return TengwarLazy(make_gen)
|
|
649
|
+
if not isinstance(seq, TengwarVector):
|
|
650
|
+
raise RuntimeError_("map requires a vector or lazy sequence")
|
|
651
|
+
return TengwarVector([self._call_function(fn, [e]) for e in seq.elements])
|
|
634
652
|
|
|
635
653
|
def _builtin_filter(self, args):
|
|
636
|
-
fn,
|
|
654
|
+
fn, seq = args[0], args[1]
|
|
655
|
+
if isinstance(seq, TengwarLazy):
|
|
656
|
+
interp = self
|
|
657
|
+
parent = seq._make_gen
|
|
658
|
+
def make_gen():
|
|
659
|
+
for val in parent():
|
|
660
|
+
if interp._is_truthy(interp._call_function(fn, [val])):
|
|
661
|
+
yield val
|
|
662
|
+
return TengwarLazy(make_gen)
|
|
637
663
|
result = []
|
|
638
|
-
for e in
|
|
664
|
+
for e in seq.elements:
|
|
639
665
|
if self._is_truthy(self._call_function(fn, [e])):
|
|
640
666
|
result.append(e)
|
|
641
667
|
return TengwarVector(result)
|
|
@@ -729,12 +755,23 @@ class Interpreter:
|
|
|
729
755
|
|
|
730
756
|
def _builtin_head(self, args):
|
|
731
757
|
vec = args[0]
|
|
758
|
+
if isinstance(vec, TengwarLazy):
|
|
759
|
+
for val in vec:
|
|
760
|
+
return val
|
|
761
|
+
raise RuntimeError_("head of empty lazy sequence")
|
|
732
762
|
if not vec.elements:
|
|
733
763
|
raise RuntimeError_("head of empty vector")
|
|
734
764
|
return vec.elements[0]
|
|
735
765
|
|
|
736
766
|
def _builtin_tail(self, args):
|
|
737
767
|
vec = args[0]
|
|
768
|
+
if isinstance(vec, TengwarLazy):
|
|
769
|
+
parent = vec._make_gen
|
|
770
|
+
def make_gen():
|
|
771
|
+
gen = parent()
|
|
772
|
+
next(gen, None) # skip first
|
|
773
|
+
yield from gen
|
|
774
|
+
return TengwarLazy(make_gen)
|
|
738
775
|
if not vec.elements:
|
|
739
776
|
raise RuntimeError_("tail of empty vector")
|
|
740
777
|
return TengwarVector(vec.elements[1:])
|
|
@@ -747,6 +784,11 @@ class Interpreter:
|
|
|
747
784
|
|
|
748
785
|
def _builtin_nth(self, args):
|
|
749
786
|
col, idx = args[0], args[1].value
|
|
787
|
+
if isinstance(col, TengwarLazy):
|
|
788
|
+
for i, val in enumerate(col):
|
|
789
|
+
if i == idx:
|
|
790
|
+
return val
|
|
791
|
+
raise RuntimeError_(f"nth: index {idx} out of range")
|
|
750
792
|
if isinstance(col, TengwarTuple): return col.elements[idx]
|
|
751
793
|
if isinstance(col, TengwarVector): return col.elements[idx]
|
|
752
794
|
raise RuntimeError_(f"Cannot nth into {type(col).__name__}")
|
|
@@ -880,8 +922,16 @@ class Interpreter:
|
|
|
880
922
|
def _builtin_enumerate(self, args):
|
|
881
923
|
"""(enumerate vec) = vector of (index, element) tuples"""
|
|
882
924
|
vec = args[0]
|
|
925
|
+
if isinstance(vec, TengwarLazy):
|
|
926
|
+
parent = vec._make_gen
|
|
927
|
+
def make_gen():
|
|
928
|
+
i = 0
|
|
929
|
+
for val in parent():
|
|
930
|
+
yield TengwarTuple([TengwarInt(i), val])
|
|
931
|
+
i += 1
|
|
932
|
+
return TengwarLazy(make_gen)
|
|
883
933
|
if not isinstance(vec, TengwarVector):
|
|
884
|
-
raise RuntimeError_("enumerate requires a vector")
|
|
934
|
+
raise RuntimeError_("enumerate requires a vector or lazy sequence")
|
|
885
935
|
return TengwarVector([
|
|
886
936
|
TengwarTuple([TengwarInt(i), e])
|
|
887
937
|
for i, e in enumerate(vec.elements)
|
|
@@ -898,10 +948,25 @@ class Interpreter:
|
|
|
898
948
|
def _builtin_apply(self, args):
|
|
899
949
|
fn, arg_vec = args[0], args[1]
|
|
900
950
|
if isinstance(arg_vec, TengwarVector):
|
|
901
|
-
|
|
902
|
-
|
|
903
|
-
|
|
904
|
-
|
|
951
|
+
elems = arg_vec.elements
|
|
952
|
+
elif isinstance(arg_vec, TengwarTuple):
|
|
953
|
+
elems = arg_vec.elements
|
|
954
|
+
else:
|
|
955
|
+
elems = [arg_vec]
|
|
956
|
+
if not elems:
|
|
957
|
+
raise RuntimeError_("apply: cannot apply function to empty collection")
|
|
958
|
+
if len(elems) == 1:
|
|
959
|
+
try:
|
|
960
|
+
return self._call_function(fn, elems)
|
|
961
|
+
except (TypeError, IndexError):
|
|
962
|
+
raise RuntimeError_("apply: function requires more arguments")
|
|
963
|
+
if len(elems) == 2:
|
|
964
|
+
return self._call_function(fn, elems)
|
|
965
|
+
# >2 args: reduce (Clojure-style variadic apply)
|
|
966
|
+
acc = self._call_function(fn, [elems[0], elems[1]])
|
|
967
|
+
for e in elems[2:]:
|
|
968
|
+
acc = self._call_function(fn, [acc, e])
|
|
969
|
+
return acc
|
|
905
970
|
|
|
906
971
|
def _builtin_err(self, args):
|
|
907
972
|
raise RuntimeError_(self._display(args[0]) if args else "error")
|
|
@@ -995,17 +1060,41 @@ class Interpreter:
|
|
|
995
1060
|
return TengwarInt(-1)
|
|
996
1061
|
|
|
997
1062
|
def _builtin_take(self, args):
|
|
998
|
-
n,
|
|
999
|
-
|
|
1063
|
+
n, seq = int(self._num_val(args[0])), args[1]
|
|
1064
|
+
if isinstance(seq, TengwarLazy):
|
|
1065
|
+
result = []
|
|
1066
|
+
for val in seq:
|
|
1067
|
+
result.append(val)
|
|
1068
|
+
if len(result) >= n:
|
|
1069
|
+
break
|
|
1070
|
+
return TengwarVector(result)
|
|
1071
|
+
return TengwarVector(seq.elements[:n])
|
|
1000
1072
|
|
|
1001
1073
|
def _builtin_drop(self, args):
|
|
1002
|
-
n,
|
|
1003
|
-
|
|
1074
|
+
n, seq = int(self._num_val(args[0])), args[1]
|
|
1075
|
+
if isinstance(seq, TengwarLazy):
|
|
1076
|
+
parent = seq._make_gen
|
|
1077
|
+
count = n
|
|
1078
|
+
def make_gen():
|
|
1079
|
+
gen = parent()
|
|
1080
|
+
for _ in range(count):
|
|
1081
|
+
next(gen, None)
|
|
1082
|
+
yield from gen
|
|
1083
|
+
return TengwarLazy(make_gen)
|
|
1084
|
+
return TengwarVector(seq.elements[n:])
|
|
1004
1085
|
|
|
1005
1086
|
def _builtin_take_while(self, args):
|
|
1006
|
-
fn,
|
|
1087
|
+
fn, seq = args[0], args[1]
|
|
1088
|
+
if isinstance(seq, TengwarLazy):
|
|
1089
|
+
result = []
|
|
1090
|
+
for val in seq:
|
|
1091
|
+
if self._is_truthy(self._call_function(fn, [val])):
|
|
1092
|
+
result.append(val)
|
|
1093
|
+
else:
|
|
1094
|
+
break
|
|
1095
|
+
return TengwarVector(result)
|
|
1007
1096
|
result = []
|
|
1008
|
-
for e in
|
|
1097
|
+
for e in seq.elements:
|
|
1009
1098
|
if self._is_truthy(self._call_function(fn, [e])):
|
|
1010
1099
|
result.append(e)
|
|
1011
1100
|
else:
|
|
@@ -1013,10 +1102,21 @@ class Interpreter:
|
|
|
1013
1102
|
return TengwarVector(result)
|
|
1014
1103
|
|
|
1015
1104
|
def _builtin_drop_while(self, args):
|
|
1016
|
-
fn,
|
|
1105
|
+
fn, seq = args[0], args[1]
|
|
1106
|
+
if isinstance(seq, TengwarLazy):
|
|
1107
|
+
interp = self
|
|
1108
|
+
parent = seq._make_gen
|
|
1109
|
+
def make_gen():
|
|
1110
|
+
dropping = True
|
|
1111
|
+
for val in parent():
|
|
1112
|
+
if dropping and interp._is_truthy(interp._call_function(fn, [val])):
|
|
1113
|
+
continue
|
|
1114
|
+
dropping = False
|
|
1115
|
+
yield val
|
|
1116
|
+
return TengwarLazy(make_gen)
|
|
1017
1117
|
dropping = True
|
|
1018
1118
|
result = []
|
|
1019
|
-
for e in
|
|
1119
|
+
for e in seq.elements:
|
|
1020
1120
|
if dropping and self._is_truthy(self._call_function(fn, [e])):
|
|
1021
1121
|
continue
|
|
1022
1122
|
dropping = False
|
|
@@ -1070,10 +1170,20 @@ class Interpreter:
|
|
|
1070
1170
|
return TengwarTuple([TengwarVector(yes), TengwarVector(no)])
|
|
1071
1171
|
|
|
1072
1172
|
def _builtin_scan(self, args):
|
|
1073
|
-
fn, init,
|
|
1173
|
+
fn, init, seq = args[0], args[1], args[2]
|
|
1174
|
+
if isinstance(seq, TengwarLazy):
|
|
1175
|
+
interp = self
|
|
1176
|
+
parent = seq._make_gen
|
|
1177
|
+
def make_gen():
|
|
1178
|
+
acc = init
|
|
1179
|
+
yield acc
|
|
1180
|
+
for val in parent():
|
|
1181
|
+
acc = interp._call_function(fn, [acc, val])
|
|
1182
|
+
yield acc
|
|
1183
|
+
return TengwarLazy(make_gen)
|
|
1074
1184
|
acc = init
|
|
1075
1185
|
result = [acc]
|
|
1076
|
-
for e in
|
|
1186
|
+
for e in seq.elements:
|
|
1077
1187
|
acc = self._call_function(fn, [acc, e])
|
|
1078
1188
|
result.append(acc)
|
|
1079
1189
|
return TengwarVector(result)
|
|
@@ -1095,6 +1205,16 @@ class Interpreter:
|
|
|
1095
1205
|
return TengwarVector([val] * n)
|
|
1096
1206
|
|
|
1097
1207
|
def _builtin_iterate(self, args):
|
|
1208
|
+
"""(iterate fn init n) → eager vector, (iterate fn init) → lazy sequence"""
|
|
1209
|
+
if len(args) == 2:
|
|
1210
|
+
fn, init = args[0], args[1]
|
|
1211
|
+
interp = self
|
|
1212
|
+
def make_gen():
|
|
1213
|
+
val = init
|
|
1214
|
+
while True:
|
|
1215
|
+
yield val
|
|
1216
|
+
val = interp._call_function(fn, [val])
|
|
1217
|
+
return TengwarLazy(make_gen)
|
|
1098
1218
|
fn, init, n = args[0], args[1], int(self._num_val(args[2]))
|
|
1099
1219
|
result = [init]
|
|
1100
1220
|
val = init
|
|
@@ -1815,9 +1935,9 @@ class Interpreter:
|
|
|
1815
1935
|
raise RuntimeError_(f"Unknown node type: {type(node).__name__}")
|
|
1816
1936
|
|
|
1817
1937
|
def _eval_binop(self, op: str, left: TengwarValue, right: TengwarValue) -> TengwarValue:
|
|
1818
|
-
# String concatenation with +
|
|
1819
|
-
if op == '+' and isinstance(left, TengwarStr):
|
|
1820
|
-
return TengwarStr(left.value +
|
|
1938
|
+
# String concatenation with + (both must be strings — no implicit coercion)
|
|
1939
|
+
if op == '+' and isinstance(left, TengwarStr) and isinstance(right, TengwarStr):
|
|
1940
|
+
return TengwarStr(left.value + right.value)
|
|
1821
1941
|
|
|
1822
1942
|
# Numeric operations
|
|
1823
1943
|
if isinstance(left, (TengwarInt, TengwarFloat)) and isinstance(right, (TengwarInt, TengwarFloat)):
|
|
@@ -1831,7 +1951,9 @@ class Interpreter:
|
|
|
1831
1951
|
if op == '/':
|
|
1832
1952
|
if rv == 0: raise RuntimeError_("Division by zero")
|
|
1833
1953
|
return TengwarFloat(lv / rv) if use_float else TengwarInt(lv // rv)
|
|
1834
|
-
if op == '%':
|
|
1954
|
+
if op == '%':
|
|
1955
|
+
if rv == 0: raise RuntimeError_("Modulo by zero")
|
|
1956
|
+
return wrap(lv % rv)
|
|
1835
1957
|
if op == '=': return TengwarBool(lv == rv)
|
|
1836
1958
|
if op == '!=': return TengwarBool(lv != rv)
|
|
1837
1959
|
if op == '<': return TengwarBool(lv < rv)
|
|
@@ -1,17 +1,17 @@
|
|
|
1
|
-
tengwar/__init__.py,sha256=
|
|
1
|
+
tengwar/__init__.py,sha256=r2Fv1Bxv43nmcSUzoe1rVFZ1c9rI8gwXht1EyIVuMLI,579
|
|
2
2
|
tengwar/__main__.py,sha256=dF1qCzTBDRAf47QGJ6e2kqefPZztrEaE9WuM1n1NfLI,179
|
|
3
3
|
tengwar/ast_nodes.py,sha256=ghhqQQBoqWT-oc9xdCGo2hXBLSqh1zz74hKDyIUtE_Y,7749
|
|
4
4
|
tengwar/binary_ast.py,sha256=UVDGpk_OvHxPLcaToYkAuYA_cg9QQwj6yJXZ057dW0Q,20729
|
|
5
5
|
tengwar/errors.py,sha256=tpZwlDorqUvqX-rtTjL2nhu51Kcdc2ozYBbnJBhR1Hk,773
|
|
6
|
-
tengwar/interpreter.py,sha256=
|
|
6
|
+
tengwar/interpreter.py,sha256=t4Lun4pbUdVFwQoiU44_-1CSsjovo44u4CRX5IZRbuI,85532
|
|
7
7
|
tengwar/lexer.py,sha256=d8MphHWmS6aA7HhRdu-CzX1Ma_3oYZSqkhNNrqLa_Ak,17666
|
|
8
8
|
tengwar/mcp_server.py,sha256=P23h-OiedeiowHlvknKsDU1cZ1eaT2ZbXfjCMUGvHus,17921
|
|
9
9
|
tengwar/parser.py,sha256=J9Sc4x8Rs9Rmc5IkOegcfuEWOSIi54fXhjwviF0SjvY,25141
|
|
10
10
|
tengwar/repl.py,sha256=FOvKth8MLOEVExgUvdod-qJqLydbVFDEA1DRhVGjZnQ,4880
|
|
11
11
|
tengwar/vm.py,sha256=etTJTufLqn76GAnZpzG_DLQQ3rXLsyFvHPEU3aNphIY,15883
|
|
12
|
-
tengwar-0.3.
|
|
13
|
-
tengwar-0.3.
|
|
14
|
-
tengwar-0.3.
|
|
15
|
-
tengwar-0.3.
|
|
16
|
-
tengwar-0.3.
|
|
17
|
-
tengwar-0.3.
|
|
12
|
+
tengwar-0.3.4.dist-info/licenses/LICENSE,sha256=qzDJpz75A1ntwYbNw63k1J-9Ov6v4z62Uj7uDcWxv1w,1072
|
|
13
|
+
tengwar-0.3.4.dist-info/METADATA,sha256=Nb-AVaVRycCRe-lrQw8y7X7gkfNwyMSEl06vR4CTFa8,6949
|
|
14
|
+
tengwar-0.3.4.dist-info/WHEEL,sha256=wUyA8OaulRlbfwMtmQsvNngGrxQHAvkKcvRmdizlJi0,92
|
|
15
|
+
tengwar-0.3.4.dist-info/entry_points.txt,sha256=W_Zolo2TLJBIDkgAkV7yWzQWKwicET_J9gs4crmrfI4,46
|
|
16
|
+
tengwar-0.3.4.dist-info/top_level.txt,sha256=VyO8Esj_l1yx0c52WUt_KUheaLbXOv2O2kGPZ1eG38k,8
|
|
17
|
+
tengwar-0.3.4.dist-info/RECORD,,
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|