mapres 3.dev19__tar.gz → 3.dev20__tar.gz

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.
Files changed (23) hide show
  1. {mapres-3.dev19/src/mapres.egg-info → mapres-3.dev20}/PKG-INFO +1 -1
  2. {mapres-3.dev19 → mapres-3.dev20}/pyproject.toml +1 -1
  3. {mapres-3.dev19 → mapres-3.dev20}/src/mapres/datamap.py +2 -4
  4. {mapres-3.dev19 → mapres-3.dev20}/src/mapres/evaluator.py +87 -3
  5. {mapres-3.dev19 → mapres-3.dev20/src/mapres.egg-info}/PKG-INFO +1 -1
  6. {mapres-3.dev19 → mapres-3.dev20}/LICENSE +0 -0
  7. {mapres-3.dev19 → mapres-3.dev20}/README.md +0 -0
  8. {mapres-3.dev19 → mapres-3.dev20}/setup.cfg +0 -0
  9. {mapres-3.dev19 → mapres-3.dev20}/src/mapres/__init__.py +0 -0
  10. {mapres-3.dev19 → mapres-3.dev20}/src/mapres/ast.py +0 -0
  11. {mapres-3.dev19 → mapres-3.dev20}/src/mapres/cache.py +0 -0
  12. {mapres-3.dev19 → mapres-3.dev20}/src/mapres/exceptions.py +0 -0
  13. {mapres-3.dev19 → mapres-3.dev20}/src/mapres/layers.py +0 -0
  14. {mapres-3.dev19 → mapres-3.dev20}/src/mapres/maps/__init__.py +0 -0
  15. {mapres-3.dev19 → mapres-3.dev20}/src/mapres/maps/color.py +0 -0
  16. {mapres-3.dev19 → mapres-3.dev20}/src/mapres/maps/time.py +0 -0
  17. {mapres-3.dev19 → mapres-3.dev20}/src/mapres/parser.py +0 -0
  18. {mapres-3.dev19 → mapres-3.dev20}/src/mapres/resolver.py +0 -0
  19. {mapres-3.dev19 → mapres-3.dev20}/src/mapres/tokenizer.py +0 -0
  20. {mapres-3.dev19 → mapres-3.dev20}/src/mapres.egg-info/SOURCES.txt +0 -0
  21. {mapres-3.dev19 → mapres-3.dev20}/src/mapres.egg-info/dependency_links.txt +0 -0
  22. {mapres-3.dev19 → mapres-3.dev20}/src/mapres.egg-info/requires.txt +0 -0
  23. {mapres-3.dev19 → mapres-3.dev20}/src/mapres.egg-info/top_level.txt +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: mapres
3
- Version: 3.dev19
3
+ Version: 3.dev20
4
4
  Summary: A powerfull mapping utility
5
5
  Author: iFamished
6
6
  License: MIT
@@ -7,7 +7,7 @@ build-backend = "setuptools.build_meta"
7
7
 
8
8
  [project]
9
9
  name = "mapres"
10
- version = "3-dev.19"
10
+ version = "3-dev.20"
11
11
  description = "A powerfull mapping utility"
12
12
  readme = "README.md"
13
13
  requires-python = ">=3.9"
@@ -95,14 +95,12 @@ class DataMap:
95
95
  return out
96
96
 
97
97
 
98
- def datamap(_cls=None, *, syntax=None, mode=None, recursive=None,
99
- missing_key=None, ignore_delimiters=None):
98
+ def datamap(_cls=None, *, syntax=None, mode=None, recursive=None, missing_key=None, ignore_delimiters=None):
100
99
 
101
100
  def wrap(cls):
102
101
  cls.__syntax__ = syntax
103
102
  cls.__mode__ = mode
104
- cls.__recursive__ = recursive if recursive is not None else False
105
- # cls.__recursive__ = recursive
103
+ cls.__recursive__ = recursive
106
104
  cls.__missing_key__ = missing_key or 'error'
107
105
  cls.__ignore_delimiters__ = ignore_delimiters or False
108
106
 
@@ -41,13 +41,32 @@ class Evaluator:
41
41
  parts.append(self._eval(child))
42
42
  out = ''.join(parts)
43
43
 
44
- # recursion disabled for now (Mapres 2–style behavior)
44
+ # recursion over full template output
45
+ if self._has_recursive_maps():
46
+ seen = set()
47
+ depth = 0
48
+ max_depth = self._get_max_depth()
49
+
50
+ while depth < max_depth:
51
+ new_out = self._re_resolve(out)
52
+ if new_out == out:
53
+ break
54
+ if new_out in seen:
55
+ raise EvaluationError('Cycle detected in template recursion')
56
+ seen.add(new_out)
57
+ out = new_out
58
+ depth += 1
59
+
45
60
  return out
46
61
 
47
62
  # identifier
48
63
  def _eval_ident(self, node: IdentNode):
49
64
  name = node.name
50
65
 
66
+ # ignore_delimiters: treat token as literal for this syntax
67
+ if self._syntax_ignores_delimiters(node.syntax):
68
+ return self._literal_from_syntax(name, node.syntax)
69
+
51
70
  # cycle detection
52
71
  if name in self._seen:
53
72
  raise EvaluationError(f"Cycle detected in identifier '{name}'")
@@ -79,6 +98,11 @@ class Evaluator:
79
98
  def _eval_call(self, node: CallNode):
80
99
  outer = node.name
81
100
 
101
+ # ignore_delimiters: treat call token as literal
102
+ if self._syntax_ignores_delimiters(node.syntax):
103
+ arg_text = self._eval(node.arg)
104
+ return self._literal_from_syntax(outer, node.syntax, is_call=True, arg_text=arg_text)
105
+
82
106
  if outer in self._seen:
83
107
  raise EvaluationError(f"Cycle detected in call '{outer}'")
84
108
  self._seen.add(outer)
@@ -124,14 +148,74 @@ class Evaluator:
124
148
  cur = cur[p]
125
149
  return cur
126
150
 
127
- # recursion helpers now effectively disabled
128
151
  def _has_recursive_maps(self):
152
+ for m in self.layerstack.all_maps():
153
+ if getattr(m, '__recursive__', False) is True:
154
+ return True
129
155
  return False
130
156
 
131
157
  def _get_max_depth(self):
132
- return 0
158
+ depths = [
159
+ getattr(m, '__max_depth__', 10)
160
+ for m in self.layerstack.all_maps()
161
+ if getattr(m, '__recursive__', False) is True
162
+ ]
163
+ return max(depths) if depths else 0
133
164
 
134
165
  def _re_resolve(self, text: str) -> str:
135
166
  tokens = Tokenizer(text).tokenize()
136
167
  ast = Parser(tokens).parse()
137
168
  return self.evaluate(ast)
169
+
170
+ def _syntax_ignores_delimiters(self, syntax_name: str) -> bool:
171
+ for m in self.layerstack.all_maps():
172
+ if getattr(m, '__syntax__', None) == syntax_name:
173
+ if getattr(m, '__ignore_delimiters__', False):
174
+ return True
175
+ return False
176
+
177
+ def _literal_from_syntax(self, name: str, syntax_name: str, is_call: bool = False, arg_text: str | None = None) -> str:
178
+ if not is_call:
179
+ if syntax_name == 'colons':
180
+ return f':{name}:'
181
+ if syntax_name == 'braces':
182
+ return f'{{{{{name}}}}}'
183
+ if syntax_name == 'dollars':
184
+ return f'${{{name}}}'
185
+ if syntax_name == 'angles':
186
+ return f'<{name}>'
187
+ if syntax_name == 'pipes':
188
+ return f'|{name}|'
189
+ if syntax_name == 'percents':
190
+ return f'%{name}%'
191
+ if syntax_name == 'paren_dollars':
192
+ return f'$({name})'
193
+ if syntax_name == 'at_tags':
194
+ return f'@{name}@'
195
+ if syntax_name == 'hash_tags':
196
+ return f'#{name}#'
197
+ return name
198
+
199
+ # call literal: syntax-specific wrapping of name(arg_text)
200
+ arg = arg_text or ''
201
+ inner = f'{name}({arg})'
202
+
203
+ if syntax_name == 'colons':
204
+ return f':{inner}:'
205
+ if syntax_name == 'braces':
206
+ return f'{{{{{inner}}}}}'
207
+ if syntax_name == 'dollars':
208
+ return f'${{{inner}}}'
209
+ if syntax_name == 'angles':
210
+ return f'<{inner}>'
211
+ if syntax_name == 'pipes':
212
+ return f'|{inner}|'
213
+ if syntax_name == 'percents':
214
+ return f'%{inner}%'
215
+ if syntax_name == 'paren_dollars':
216
+ return f'$({inner})'
217
+ if syntax_name == 'at_tags':
218
+ return f'@{inner}@'
219
+ if syntax_name == 'hash_tags':
220
+ return f'#{inner}#'
221
+ return inner
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: mapres
3
- Version: 3.dev19
3
+ Version: 3.dev20
4
4
  Summary: A powerfull mapping utility
5
5
  Author: iFamished
6
6
  License: MIT
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes