mapres 3.dev22__py3-none-any.whl → 3.dev24__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.
mapres/datamap.py CHANGED
@@ -36,6 +36,8 @@ class DataMap:
36
36
  __syntax__: str = None
37
37
  __mode__: str | None = None # 'dynamic', 'config', 'callable', or None
38
38
  __missing_key__: str = 'error' # 'error', 'silent', 'placeholder'
39
+ __recursive__: bool = False
40
+ __max_depth__: int = 10
39
41
 
40
42
  def as_map(self):
41
43
  '''
@@ -92,11 +94,13 @@ class DataMap:
92
94
  return out
93
95
 
94
96
 
95
- def datamap(_cls=None, *, syntax=None, mode=None, missing_key=None):
97
+ def datamap(_cls=None, *, syntax=None, mode=None, missing_key=None, recursive=None, max_depth=None):
96
98
  def wrap(cls):
97
99
  cls.__syntax__ = syntax
98
100
  cls.__mode__ = mode
99
101
  cls.__missing_key__ = missing_key or 'error'
102
+ cls.__recursive__ = recursive or False
103
+ cls.__max_depth__ = max_depth or 10
100
104
 
101
105
  namespace = dict(cls.__dict__)
102
106
  namespace['__dict__'] = {}
mapres/evaluator.py CHANGED
@@ -33,6 +33,13 @@ class Evaluator:
33
33
  return self._eval_call(node)
34
34
 
35
35
  raise EvaluationError(f'Unknown AST node: {node}')
36
+
37
+ # re-resolve
38
+ def _re_resolve(self, text: str) -> str:
39
+ tokens = Tokenizer(text).tokenize()
40
+ ast = Parser(tokens).parse()
41
+ return self.evaluate(ast)
42
+
36
43
 
37
44
  # template
38
45
  def _eval_template(self, node: TemplateNode):
@@ -40,6 +47,42 @@ class Evaluator:
40
47
  for child in node.children:
41
48
  parts.append(self._eval(child))
42
49
  out = ''.join(parts)
50
+
51
+ # ---------------------------------------
52
+ # PER-MAP RECURSION (syntax-scoped)
53
+ # ---------------------------------------
54
+ # Find all maps in the layerstack that have recursive=True
55
+ recursive_maps = [
56
+ m for m in self.layerstack.all_maps()
57
+ if getattr(m, '__recursive__', False) is True
58
+ ]
59
+
60
+ # If no maps are recursive, return the first-pass output
61
+ if not recursive_maps:
62
+ return out
63
+
64
+ # Determine max recursion depth across all recursive maps
65
+ max_depth = max(getattr(m, '__max_depth__', 10) for m in recursive_maps)
66
+
67
+ seen = set()
68
+ depth = 0
69
+
70
+ while depth < max_depth:
71
+ # Re-tokenize and re-evaluate the ENTIRE output string
72
+ new_out = self._re_resolve(out)
73
+
74
+ # If stable, stop recursion
75
+ if new_out == out:
76
+ break
77
+
78
+ # Cycle detection
79
+ if new_out in seen:
80
+ raise EvaluationError('Cycle detected in recursive map resolution')
81
+
82
+ seen.add(new_out)
83
+ out = new_out
84
+ depth += 1
85
+
43
86
  return out
44
87
 
45
88
  # identifier
mapres/tokenizer.py CHANGED
@@ -121,6 +121,23 @@ class Tokenizer:
121
121
  self.advance()
122
122
  continue
123
123
 
124
+ # --- $(IDENT) ---
125
+ if self.match('$('):
126
+ flush_text()
127
+ start = self.i
128
+ self.advance(2)
129
+ ident = self._read_ident()
130
+ if ident is not None and self.peek() == ')':
131
+ self.emit(TokenType.DOLLAR_OPEN)
132
+ self.emit(TokenType.IDENT, ident)
133
+ self.advance()
134
+ self.emit(TokenType.DOLLAR_CLOSE)
135
+ continue
136
+ self.i = start
137
+ buf.append(self.peek())
138
+ self.advance()
139
+ continue
140
+
124
141
  # --- <IDENT> ---
125
142
  if ch == '<':
126
143
  flush_text()
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: mapres
3
- Version: 3.dev22
3
+ Version: 3.dev24
4
4
  Summary: A powerfull mapping utility
5
5
  Author: iFamished
6
6
  License: MIT
@@ -1,18 +1,18 @@
1
1
  mapres/__init__.py,sha256=t23ofM-wzpPByYi1rEQonxyU1yyza4ZzwwHDZUa5QqA,1010
2
2
  mapres/ast.py,sha256=6PcMkwtNHYD8xEkdyzDgn_mRTj1ZaWSyuHZK3BtXiuo,427
3
3
  mapres/cache.py,sha256=hbvsoc6Qw3RhWAEfOOpKHtC7i9EomoUgWzyd4dnH71w,333
4
- mapres/datamap.py,sha256=R_5G_mE2OZpZ9YVL4tsNXAGS_SkQ6LKlx6Bz2Pr652Y,5021
5
- mapres/evaluator.py,sha256=KNZ9aygOClM0kgnOf3anigsupLF175EJ07z_17ubZzU,3441
4
+ mapres/datamap.py,sha256=dBYRYijqCBt41MGg95ZEw40C--0ZTnH0Foq-Vv9-jhA,5204
5
+ mapres/evaluator.py,sha256=MV5nyQJ0R40RX4CdXj-lXXKT6dEG_ocoGClM6kLs38U,4756
6
6
  mapres/exceptions.py,sha256=D2XKnrMkZDyUXQt2PmaKbj08FObWU00yXKGHwNpjvww,222
7
7
  mapres/layers.py,sha256=sFc1eUOBg2BoB2cBXIleq8RMYcg5GZpUoCnGh-uKN6U,1380
8
8
  mapres/parser.py,sha256=q3PgyvXJn9c-EJJYyibw7sHJ0Y9soirgB10OyTKaT9s,3657
9
9
  mapres/resolver.py,sha256=kQexTdBnPy70Azh_U6--hwUtnIJjoKcuaJ2KlBaG3Rg,3889
10
- mapres/tokenizer.py,sha256=0iBJBiqY4-_7jKUpY38HzLoZ2m_l2WJJvhBqcRUwo50,7182
10
+ mapres/tokenizer.py,sha256=O28ZTClzC8CkHlnjMHlyGsSLXwMRKIho-JZLF-JDxj0,7795
11
11
  mapres/maps/__init__.py,sha256=lIRRfem1Fw4iynuwUQ7BY5qrC4fbJKxqLivao2_Dtm4,239
12
12
  mapres/maps/color.py,sha256=noRTGFNo9xLl5YEhX0tttV6i_oDAiptXmRVnkr5EzwM,1348
13
13
  mapres/maps/time.py,sha256=TyncycYoIGVZWps32qWlFy2a2hTayvZWVHu9uh2nid8,2050
14
- mapres-3.dev22.dist-info/licenses/LICENSE,sha256=OXLcl0T2SZ8Pmy2_dmlvKuetivmyPd5m1q-Gyd-zaYY,35149
15
- mapres-3.dev22.dist-info/METADATA,sha256=3gas02EXpAh_Gh52KVRfuhJQ0IKhUQLiwYRGYd-IbFo,1476
16
- mapres-3.dev22.dist-info/WHEEL,sha256=K260EYznzXsJYBQGqmI8VTxEdiZYNvDZwW9cBh9-_MA,91
17
- mapres-3.dev22.dist-info/top_level.txt,sha256=5LMVQqJdtyjxfzv7wJBOZ-360m0Yc79w_-Y7s3n6cTw,7
18
- mapres-3.dev22.dist-info/RECORD,,
14
+ mapres-3.dev24.dist-info/licenses/LICENSE,sha256=OXLcl0T2SZ8Pmy2_dmlvKuetivmyPd5m1q-Gyd-zaYY,35149
15
+ mapres-3.dev24.dist-info/METADATA,sha256=3uX4LVE1YqRCOJP4ehkXZ4ng3VrFL4geQN0OVuYKAjc,1476
16
+ mapres-3.dev24.dist-info/WHEEL,sha256=K260EYznzXsJYBQGqmI8VTxEdiZYNvDZwW9cBh9-_MA,91
17
+ mapres-3.dev24.dist-info/top_level.txt,sha256=5LMVQqJdtyjxfzv7wJBOZ-360m0Yc79w_-Y7s3n6cTw,7
18
+ mapres-3.dev24.dist-info/RECORD,,