9
9
10
10
P = TypeVar ("P" , bound = "Parser" )
11
11
N = TypeVar ("N" , bound = "Node" )
12
- def contextual (func : Callable [[P ], N | None ]) -> Callable [[P ], N | None ]:
12
+
13
+
14
+ def contextual (func : Callable [[P ], N | None ]) -> Callable [[P ], N | None ]:
13
15
# Decorator to wrap grammar methods.
14
16
# Resets position if `func` returns None.
15
- def contextual_wrapper (self : P ) -> N | None :
17
+ def contextual_wrapper (self : P ) -> N | None :
16
18
begin = self .getpos ()
17
19
res = func (self )
18
20
if res is None :
@@ -21,6 +23,7 @@ def contextual_wrapper(self: P) -> N|None:
21
23
end = self .getpos ()
22
24
res .context = Context (begin , end , self )
23
25
return res
26
+
24
27
return contextual_wrapper
25
28
26
29
@@ -35,7 +38,7 @@ def __repr__(self):
35
38
36
39
@dataclass
37
40
class Node :
38
- context : Context | None = field (init = False , default = None )
41
+ context : Context | None = field (init = False , default = None )
39
42
40
43
@property
41
44
def text (self ) -> str :
@@ -68,8 +71,14 @@ class CacheEffect(Node):
68
71
size : int
69
72
70
73
74
+ @dataclass
75
+ class OpName (Node ):
76
+ name : str
77
+
78
+
71
79
InputEffect = StackEffect | CacheEffect
72
80
OutputEffect = StackEffect
81
+ UOp = OpName | CacheEffect
73
82
74
83
75
84
@dataclass
@@ -82,32 +91,23 @@ class InstHeader(Node):
82
91
83
92
@dataclass
84
93
class InstDef (Node ):
85
- # TODO: Merge InstHeader and InstDef
86
- header : InstHeader
94
+ kind : Literal ["inst" , "op" ]
95
+ name : str
96
+ inputs : list [InputEffect ]
97
+ outputs : list [OutputEffect ]
87
98
block : Block
88
99
89
- @property
90
- def kind (self ) -> str :
91
- return self .header .kind
92
-
93
- @property
94
- def name (self ) -> str :
95
- return self .header .name
96
100
97
- @property
98
- def inputs (self ) -> list [InputEffect ]:
99
- return self .header .inputs
100
-
101
- @property
102
- def outputs (self ) -> list [OutputEffect ]:
103
- return self .header .outputs
101
+ @dataclass
102
+ class Super (Node ):
103
+ name : str
104
+ ops : list [OpName ]
104
105
105
106
106
107
@dataclass
107
- class Super (Node ):
108
- kind : Literal ["macro" , "super" ]
108
+ class Macro (Node ):
109
109
name : str
110
- ops : list [str ]
110
+ uops : list [UOp ]
111
111
112
112
113
113
@dataclass
@@ -118,12 +118,22 @@ class Family(Node):
118
118
119
119
120
120
class Parser (PLexer ):
121
+ @contextual
122
+ def definition (self ) -> InstDef | Super | Macro | Family | None :
123
+ if inst := self .inst_def ():
124
+ return inst
125
+ if super := self .super_def ():
126
+ return super
127
+ if macro := self .macro_def ():
128
+ return macro
129
+ if family := self .family_def ():
130
+ return family
121
131
122
132
@contextual
123
133
def inst_def (self ) -> InstDef | None :
124
- if header := self .inst_header ():
134
+ if hdr := self .inst_header ():
125
135
if block := self .block ():
126
- return InstDef (header , block )
136
+ return InstDef (hdr . kind , hdr . name , hdr . inputs , hdr . outputs , block )
127
137
raise self .make_syntax_error ("Expected block" )
128
138
return None
129
139
@@ -132,17 +142,14 @@ def inst_header(self) -> InstHeader | None:
132
142
# inst(NAME)
133
143
# | inst(NAME, (inputs -- outputs))
134
144
# | op(NAME, (inputs -- outputs))
135
- # TODO: Error out when there is something unexpected.
136
145
# TODO: Make INST a keyword in the lexer.
137
146
if (tkn := self .expect (lx .IDENTIFIER )) and (kind := tkn .text ) in ("inst" , "op" ):
138
- if (self .expect (lx .LPAREN )
139
- and (tkn := self .expect (lx .IDENTIFIER ))):
147
+ if self .expect (lx .LPAREN ) and (tkn := self .expect (lx .IDENTIFIER )):
140
148
name = tkn .text
141
149
if self .expect (lx .COMMA ):
142
150
inp , outp = self .stack_effect ()
143
151
if self .expect (lx .RPAREN ):
144
- if ((tkn := self .peek ())
145
- and tkn .kind == lx .LBRACE ):
152
+ if (tkn := self .peek ()) and tkn .kind == lx .LBRACE :
146
153
return InstHeader (kind , name , inp , outp )
147
154
elif self .expect (lx .RPAREN ) and kind == "inst" :
148
155
# No legacy stack effect if kind is "op".
@@ -176,18 +183,20 @@ def inputs(self) -> list[InputEffect] | None:
176
183
def input (self ) -> InputEffect | None :
177
184
# IDENTIFIER '/' INTEGER (CacheEffect)
178
185
# IDENTIFIER (StackEffect)
179
- if ( tkn := self .expect (lx .IDENTIFIER ) ):
186
+ if tkn := self .expect (lx .IDENTIFIER ):
180
187
if self .expect (lx .DIVIDE ):
181
188
if num := self .expect (lx .NUMBER ):
182
189
try :
183
190
size = int (num .text )
184
191
except ValueError :
185
192
raise self .make_syntax_error (
186
- f"Expected integer, got { num .text !r} " )
193
+ f"Expected integer, got { num .text !r} "
194
+ )
187
195
else :
188
196
return CacheEffect (tkn .text , size )
189
197
raise self .make_syntax_error ("Expected integer" )
190
198
else :
199
+ # TODO: Arrays, conditions
191
200
return StackEffect (tkn .text )
192
201
193
202
def outputs (self ) -> list [OutputEffect ] | None :
@@ -205,46 +214,91 @@ def outputs(self) -> list[OutputEffect] | None:
205
214
206
215
@contextual
207
216
def output (self ) -> OutputEffect | None :
208
- if ( tkn := self .expect (lx .IDENTIFIER ) ):
217
+ if tkn := self .expect (lx .IDENTIFIER ):
209
218
return StackEffect (tkn .text )
210
219
211
220
@contextual
212
221
def super_def (self ) -> Super | None :
213
- if (tkn := self .expect (lx .IDENTIFIER )) and ( kind := tkn .text ) in ( "super" , "macro" ) :
222
+ if (tkn := self .expect (lx .IDENTIFIER )) and tkn .text == "super" :
214
223
if self .expect (lx .LPAREN ):
215
- if ( tkn := self .expect (lx .IDENTIFIER ) ):
224
+ if tkn := self .expect (lx .IDENTIFIER ):
216
225
if self .expect (lx .RPAREN ):
217
226
if self .expect (lx .EQUALS ):
218
227
if ops := self .ops ():
219
- res = Super (kind , tkn .text , ops )
228
+ self .require (lx .SEMI )
229
+ res = Super (tkn .text , ops )
220
230
return res
221
231
222
- def ops (self ) -> list [str ] | None :
223
- if tkn := self .expect ( lx . IDENTIFIER ):
224
- ops = [tkn . text ]
232
+ def ops (self ) -> list [OpName ] | None :
233
+ if op := self .op ( ):
234
+ ops = [op ]
225
235
while self .expect (lx .PLUS ):
226
- if tkn := self .require (lx .IDENTIFIER ):
227
- ops .append (tkn .text )
228
- self .require (lx .SEMI )
236
+ if op := self .op ():
237
+ ops .append (op )
229
238
return ops
230
239
240
+ @contextual
241
+ def op (self ) -> OpName | None :
242
+ if tkn := self .expect (lx .IDENTIFIER ):
243
+ return OpName (tkn .text )
244
+
245
+ @contextual
246
+ def macro_def (self ) -> Macro | None :
247
+ if (tkn := self .expect (lx .IDENTIFIER )) and tkn .text == "macro" :
248
+ if self .expect (lx .LPAREN ):
249
+ if tkn := self .expect (lx .IDENTIFIER ):
250
+ if self .expect (lx .RPAREN ):
251
+ if self .expect (lx .EQUALS ):
252
+ if uops := self .uops ():
253
+ self .require (lx .SEMI )
254
+ res = Macro (tkn .text , uops )
255
+ return res
256
+
257
+ def uops (self ) -> list [UOp ] | None :
258
+ if uop := self .uop ():
259
+ uops = [uop ]
260
+ while self .expect (lx .PLUS ):
261
+ if uop := self .uop ():
262
+ uops .append (uop )
263
+ else :
264
+ raise self .make_syntax_error ("Expected op name or cache effect" )
265
+ return uops
266
+
267
+ @contextual
268
+ def uop (self ) -> UOp | None :
269
+ if tkn := self .expect (lx .IDENTIFIER ):
270
+ if self .expect (lx .DIVIDE ):
271
+ if num := self .expect (lx .NUMBER ):
272
+ try :
273
+ size = int (num .text )
274
+ except ValueError :
275
+ raise self .make_syntax_error (
276
+ f"Expected integer, got { num .text !r} "
277
+ )
278
+ else :
279
+ return CacheEffect (tkn .text , size )
280
+ raise self .make_syntax_error ("Expected integer" )
281
+ else :
282
+ return OpName (tkn .text )
283
+
231
284
@contextual
232
285
def family_def (self ) -> Family | None :
233
286
if (tkn := self .expect (lx .IDENTIFIER )) and tkn .text == "family" :
234
287
size = None
235
288
if self .expect (lx .LPAREN ):
236
- if ( tkn := self .expect (lx .IDENTIFIER ) ):
289
+ if tkn := self .expect (lx .IDENTIFIER ):
237
290
if self .expect (lx .COMMA ):
238
291
if not (size := self .expect (lx .IDENTIFIER )):
239
- raise self .make_syntax_error (
240
- "Expected identifier" )
292
+ raise self .make_syntax_error ("Expected identifier" )
241
293
if self .expect (lx .RPAREN ):
242
294
if self .expect (lx .EQUALS ):
243
295
if not self .expect (lx .LBRACE ):
244
296
raise self .make_syntax_error ("Expected {" )
245
297
if members := self .members ():
246
298
if self .expect (lx .RBRACE ) and self .expect (lx .SEMI ):
247
- return Family (tkn .text , size .text if size else "" , members )
299
+ return Family (
300
+ tkn .text , size .text if size else "" , members
301
+ )
248
302
return None
249
303
250
304
def members (self ) -> list [str ] | None :
@@ -284,6 +338,7 @@ def c_blob(self) -> list[lx.Token]:
284
338
285
339
if __name__ == "__main__" :
286
340
import sys
341
+
287
342
if sys .argv [1 :]:
288
343
filename = sys .argv [1 ]
289
344
if filename == "-c" and sys .argv [2 :]:
@@ -295,10 +350,10 @@ def c_blob(self) -> list[lx.Token]:
295
350
srclines = src .splitlines ()
296
351
begin = srclines .index ("// BEGIN BYTECODES //" )
297
352
end = srclines .index ("// END BYTECODES //" )
298
- src = "\n " .join (srclines [begin + 1 : end ])
353
+ src = "\n " .join (srclines [begin + 1 : end ])
299
354
else :
300
355
filename = "<default>"
301
356
src = "if (x) { x.foo; // comment\n }"
302
357
parser = Parser (src , filename )
303
- x = parser .inst_def () or parser . super_def () or parser . family_def ()
358
+ x = parser .definition ()
304
359
print (x )
0 commit comments