mapres 3.dev21__tar.gz → 3.dev23__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 (24) hide show
  1. {mapres-3.dev21/src/mapres.egg-info → mapres-3.dev23}/PKG-INFO +1 -1
  2. {mapres-3.dev21 → mapres-3.dev23}/pyproject.toml +1 -1
  3. {mapres-3.dev21 → mapres-3.dev23}/src/mapres/parser.py +21 -34
  4. mapres-3.dev23/src/mapres/tokenizer.py +248 -0
  5. {mapres-3.dev21 → mapres-3.dev23/src/mapres.egg-info}/PKG-INFO +1 -1
  6. mapres-3.dev21/src/mapres/tokenizer.py +0 -232
  7. {mapres-3.dev21 → mapres-3.dev23}/LICENSE +0 -0
  8. {mapres-3.dev21 → mapres-3.dev23}/README.md +0 -0
  9. {mapres-3.dev21 → mapres-3.dev23}/setup.cfg +0 -0
  10. {mapres-3.dev21 → mapres-3.dev23}/src/mapres/__init__.py +0 -0
  11. {mapres-3.dev21 → mapres-3.dev23}/src/mapres/ast.py +0 -0
  12. {mapres-3.dev21 → mapres-3.dev23}/src/mapres/cache.py +0 -0
  13. {mapres-3.dev21 → mapres-3.dev23}/src/mapres/datamap.py +0 -0
  14. {mapres-3.dev21 → mapres-3.dev23}/src/mapres/evaluator.py +0 -0
  15. {mapres-3.dev21 → mapres-3.dev23}/src/mapres/exceptions.py +0 -0
  16. {mapres-3.dev21 → mapres-3.dev23}/src/mapres/layers.py +0 -0
  17. {mapres-3.dev21 → mapres-3.dev23}/src/mapres/maps/__init__.py +0 -0
  18. {mapres-3.dev21 → mapres-3.dev23}/src/mapres/maps/color.py +0 -0
  19. {mapres-3.dev21 → mapres-3.dev23}/src/mapres/maps/time.py +0 -0
  20. {mapres-3.dev21 → mapres-3.dev23}/src/mapres/resolver.py +0 -0
  21. {mapres-3.dev21 → mapres-3.dev23}/src/mapres.egg-info/SOURCES.txt +0 -0
  22. {mapres-3.dev21 → mapres-3.dev23}/src/mapres.egg-info/dependency_links.txt +0 -0
  23. {mapres-3.dev21 → mapres-3.dev23}/src/mapres.egg-info/requires.txt +0 -0
  24. {mapres-3.dev21 → mapres-3.dev23}/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.dev21
3
+ Version: 3.dev23
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.21"
10
+ version = "3-dev.23"
11
11
  description = "A powerfull mapping utility"
12
12
  readme = "README.md"
13
13
  requires-python = ">=3.9"
@@ -22,11 +22,10 @@ class Parser:
22
22
  def expect(self, type_: TokenType) -> Token:
23
23
  tok = self.peek()
24
24
  if tok is None or tok.type != type_:
25
- raise ParserError(f"Expected {type_}, got {tok}")
25
+ raise ParserError(f'Expected {type_}, got {tok}')
26
26
  self.advance()
27
27
  return tok
28
28
 
29
- # top-level template parse
30
29
  def parse(self) -> TemplateNode:
31
30
  children: list[Node] = []
32
31
  while self.peek() is not None:
@@ -38,88 +37,76 @@ class Parser:
38
37
  children.append(self.parse_token())
39
38
  return TemplateNode(children)
40
39
 
41
- # nested template parse (for IDENT(...))
42
40
  def parse_until(self, stop_types: tuple[TokenType, ...]) -> TemplateNode:
43
41
  children: list[Node] = []
44
42
  while True:
45
43
  tok = self.peek()
46
44
  if tok is None or tok.type in stop_types:
47
45
  break
48
-
49
46
  if tok.type is TokenType.TEXT:
50
47
  children.append(TextNode(tok.value))
51
48
  self.advance()
52
49
  else:
53
50
  children.append(self.parse_token())
54
-
55
51
  return TemplateNode(children)
56
52
 
57
- # dispatch by opening delimiter
58
53
  def parse_token(self) -> Node:
59
54
  tok = self.peek()
60
55
 
61
56
  if tok.type is TokenType.COLON_OPEN:
62
- return self.parse_colon_token()
57
+ return self.parse_colon()
63
58
 
64
59
  if tok.type is TokenType.BRACE_OPEN:
65
- return self.parse_brace_token()
60
+ return self.parse_brace()
66
61
 
67
62
  if tok.type is TokenType.DOLLAR_OPEN:
68
- return self.parse_dollar_token()
63
+ return self.parse_dollar()
69
64
 
70
65
  if tok.type is TokenType.ANGLE_OPEN:
71
- return self.parse_angle_token()
66
+ return self.parse_angle()
72
67
 
73
68
  if tok.type is TokenType.PIPE_OPEN:
74
- return self.parse_pipe_token()
69
+ return self.parse_pipe()
75
70
 
76
71
  if tok.type is TokenType.PERCENT_OPEN:
77
- return self.parse_percent_token()
72
+ return self.parse_percent()
78
73
 
79
- raise ParserError(f"Unexpected token {tok}")
74
+ raise ParserError(f'Unexpected token {tok}')
80
75
 
81
- # core pattern: IDENT or IDENT(arg)
82
76
  def _parse_ident_or_call(self, closing_type: TokenType, syntax_name: str) -> Node:
83
77
  ident_tok = self.expect(TokenType.IDENT)
84
78
  name = ident_tok.value
85
79
 
86
- # IDENT(arg)
87
80
  if self.peek() and self.peek().type is TokenType.LPAREN:
88
- self.advance() # consume '('
89
-
90
- # parse only until RPAREN
81
+ self.advance()
91
82
  arg = self.parse_until((TokenType.RPAREN,))
92
-
93
83
  self.expect(TokenType.RPAREN)
94
84
  self.expect(closing_type)
95
85
  return CallNode(name=name, arg=arg, syntax=syntax_name)
96
86
 
97
- # IDENT
98
87
  self.expect(closing_type)
99
88
  return IdentNode(name=name, syntax=syntax_name)
100
89
 
101
- # --- syntax-bound token handlers ---
102
-
103
- def parse_colon_token(self) -> Node:
90
+ def parse_colon(self) -> Node:
104
91
  self.expect(TokenType.COLON_OPEN)
105
- return self._parse_ident_or_call(TokenType.COLON_CLOSE, "colons")
92
+ return self._parse_ident_or_call(TokenType.COLON_CLOSE, 'colons')
106
93
 
107
- def parse_brace_token(self) -> Node:
94
+ def parse_brace(self) -> Node:
108
95
  self.expect(TokenType.BRACE_OPEN)
109
- return self._parse_ident_or_call(TokenType.BRACE_CLOSE, "braces")
96
+ return self._parse_ident_or_call(TokenType.BRACE_CLOSE, 'braces')
110
97
 
111
- def parse_dollar_token(self) -> Node:
98
+ def parse_dollar(self) -> Node:
112
99
  self.expect(TokenType.DOLLAR_OPEN)
113
- return self._parse_ident_or_call(TokenType.DOLLAR_CLOSE, "dollars")
100
+ return self._parse_ident_or_call(TokenType.DOLLAR_CLOSE, 'dollars')
114
101
 
115
- def parse_angle_token(self) -> Node:
102
+ def parse_angle(self) -> Node:
116
103
  self.expect(TokenType.ANGLE_OPEN)
117
- return self._parse_ident_or_call(TokenType.ANGLE_CLOSE, "angles")
104
+ return self._parse_ident_or_call(TokenType.ANGLE_CLOSE, 'angles')
118
105
 
119
- def parse_pipe_token(self) -> Node:
106
+ def parse_pipe(self) -> Node:
120
107
  self.expect(TokenType.PIPE_OPEN)
121
- return self._parse_ident_or_call(TokenType.PIPE_CLOSE, "pipes")
108
+ return self._parse_ident_or_call(TokenType.PIPE_CLOSE, 'pipes')
122
109
 
123
- def parse_percent_token(self) -> Node:
110
+ def parse_percent(self) -> Node:
124
111
  self.expect(TokenType.PERCENT_OPEN)
125
- return self._parse_ident_or_call(TokenType.PERCENT_CLOSE, "percents")
112
+ return self._parse_ident_or_call(TokenType.PERCENT_CLOSE, 'percents')
@@ -0,0 +1,248 @@
1
+ from enum import Enum, auto
2
+
3
+
4
+ class TokenType(Enum):
5
+ TEXT = auto()
6
+ IDENT = auto()
7
+ COLON_OPEN = auto()
8
+ COLON_CLOSE = auto()
9
+ BRACE_OPEN = auto()
10
+ BRACE_CLOSE = auto()
11
+ DOLLAR_OPEN = auto()
12
+ DOLLAR_CLOSE = auto()
13
+ ANGLE_OPEN = auto()
14
+ ANGLE_CLOSE = auto()
15
+ PIPE_OPEN = auto()
16
+ PIPE_CLOSE = auto()
17
+ PERCENT_OPEN = auto()
18
+ PERCENT_CLOSE = auto()
19
+ LPAREN = auto()
20
+ RPAREN = auto()
21
+
22
+
23
+ class Token:
24
+ def __init__(self, type_, value=None, pos=0):
25
+ self.type = type_
26
+ self.value = value
27
+ self.pos = pos
28
+
29
+ def __repr__(self):
30
+ if self.value is not None:
31
+ return f'Token({self.type}, {self.value!r}, pos={self.pos})'
32
+ return f'Token({self.type}, pos={self.pos})'
33
+
34
+
35
+ class Tokenizer:
36
+ def __init__(self, text: str):
37
+ self.text = text
38
+ self.i = 0
39
+ self.n = len(text)
40
+ self.tokens: list[Token] = []
41
+
42
+ def peek(self, k: int = 0) -> str:
43
+ idx = self.i + k
44
+ if idx >= self.n:
45
+ return ''
46
+ return self.text[idx]
47
+
48
+ def advance(self, k: int = 1) -> None:
49
+ self.i += k
50
+
51
+ def match(self, s: str) -> bool:
52
+ return self.text.startswith(s, self.i)
53
+
54
+ def emit(self, type_, value=None) -> None:
55
+ self.tokens.append(Token(type_, value, self.i))
56
+
57
+ def tokenize(self) -> list[Token]:
58
+ buf: list[str] = []
59
+
60
+ def flush_text():
61
+ if buf:
62
+ self.emit(TokenType.TEXT, ''.join(buf))
63
+ buf.clear()
64
+
65
+ while self.i < self.n:
66
+ ch = self.peek()
67
+
68
+ # escapes
69
+ if self.match(r'\:'):
70
+ buf.append(':'); self.advance(2); continue
71
+ if self.match(r'\<'):
72
+ buf.append('<'); self.advance(2); continue
73
+ if self.match(r'\>'):
74
+ buf.append('>'); self.advance(2); continue
75
+ if self.match(r'\%'):
76
+ buf.append('%'); self.advance(2); continue
77
+ if self.match(r'\$'):
78
+ buf.append('$'); self.advance(2); continue
79
+ if self.match(r'\{'):
80
+ buf.append('{'); self.advance(2); continue
81
+ if self.match(r'\}'):
82
+ buf.append('}'); self.advance(2); continue
83
+ if self.match(r'\|'):
84
+ buf.append('|'); self.advance(2); continue
85
+ if self.match(r'\('):
86
+ buf.append('('); self.advance(2); continue
87
+ if self.match(r'\)'):
88
+ buf.append(')'); self.advance(2); continue
89
+
90
+ # --- {{IDENT}} ---
91
+ if self.match('{{'):
92
+ flush_text()
93
+ start = self.i
94
+ self.advance(2)
95
+ ident = self._read_ident()
96
+ if ident is not None and self.match('}}'):
97
+ self.emit(TokenType.BRACE_OPEN)
98
+ self.emit(TokenType.IDENT, ident)
99
+ self.advance(2)
100
+ self.emit(TokenType.BRACE_CLOSE)
101
+ continue
102
+ self.i = start
103
+ buf.append(self.peek())
104
+ self.advance()
105
+ continue
106
+
107
+ # --- ${IDENT} ---
108
+ if self.match('${'):
109
+ flush_text()
110
+ start = self.i
111
+ self.advance(2)
112
+ ident = self._read_ident()
113
+ if ident is not None and self.peek() == '}':
114
+ self.emit(TokenType.DOLLAR_OPEN)
115
+ self.emit(TokenType.IDENT, ident)
116
+ self.advance()
117
+ self.emit(TokenType.DOLLAR_CLOSE)
118
+ continue
119
+ self.i = start
120
+ buf.append(self.peek())
121
+ self.advance()
122
+ continue
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
+
141
+ # --- <IDENT> ---
142
+ if ch == '<':
143
+ flush_text()
144
+ start = self.i
145
+ self.advance()
146
+ ident = self._read_ident()
147
+ if ident is not None and self.peek() == '>':
148
+ self.emit(TokenType.ANGLE_OPEN)
149
+ self.emit(TokenType.IDENT, ident)
150
+ self.advance()
151
+ self.emit(TokenType.ANGLE_CLOSE)
152
+ continue
153
+ self.i = start
154
+ buf.append(self.peek())
155
+ self.advance()
156
+ continue
157
+
158
+ # --- |IDENT| ---
159
+ if ch == '|':
160
+ flush_text()
161
+ start = self.i
162
+ self.advance()
163
+ ident = self._read_ident()
164
+ if ident is not None and self.peek() == '|':
165
+ self.emit(TokenType.PIPE_OPEN)
166
+ self.emit(TokenType.IDENT, ident)
167
+ self.advance()
168
+ self.emit(TokenType.PIPE_CLOSE)
169
+ continue
170
+ self.i = start
171
+ buf.append(self.peek())
172
+ self.advance()
173
+ continue
174
+
175
+ # --- %IDENT% ---
176
+ if ch == '%':
177
+ flush_text()
178
+ start = self.i
179
+ self.advance()
180
+ ident = self._read_ident()
181
+ if ident is not None and self.peek() == '%':
182
+ self.emit(TokenType.PERCENT_OPEN)
183
+ self.emit(TokenType.IDENT, ident)
184
+ self.advance()
185
+ self.emit(TokenType.PERCENT_CLOSE)
186
+ continue
187
+ self.i = start
188
+ buf.append(self.peek())
189
+ self.advance()
190
+ continue
191
+
192
+ # --- :IDENT: ---
193
+ if ch == ':':
194
+ flush_text()
195
+ start = self.i
196
+ self.advance()
197
+ ident = self._read_ident()
198
+ if ident is not None and self.peek() == ':':
199
+ self.emit(TokenType.COLON_OPEN)
200
+ self.emit(TokenType.IDENT, ident)
201
+ self.advance()
202
+ self.emit(TokenType.COLON_CLOSE)
203
+ continue
204
+ self.i = start
205
+ buf.append(self.peek())
206
+ self.advance()
207
+ continue
208
+
209
+ # --- parens ---
210
+ if ch == '(':
211
+ flush_text()
212
+ self.emit(TokenType.LPAREN)
213
+ self.advance()
214
+ continue
215
+
216
+ if ch == ')':
217
+ flush_text()
218
+ self.emit(TokenType.RPAREN)
219
+ self.advance()
220
+ continue
221
+
222
+ # fallback TEXT
223
+ buf.append(ch)
224
+ self.advance()
225
+
226
+ flush_text()
227
+ return self.tokens
228
+
229
+ def _read_ident(self) -> str | None:
230
+ start = self.i
231
+ ch = self.peek()
232
+ if not ch or not ch.isalnum():
233
+ return None
234
+
235
+ self.advance()
236
+ while True:
237
+ nxt = self.peek()
238
+ if not nxt:
239
+ break
240
+ if nxt.isalnum() or nxt in '._':
241
+ self.advance()
242
+ else:
243
+ break
244
+
245
+ ident = self.text[start:self.i]
246
+ if ident.startswith('_') or ident.endswith('_') or '-' in ident:
247
+ return None
248
+ return ident
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: mapres
3
- Version: 3.dev21
3
+ Version: 3.dev23
4
4
  Summary: A powerfull mapping utility
5
5
  Author: iFamished
6
6
  License: MIT
@@ -1,232 +0,0 @@
1
- from enum import Enum, auto
2
-
3
-
4
- class TokenType(Enum):
5
- TEXT = auto()
6
- IDENT = auto()
7
- COLON_OPEN = auto()
8
- COLON_CLOSE = auto()
9
- BRACE_OPEN = auto()
10
- BRACE_CLOSE = auto()
11
- DOLLAR_OPEN = auto()
12
- DOLLAR_CLOSE = auto()
13
- ANGLE_OPEN = auto()
14
- ANGLE_CLOSE = auto()
15
- PIPE_OPEN = auto()
16
- PIPE_CLOSE = auto()
17
- PERCENT_OPEN = auto()
18
- PERCENT_CLOSE = auto()
19
- LPAREN = auto()
20
- RPAREN = auto()
21
-
22
-
23
- class Token:
24
- def __init__(self, type_, value=None, pos=0):
25
- self.type = type_
26
- self.value = value
27
- self.pos = pos
28
-
29
- def __repr__(self):
30
- if self.value is not None:
31
- return f'Token({self.type}, {self.value!r}, pos={self.pos})'
32
- return f'Token({self.type}, pos={self.pos})'
33
-
34
-
35
- class Tokenizer:
36
- def __init__(self, text):
37
- self.text = text
38
- self.i = 0
39
- self.n = len(text)
40
- self.tokens = []
41
-
42
- # toggle states
43
- self.in_pipe = False
44
- self.in_percent = False
45
- self.in_colon = False
46
-
47
- # mixed states
48
- self.in_dollar = False
49
-
50
- def peek(self, k=0):
51
- idx = self.i + k
52
- if idx >= self.n:
53
- return ''
54
- return self.text[idx]
55
-
56
- def advance(self, k=1):
57
- self.i += k
58
-
59
- def match(self, s):
60
- return self.text.startswith(s, self.i)
61
-
62
- def emit(self, type_, value=None):
63
- self.tokens.append(Token(type_, value, self.i))
64
-
65
- def tokenize(self):
66
- buf = []
67
-
68
- def flush_text():
69
- if buf:
70
- self.emit(TokenType.TEXT, ''.join(buf))
71
- buf.clear()
72
-
73
- while self.i < self.n:
74
- ch = self.peek()
75
-
76
- # escapes
77
- if self.match(r'\:'):
78
- buf.append(':'); self.advance(2); continue
79
- if self.match(r'\<'):
80
- buf.append('<'); self.advance(2); continue
81
- if self.match(r'\>'):
82
- buf.append('>'); self.advance(2); continue
83
- if self.match(r'\%'):
84
- buf.append('%'); self.advance(2); continue
85
- if self.match(r'\$'):
86
- buf.append('$'); self.advance(2); continue
87
- if self.match(r'\{'):
88
- buf.append('{'); self.advance(2); continue
89
- if self.match(r'\}'):
90
- buf.append('}'); self.advance(2); continue
91
- if self.match(r'\|'):
92
- buf.append('|'); self.advance(2); continue
93
- if self.match(r'\('):
94
- buf.append('('); self.advance(2); continue
95
- if self.match(r'\)'):
96
- buf.append(')'); self.advance(2); continue
97
-
98
- # --- paired delimiters ---
99
-
100
- # braces {{ }}
101
- if self.match('{{'):
102
- flush_text()
103
- self.emit(TokenType.BRACE_OPEN)
104
- self.advance(2)
105
- continue
106
-
107
- if self.match('}}'):
108
- flush_text()
109
- self.emit(TokenType.BRACE_CLOSE)
110
- self.advance(2)
111
- continue
112
-
113
- # angles < >
114
- if self.match('<'):
115
- flush_text()
116
- self.emit(TokenType.ANGLE_OPEN)
117
- self.advance()
118
- continue
119
-
120
- if self.match('>'):
121
- flush_text()
122
- self.emit(TokenType.ANGLE_CLOSE)
123
- self.advance()
124
- continue
125
-
126
- # --- mixed delimiters (dollars) ---
127
-
128
- if self.match('${'):
129
- flush_text()
130
- self.emit(TokenType.DOLLAR_OPEN)
131
- self.in_dollar = True
132
- self.advance(2)
133
- continue
134
-
135
- if ch == '}':
136
- flush_text()
137
- if self.in_dollar:
138
- self.emit(TokenType.DOLLAR_CLOSE)
139
- self.in_dollar = False
140
- else:
141
- buf.append('}')
142
- self.advance()
143
- continue
144
-
145
- # --- toggle delimiters ---
146
-
147
- # pipes |...|
148
- if self.match('|'):
149
- flush_text()
150
- if not self.in_pipe:
151
- self.emit(TokenType.PIPE_OPEN)
152
- self.in_pipe = True
153
- else:
154
- self.emit(TokenType.PIPE_CLOSE)
155
- self.in_pipe = False
156
- self.advance()
157
- continue
158
-
159
- # percents %...%
160
- if self.match('%'):
161
- flush_text()
162
- if not self.in_percent:
163
- self.emit(TokenType.PERCENT_OPEN)
164
- self.in_percent = True
165
- else:
166
- self.emit(TokenType.PERCENT_CLOSE)
167
- self.in_percent = False
168
- self.advance()
169
- continue
170
-
171
- # colons :...:
172
- if self.match(':'):
173
- flush_text()
174
- if not self.in_colon:
175
- self.emit(TokenType.COLON_OPEN)
176
- self.in_colon = True
177
- else:
178
- self.emit(TokenType.COLON_CLOSE)
179
- self.in_colon = False
180
- self.advance()
181
- continue
182
-
183
- # --- parens ---
184
-
185
- if ch == '(':
186
- flush_text()
187
- self.emit(TokenType.LPAREN)
188
- self.advance()
189
- continue
190
-
191
- if ch == ')':
192
- flush_text()
193
- self.emit(TokenType.RPAREN)
194
- self.advance()
195
- continue
196
-
197
- # --- IDENT (your rules) ---
198
-
199
- if ch.isalnum():
200
- flush_text()
201
- start = self.i
202
-
203
- # first char: [a-zA-Z0-9]
204
- self.advance()
205
-
206
- # middle chars: [a-zA-Z0-9._]*
207
- while True:
208
- nxt = self.peek()
209
- if not nxt:
210
- break
211
- if nxt.isalnum() or nxt in '._':
212
- self.advance()
213
- else:
214
- break
215
-
216
- ident = self.text[start:self.i]
217
-
218
- # enforce: no leading/trailing '_', no '-'
219
- if ident.startswith('_') or ident.endswith('_') or '-' in ident:
220
- # treat as TEXT instead
221
- buf.append(ident)
222
- else:
223
- self.emit(TokenType.IDENT, ident)
224
- continue
225
-
226
- # --- fallback: TEXT ---
227
-
228
- buf.append(ch)
229
- self.advance()
230
-
231
- flush_text()
232
- return self.tokens
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes