mapres 3.dev6__py3-none-any.whl → 3.dev8__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/parser.py CHANGED
@@ -12,22 +12,23 @@ class Parser:
12
12
  self.i = 0
13
13
  self.n = len(tokens)
14
14
 
15
- def peek(self, k=0) -> Token | None:
15
+ def peek(self, k: int = 0) -> Token | None:
16
16
  idx = self.i + k
17
17
  return self.tokens[idx] if idx < self.n else None
18
18
 
19
- def advance(self, k=1):
19
+ def advance(self, k: int = 1) -> None:
20
20
  self.i += k
21
21
 
22
- def expect(self, type_: TokenType):
22
+ def expect(self, type_: TokenType) -> Token:
23
23
  tok = self.peek()
24
24
  if tok is None or tok.type != type_:
25
25
  raise ParserError(f"Expected {type_}, got {tok}")
26
26
  self.advance()
27
27
  return tok
28
28
 
29
+ # top-level template parse
29
30
  def parse(self) -> TemplateNode:
30
- children = []
31
+ children: list[Node] = []
31
32
  while self.peek() is not None:
32
33
  tok = self.peek()
33
34
  if tok.type is TokenType.TEXT:
@@ -37,6 +38,23 @@ class Parser:
37
38
  children.append(self.parse_token())
38
39
  return TemplateNode(children)
39
40
 
41
+ # nested template parse (for IDENT(...))
42
+ def parse_until(self, stop_types: tuple[TokenType, ...]) -> TemplateNode:
43
+ children: list[Node] = []
44
+ while True:
45
+ tok = self.peek()
46
+ if tok is None or tok.type in stop_types:
47
+ break
48
+
49
+ if tok.type is TokenType.TEXT:
50
+ children.append(TextNode(tok.value))
51
+ self.advance()
52
+ else:
53
+ children.append(self.parse_token())
54
+
55
+ return TemplateNode(children)
56
+
57
+ # dispatch by opening delimiter
40
58
  def parse_token(self) -> Node:
41
59
  tok = self.peek()
42
60
 
@@ -60,21 +78,23 @@ class Parser:
60
78
 
61
79
  raise ParserError(f"Unexpected token {tok}")
62
80
 
63
- # --- core pattern: IDENT or IDENT(arg) ---
64
-
65
- def _parse_ident_or_call(self, closing_type, syntax_name: str) -> Node:
81
+ # core pattern: IDENT or IDENT(arg)
82
+ def _parse_ident_or_call(self, closing_type: TokenType, syntax_name: str) -> Node:
66
83
  ident_tok = self.expect(TokenType.IDENT)
67
84
  name = ident_tok.value
68
85
 
69
- # single-argument nested form: IDENT LPAREN Template RPAREN
86
+ # IDENT(arg)
70
87
  if self.peek() and self.peek().type is TokenType.LPAREN:
71
88
  self.advance() # consume '('
72
- arg = self.parse() # nested Template
89
+
90
+ # parse only until RPAREN
91
+ arg = self.parse_until((TokenType.RPAREN,))
92
+
73
93
  self.expect(TokenType.RPAREN)
74
94
  self.expect(closing_type)
75
95
  return CallNode(name=name, arg=arg, syntax=syntax_name)
76
96
 
77
- # simple identifier: IDENT
97
+ # IDENT
78
98
  self.expect(closing_type)
79
99
  return IdentNode(name=name, syntax=syntax_name)
80
100
 
mapres/tokenizer.py CHANGED
@@ -46,6 +46,11 @@ class Tokenizer:
46
46
  self.n = len(text)
47
47
  self.tokens = []
48
48
 
49
+ # state for single-char paired delimiters
50
+ self.in_pipe = False
51
+ self.in_percent = False
52
+ self.in_colon = False
53
+
49
54
  def peek(self, k=0):
50
55
  idx = self.i + k
51
56
  if idx >= self.n:
@@ -72,9 +77,7 @@ class Tokenizer:
72
77
  while self.i < self.n:
73
78
  ch = self.peek()
74
79
 
75
- # ------------------------------------
76
- # ESCAPING: \X → literal X
77
- # ------------------------------------
80
+ # ESCAPES
78
81
  if self.match(r'\:'):
79
82
  buf.append(':'); self.advance(2); continue
80
83
  if self.match(r'\<'):
@@ -96,9 +99,7 @@ class Tokenizer:
96
99
  if self.match(r'\)'):
97
100
  buf.append(')'); self.advance(2); continue
98
101
 
99
- # ------------------------------------
100
102
  # DOUBLE BRACES {{value}}
101
- # ------------------------------------
102
103
  if self.match("{{"):
103
104
  flush_text()
104
105
  self.emit(TokenType.BRACE_OPEN)
@@ -111,9 +112,7 @@ class Tokenizer:
111
112
  self.advance(2)
112
113
  continue
113
114
 
114
- # ------------------------------------
115
115
  # DOLLARS ${value}
116
- # ------------------------------------
117
116
  if self.match("${"):
118
117
  flush_text()
119
118
  self.emit(TokenType.DOLLAR_OPEN)
@@ -126,9 +125,7 @@ class Tokenizer:
126
125
  self.advance()
127
126
  continue
128
127
 
129
- # ------------------------------------
130
128
  # ANGLES <value>
131
- # ------------------------------------
132
129
  if self.match("<"):
133
130
  flush_text()
134
131
  self.emit(TokenType.ANGLE_OPEN)
@@ -141,48 +138,43 @@ class Tokenizer:
141
138
  self.advance()
142
139
  continue
143
140
 
144
- # ------------------------------------
145
141
  # PIPES |value|
146
- # ------------------------------------
147
142
  if self.match("|"):
148
143
  flush_text()
149
- # explicit open/close detection:
150
- # |IDENT| → PIPE_OPEN IDENT PIPE_CLOSE
151
- # parser enforces structure
152
- if self.tokens and self.tokens[-1].type == TokenType.PIPE_OPEN:
153
- self.emit(TokenType.PIPE_CLOSE)
154
- else:
144
+ if not self.in_pipe:
155
145
  self.emit(TokenType.PIPE_OPEN)
146
+ self.in_pipe = True
147
+ else:
148
+ self.emit(TokenType.PIPE_CLOSE)
149
+ self.in_pipe = False
156
150
  self.advance()
157
151
  continue
158
152
 
159
- # ------------------------------------
160
153
  # PERCENTS %value%
161
- # ------------------------------------
162
154
  if self.match("%"):
163
155
  flush_text()
164
- if self.tokens and self.tokens[-1].type == TokenType.PERCENT_OPEN:
165
- self.emit(TokenType.PERCENT_CLOSE)
166
- else:
156
+ if not self.in_percent:
167
157
  self.emit(TokenType.PERCENT_OPEN)
158
+ self.in_percent = True
159
+ else:
160
+ self.emit(TokenType.PERCENT_CLOSE)
161
+ self.in_percent = False
168
162
  self.advance()
169
163
  continue
170
164
 
171
- # ------------------------------------
172
165
  # COLONS :value:
173
- # ------------------------------------
174
166
  if self.match(":"):
175
167
  flush_text()
176
- if self.tokens and self.tokens[-1].type == TokenType.COLON_OPEN:
177
- self.emit(TokenType.COLON_CLOSE)
178
- else:
168
+ if not self.in_colon:
179
169
  self.emit(TokenType.COLON_OPEN)
170
+ self.in_colon = True
171
+ else:
172
+ self.emit(TokenType.COLON_CLOSE)
173
+ self.in_colon = False
180
174
  self.advance()
181
175
  continue
182
176
 
183
- # ------------------------------------
184
177
  # PARENTHESES
185
- # ------------------------------------
186
178
  if ch == "(":
187
179
  flush_text()
188
180
  self.emit(TokenType.LPAREN)
@@ -195,9 +187,7 @@ class Tokenizer:
195
187
  self.advance()
196
188
  continue
197
189
 
198
- # ------------------------------------
199
190
  # IDENTIFIERS (with dots)
200
- # ------------------------------------
201
191
  if ch.isalpha():
202
192
  flush_text()
203
193
  start = self.i
@@ -207,9 +197,7 @@ class Tokenizer:
207
197
  self.emit(TokenType.IDENT, ident)
208
198
  continue
209
199
 
210
- # ------------------------------------
211
200
  # DEFAULT: TEXT
212
- # ------------------------------------
213
201
  buf.append(ch)
214
202
  self.advance()
215
203
 
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: mapres
3
- Version: 3.dev6
3
+ Version: 3.dev8
4
4
  Summary: A powerfull mapping utility
5
5
  Author: iFamished
6
6
  License: MIT
@@ -5,14 +5,14 @@ mapres/datamap.py,sha256=HAflZFD9eh2VRkR9_2aDtXxY3r_A5ZUnpxNJ_VqmFBE,3837
5
5
  mapres/evaluator.py,sha256=-MsLxUlmYIOz5IOR5KT8IclJXtABGukLoQVmqkOTqTA,3780
6
6
  mapres/exceptions.py,sha256=jirHKK5yCffSCWWkgZY_gTSIOaFCmXOe5NJJf60HeeQ,130
7
7
  mapres/layers.py,sha256=sFc1eUOBg2BoB2cBXIleq8RMYcg5GZpUoCnGh-uKN6U,1380
8
- mapres/parser.py,sha256=xCnR290-A_XI8Yr8u1V-K_Of8exhGFOz5aT6gjAeBGA,3405
8
+ mapres/parser.py,sha256=8XLCzYosvh81bN-Jddc1AM4w0X7bsHnBzmA8sq5_72w,4018
9
9
  mapres/resolver.py,sha256=LOAnuNc1RW97eBXughkEPK90MntMSYa7yC8s1EJPVvA,3134
10
- mapres/tokenizer.py,sha256=vQDy9Fw1rIDLcqs3jlcbZ0VI6mcK0U5h3SJ_jqpH45g,6627
10
+ mapres/tokenizer.py,sha256=zw1jhnfypak1bLSTlyo9Xj4UoOF9DJ3y1qqu2OzudiI,5702
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.dev6.dist-info/licenses/LICENSE,sha256=OXLcl0T2SZ8Pmy2_dmlvKuetivmyPd5m1q-Gyd-zaYY,35149
15
- mapres-3.dev6.dist-info/METADATA,sha256=GnbMjkS5eTneybi5Uyhw_PB8svvp2qg7LjBP3yEipVw,1475
16
- mapres-3.dev6.dist-info/WHEEL,sha256=K260EYznzXsJYBQGqmI8VTxEdiZYNvDZwW9cBh9-_MA,91
17
- mapres-3.dev6.dist-info/top_level.txt,sha256=5LMVQqJdtyjxfzv7wJBOZ-360m0Yc79w_-Y7s3n6cTw,7
18
- mapres-3.dev6.dist-info/RECORD,,
14
+ mapres-3.dev8.dist-info/licenses/LICENSE,sha256=OXLcl0T2SZ8Pmy2_dmlvKuetivmyPd5m1q-Gyd-zaYY,35149
15
+ mapres-3.dev8.dist-info/METADATA,sha256=394wGpH8u6Ty7yMaxlW5HfTfky8_9W-wQ2NNNIRZ-dM,1475
16
+ mapres-3.dev8.dist-info/WHEEL,sha256=K260EYznzXsJYBQGqmI8VTxEdiZYNvDZwW9cBh9-_MA,91
17
+ mapres-3.dev8.dist-info/top_level.txt,sha256=5LMVQqJdtyjxfzv7wJBOZ-360m0Yc79w_-Y7s3n6cTw,7
18
+ mapres-3.dev8.dist-info/RECORD,,