tengwar 0.3.1__py3-none-any.whl → 0.3.3__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 CHANGED
@@ -5,7 +5,7 @@ Built from first principles for machine intelligence.
5
5
  Zero ambiguity. Maximum semantic density. Binary AST protocol.
6
6
  """
7
7
 
8
- __version__ = "0.3.1"
8
+ __version__ = "0.3.3"
9
9
  __author__ = "TENGWAR Project"
10
10
 
11
11
  from .lexer import tokenize
tengwar/ast_nodes.py CHANGED
@@ -215,8 +215,9 @@ class TypeAnn(ASTNode):
215
215
 
216
216
  @dataclass
217
217
  class Proof(ASTNode):
218
- """(⊢ assertion) - proof obligation"""
218
+ """(⊢ assertion) or (⊢ assertion message) - proof obligation"""
219
219
  assertion: Any = None
220
+ message: Any = None
220
221
  def __post_init__(self):
221
222
  self.type = NodeType.PROOF
222
223
 
tengwar/interpreter.py CHANGED
@@ -74,6 +74,21 @@ 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 — generated on demand by take/head/etc."""
79
+ def __init__(self, gen_fn, init_val):
80
+ self.gen_fn = gen_fn # function: val -> next_val
81
+ self.init_val = init_val
82
+ def take(self, n, call_fn):
83
+ result = [self.init_val]
84
+ val = self.init_val
85
+ for _ in range(n - 1):
86
+ val = call_fn(self.gen_fn, [val])
87
+ result.append(val)
88
+ return result
89
+ def __repr__(self): return f'<lazy-seq from {repr(self.init_val)}>'
90
+
91
+
77
92
  class TengwarClosure(TengwarValue):
78
93
  def __init__(self, params: list, body, env: 'Environment', name: str = ""):
79
94
  self.params = params
@@ -241,6 +256,8 @@ class Interpreter:
241
256
  # Vector/sequence ops
242
257
  env.set('vec', TengwarBuiltin('vec', lambda args: TengwarVector(list(args))))
243
258
  env.set('push', TengwarBuiltin('push', self._builtin_push))
259
+ env.set('cons', TengwarBuiltin('cons', self._builtin_cons))
260
+ env.set('prepend', TengwarBuiltin('prepend', self._builtin_cons))
244
261
  env.set('pop', TengwarBuiltin('pop', self._builtin_pop))
245
262
  env.set('get', TengwarBuiltin('get', self._builtin_get))
246
263
  env.set('set-at', TengwarBuiltin('set-at', self._builtin_set_at))
@@ -314,6 +331,7 @@ class Interpreter:
314
331
  env.set('&', TengwarBuiltin('&', lambda args: self._eval_binop('&', args[0], args[1])))
315
332
  env.set('|', TengwarBuiltin('|', lambda args: self._eval_binop('|', args[0], args[1])))
316
333
  env.set('!', TengwarBuiltin('!', lambda args: self._eval_unop('!', args[0])))
334
+ env.set('not', TengwarBuiltin('not', lambda args: self._eval_unop('!', args[0])))
317
335
 
318
336
  # === DICT / HASHMAP ===
319
337
  env.set('dict', TengwarBuiltin('dict', self._builtin_dict))
@@ -583,6 +601,13 @@ class Interpreter:
583
601
  raise RuntimeError_("push requires a vector")
584
602
  return TengwarVector(vec.elements + [args[1]])
585
603
 
604
+ def _builtin_cons(self, args):
605
+ """(cons element vector) — prepend element to front"""
606
+ elem, vec = args[0], args[1]
607
+ if not isinstance(vec, TengwarVector):
608
+ raise RuntimeError_("cons requires a vector as second argument")
609
+ return TengwarVector([elem] + vec.elements)
610
+
586
611
  def _builtin_pop(self, args):
587
612
  vec = args[0]
588
613
  if not isinstance(vec, TengwarVector):
@@ -695,13 +720,15 @@ class Interpreter:
695
720
  return TengwarVector(sorted(vec.elements, key=lambda e: e.value))
696
721
 
697
722
  def _builtin_flatten(self, args):
698
- result = []
699
- for e in args[0].elements:
700
- if isinstance(e, TengwarVector):
701
- result.extend(e.elements)
702
- else:
703
- result.append(e)
704
- return TengwarVector(result)
723
+ def _deep_flatten(elements):
724
+ result = []
725
+ for e in elements:
726
+ if isinstance(e, TengwarVector):
727
+ result.extend(_deep_flatten(e.elements))
728
+ else:
729
+ result.append(e)
730
+ return result
731
+ return TengwarVector(_deep_flatten(args[0].elements))
705
732
 
706
733
  def _builtin_zip(self, args):
707
734
  vecs = [a.elements for a in args]
@@ -717,6 +744,8 @@ class Interpreter:
717
744
 
718
745
  def _builtin_head(self, args):
719
746
  vec = args[0]
747
+ if isinstance(vec, TengwarLazy):
748
+ return vec.init_val
720
749
  if not vec.elements:
721
750
  raise RuntimeError_("head of empty vector")
722
751
  return vec.elements[0]
@@ -983,8 +1012,10 @@ class Interpreter:
983
1012
  return TengwarInt(-1)
984
1013
 
985
1014
  def _builtin_take(self, args):
986
- n, vec = int(self._num_val(args[0])), args[1]
987
- return TengwarVector(vec.elements[:n])
1015
+ n, seq = int(self._num_val(args[0])), args[1]
1016
+ if isinstance(seq, TengwarLazy):
1017
+ return TengwarVector(seq.take(n, self._call_function))
1018
+ return TengwarVector(seq.elements[:n])
988
1019
 
989
1020
  def _builtin_drop(self, args):
990
1021
  n, vec = int(self._num_val(args[0])), args[1]
@@ -1083,6 +1114,11 @@ class Interpreter:
1083
1114
  return TengwarVector([val] * n)
1084
1115
 
1085
1116
  def _builtin_iterate(self, args):
1117
+ """(iterate fn init n) → eager vector, (iterate fn init) → lazy sequence"""
1118
+ if len(args) == 2:
1119
+ # Lazy form: return a TengwarLazy that take/head can consume
1120
+ fn, init = args[0], args[1]
1121
+ return TengwarLazy(fn, init)
1086
1122
  fn, init, n = args[0], args[1], int(self._num_val(args[2]))
1087
1123
  result = [init]
1088
1124
  val = init
@@ -1092,9 +1128,21 @@ class Interpreter:
1092
1128
  return TengwarVector(result)
1093
1129
 
1094
1130
  def _builtin_juxt(self, args):
1095
- """(juxt f1 f2 ... val) apply multiple fns to same value"""
1096
- fns, val = args[:-1], args[-1]
1097
- return TengwarVector([self._call_function(fn, [val]) for fn in fns])
1131
+ """(juxt f1 f2 ...) fn, or ((juxt f1 f2 ...) val) → vector of results"""
1132
+ def _is_tengwar_callable(x):
1133
+ return isinstance(x, (TengwarBuiltin, TengwarClosure))
1134
+ # If last arg is not callable, treat it as the value to apply to
1135
+ if len(args) >= 2 and not _is_tengwar_callable(args[-1]):
1136
+ fns, val = args[:-1], args[-1]
1137
+ return TengwarVector([self._call_function(fn, [val]) for fn in fns])
1138
+ else:
1139
+ # Return a closure that applies all functions to a value
1140
+ fns = list(args)
1141
+ interp = self
1142
+ def juxt_fn(inner_args):
1143
+ val = inner_args[0]
1144
+ return TengwarVector([interp._call_function(fn, [val]) for fn in fns])
1145
+ return TengwarBuiltin('juxt*', juxt_fn)
1098
1146
 
1099
1147
  def _builtin_min_by(self, args):
1100
1148
  fn, vec = args[0], args[1]
@@ -1678,6 +1726,9 @@ class Interpreter:
1678
1726
  if isinstance(node, Proof):
1679
1727
  result = self.eval(node.assertion, env)
1680
1728
  if not self._is_truthy(result):
1729
+ if node.message:
1730
+ msg = self.eval(node.message, env)
1731
+ raise ProofError(f"Proof obligation failed: {msg}")
1681
1732
  raise ProofError(f"Proof obligation failed: {repr(result)}")
1682
1733
  return result
1683
1734
 
@@ -1788,9 +1839,9 @@ class Interpreter:
1788
1839
  raise RuntimeError_(f"Unknown node type: {type(node).__name__}")
1789
1840
 
1790
1841
  def _eval_binop(self, op: str, left: TengwarValue, right: TengwarValue) -> TengwarValue:
1791
- # String concatenation with +
1792
- if op == '+' and isinstance(left, TengwarStr):
1793
- return TengwarStr(left.value + self._display(right))
1842
+ # String concatenation with + (both must be strings — no implicit coercion)
1843
+ if op == '+' and isinstance(left, TengwarStr) and isinstance(right, TengwarStr):
1844
+ return TengwarStr(left.value + right.value)
1794
1845
 
1795
1846
  # Numeric operations
1796
1847
  if isinstance(left, (TengwarInt, TengwarFloat)) and isinstance(right, (TengwarInt, TengwarFloat)):
tengwar/lexer.py CHANGED
@@ -120,7 +120,7 @@ KEYWORDS = {
120
120
  'do': TokenType.SEQ,
121
121
  'par': TokenType.PARALLEL,
122
122
  'nil': TokenType.UNIT,
123
- 'mod': TokenType.MODULE,
123
+ 'module': TokenType.MODULE,
124
124
  # Note: let, pipe, throw, catch, try are handled as symbols
125
125
  # by the parser since they need custom parse rules
126
126
  }
@@ -130,6 +130,8 @@ SINGLE_CHAR = {
130
130
  ')': TokenType.RPAREN,
131
131
  '{': TokenType.LBRACE,
132
132
  '}': TokenType.RBRACE,
133
+ '[': TokenType.LBRACKET,
134
+ ']': TokenType.RBRACKET,
133
135
  '?': TokenType.COND,
134
136
  '~': TokenType.MATCH,
135
137
  '+': TokenType.PLUS,
tengwar/parser.py CHANGED
@@ -426,11 +426,14 @@ class Parser:
426
426
  return Recurse(name=name, body=body, line=line, col=col)
427
427
 
428
428
  def parse_proof(self, line: int, col: int) -> Proof:
429
- """(⊢ assertion)"""
429
+ """(⊢ assertion) or (⊢ assertion message)"""
430
430
  self.advance() # consume ⊢
431
431
  assertion = self.parse_expr()
432
+ message = None
433
+ if self.peek_type() != TokenType.RPAREN:
434
+ message = self.parse_expr()
432
435
  self.expect(TokenType.RPAREN)
433
- return Proof(assertion=assertion, line=line, col=col)
436
+ return Proof(assertion=assertion, message=message, line=line, col=col)
434
437
 
435
438
  def parse_mutate(self, line: int, col: int) -> Mutate:
436
439
  """(μ name value)"""
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: tengwar
3
- Version: 0.3.1
3
+ Version: 0.3.3
4
4
  Summary: The AI-Native Programming Language
5
5
  Author: TENGWAR Project
6
6
  License: MIT
@@ -0,0 +1,17 @@
1
+ tengwar/__init__.py,sha256=LeSxwrvAQpT7OE3vzGjdN9MEuNOqHlK1O78S3hIxg-o,579
2
+ tengwar/__main__.py,sha256=dF1qCzTBDRAf47QGJ6e2kqefPZztrEaE9WuM1n1NfLI,179
3
+ tengwar/ast_nodes.py,sha256=ghhqQQBoqWT-oc9xdCGo2hXBLSqh1zz74hKDyIUtE_Y,7749
4
+ tengwar/binary_ast.py,sha256=UVDGpk_OvHxPLcaToYkAuYA_cg9QQwj6yJXZ057dW0Q,20729
5
+ tengwar/errors.py,sha256=tpZwlDorqUvqX-rtTjL2nhu51Kcdc2ozYBbnJBhR1Hk,773
6
+ tengwar/interpreter.py,sha256=jej7k6I-WwupqlQgJSf6_ihTtawMPvR97_pDsVTd9ts,81919
7
+ tengwar/lexer.py,sha256=d8MphHWmS6aA7HhRdu-CzX1Ma_3oYZSqkhNNrqLa_Ak,17666
8
+ tengwar/mcp_server.py,sha256=P23h-OiedeiowHlvknKsDU1cZ1eaT2ZbXfjCMUGvHus,17921
9
+ tengwar/parser.py,sha256=J9Sc4x8Rs9Rmc5IkOegcfuEWOSIi54fXhjwviF0SjvY,25141
10
+ tengwar/repl.py,sha256=FOvKth8MLOEVExgUvdod-qJqLydbVFDEA1DRhVGjZnQ,4880
11
+ tengwar/vm.py,sha256=etTJTufLqn76GAnZpzG_DLQQ3rXLsyFvHPEU3aNphIY,15883
12
+ tengwar-0.3.3.dist-info/licenses/LICENSE,sha256=qzDJpz75A1ntwYbNw63k1J-9Ov6v4z62Uj7uDcWxv1w,1072
13
+ tengwar-0.3.3.dist-info/METADATA,sha256=U5NW_NAMk54OB8OxJ8O4nrxPLKsfIJpnuUAAxL9GzRc,6949
14
+ tengwar-0.3.3.dist-info/WHEEL,sha256=wUyA8OaulRlbfwMtmQsvNngGrxQHAvkKcvRmdizlJi0,92
15
+ tengwar-0.3.3.dist-info/entry_points.txt,sha256=W_Zolo2TLJBIDkgAkV7yWzQWKwicET_J9gs4crmrfI4,46
16
+ tengwar-0.3.3.dist-info/top_level.txt,sha256=VyO8Esj_l1yx0c52WUt_KUheaLbXOv2O2kGPZ1eG38k,8
17
+ tengwar-0.3.3.dist-info/RECORD,,
@@ -1,17 +0,0 @@
1
- tengwar/__init__.py,sha256=vnHeFtc3HEiQl6tDYr9B7A9PmjvAulARvZY02OHd40k,579
2
- tengwar/__main__.py,sha256=dF1qCzTBDRAf47QGJ6e2kqefPZztrEaE9WuM1n1NfLI,179
3
- tengwar/ast_nodes.py,sha256=Q5rrMaAtKNPraVJ0nnwpGUiXJerVKAhKXLZjmaaGfyg,7698
4
- tengwar/binary_ast.py,sha256=UVDGpk_OvHxPLcaToYkAuYA_cg9QQwj6yJXZ057dW0Q,20729
5
- tengwar/errors.py,sha256=tpZwlDorqUvqX-rtTjL2nhu51Kcdc2ozYBbnJBhR1Hk,773
6
- tengwar/interpreter.py,sha256=8tNzLtSGp8CIAFkuPGikZobnQDeeg0nKlmONqa4NutA,79426
7
- tengwar/lexer.py,sha256=6PjWeuAWrYHPug_Mtfuk1kyB6Rbp5oTVLil9TKlKH6o,17605
8
- tengwar/mcp_server.py,sha256=P23h-OiedeiowHlvknKsDU1cZ1eaT2ZbXfjCMUGvHus,17921
9
- tengwar/parser.py,sha256=VY6zNHl8IsOHOLjSUJa9nUL-I9IogRKKCsU1XdBQutM,24985
10
- tengwar/repl.py,sha256=FOvKth8MLOEVExgUvdod-qJqLydbVFDEA1DRhVGjZnQ,4880
11
- tengwar/vm.py,sha256=etTJTufLqn76GAnZpzG_DLQQ3rXLsyFvHPEU3aNphIY,15883
12
- tengwar-0.3.1.dist-info/licenses/LICENSE,sha256=qzDJpz75A1ntwYbNw63k1J-9Ov6v4z62Uj7uDcWxv1w,1072
13
- tengwar-0.3.1.dist-info/METADATA,sha256=KoCww2GbQcklh1j_u87ta2zidbkSehE5ikWEbbXn2nE,6949
14
- tengwar-0.3.1.dist-info/WHEEL,sha256=wUyA8OaulRlbfwMtmQsvNngGrxQHAvkKcvRmdizlJi0,92
15
- tengwar-0.3.1.dist-info/entry_points.txt,sha256=W_Zolo2TLJBIDkgAkV7yWzQWKwicET_J9gs4crmrfI4,46
16
- tengwar-0.3.1.dist-info/top_level.txt,sha256=VyO8Esj_l1yx0c52WUt_KUheaLbXOv2O2kGPZ1eG38k,8
17
- tengwar-0.3.1.dist-info/RECORD,,