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 +30 -10
- mapres/tokenizer.py +21 -33
- {mapres-3.dev6.dist-info → mapres-3.dev8.dist-info}/METADATA +1 -1
- {mapres-3.dev6.dist-info → mapres-3.dev8.dist-info}/RECORD +7 -7
- {mapres-3.dev6.dist-info → mapres-3.dev8.dist-info}/WHEEL +0 -0
- {mapres-3.dev6.dist-info → mapres-3.dev8.dist-info}/licenses/LICENSE +0 -0
- {mapres-3.dev6.dist-info → mapres-3.dev8.dist-info}/top_level.txt +0 -0
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
|
-
#
|
|
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
|
-
#
|
|
86
|
+
# IDENT(arg)
|
|
70
87
|
if self.peek() and self.peek().type is TokenType.LPAREN:
|
|
71
88
|
self.advance() # consume '('
|
|
72
|
-
|
|
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
|
-
#
|
|
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
|
-
|
|
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
|
|
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
|
|
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
|
|
|
@@ -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=
|
|
8
|
+
mapres/parser.py,sha256=8XLCzYosvh81bN-Jddc1AM4w0X7bsHnBzmA8sq5_72w,4018
|
|
9
9
|
mapres/resolver.py,sha256=LOAnuNc1RW97eBXughkEPK90MntMSYa7yC8s1EJPVvA,3134
|
|
10
|
-
mapres/tokenizer.py,sha256=
|
|
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.
|
|
15
|
-
mapres-3.
|
|
16
|
-
mapres-3.
|
|
17
|
-
mapres-3.
|
|
18
|
-
mapres-3.
|
|
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,,
|
|
File without changes
|
|
File without changes
|
|
File without changes
|