12
12
# type ::= product | sum
13
13
# product ::= fields ["attributes" fields]
14
14
# fields ::= "(" { field, "," } field ")"
15
- # field ::= TypeId [ "?" | "*"] [Id]
15
+ # field ::= TypeId { "?" | "*" } [Id]
16
16
# sum ::= constructor { "|" constructor } ["attributes" fields]
17
17
# constructor ::= ConstructorId [fields]
18
18
#
19
19
# [1] "The Zephyr Abstract Syntax Description Language" by Wang, et. al. See
20
20
# http://asdl.sourceforge.net/
21
21
#-------------------------------------------------------------------------------
22
22
from collections import namedtuple
23
+ import enum
23
24
import re
24
25
25
26
__all__ = [
@@ -64,34 +65,43 @@ def __init__(self, name, fields=None):
64
65
def __repr__ (self ):
65
66
return 'Constructor({0.name}, {0.fields})' .format (self )
66
67
68
+ class Quantifier (enum .Enum ):
69
+ OPTIONAL = enum .auto ()
70
+ SEQUENCE = enum .auto ()
71
+
67
72
class Field (AST ):
68
- def __init__ (self , type , name = None , seq = False , opt = False ):
73
+ def __init__ (self , type , name = None , quantifiers = None ):
69
74
self .type = type
70
75
self .name = name
71
- self .seq = seq
72
- self .opt = opt
76
+ self .seq = False
77
+ self .opt = False
78
+ self .quantifiers = quantifiers or []
79
+ if len (self .quantifiers ) > 0 :
80
+ self .seq = self .quantifiers [- 1 ] is Quantifier .SEQUENCE
81
+ self .opt = self .quantifiers [- 1 ] is Quantifier .OPTIONAL
73
82
74
83
def __str__ (self ):
75
- if self . seq :
76
- extra = "*"
77
- elif self . opt :
78
- extra = "? "
79
- else :
80
- extra = ""
84
+ extra = ""
85
+ for mod in self . quantifiers :
86
+ if mod is Quantifier . SEQUENCE :
87
+ extra + = "* "
88
+ elif mod is Quantifier . OPTIONAL :
89
+ extra + = "? "
81
90
82
91
return "{}{} {}" .format (self .type , extra , self .name )
83
92
84
93
def __repr__ (self ):
85
- if self .seq :
86
- extra = ", seq=True"
87
- elif self .opt :
88
- extra = ", opt=True"
89
- else :
90
- extra = ""
94
+ extra = ""
95
+ for mod in self .quantifiers :
96
+ if mod is Quantifier .SEQUENCE :
97
+ extra += ", SEQUENCE"
98
+ elif mod is Quantifier .OPTIONAL :
99
+ extra += ", OPTIONAL"
100
+
91
101
if self .name is None :
92
- return 'Field({0.type}{1})' .format (self , extra )
102
+ return 'Field({0.type}, quantifiers=[ {1}] )' .format (self , extra )
93
103
else :
94
- return 'Field({0.type}, {0.name}{1})' .format (self , extra )
104
+ return 'Field({0.type}, {0.name}, quantifiers=[ {1}] )' .format (self , extra )
95
105
96
106
class Sum (AST ):
97
107
def __init__ (self , types , attributes = None ):
@@ -314,10 +324,10 @@ def _parse_fields(self):
314
324
self ._match (TokenKind .LParen )
315
325
while self .cur_token .kind == TokenKind .TypeId :
316
326
typename = self ._advance ()
317
- is_seq , is_opt = self ._parse_optional_field_quantifier ()
327
+ quantifiers = self ._parse_optional_field_quantifier ()
318
328
id = (self ._advance () if self .cur_token .kind in self ._id_kinds
319
329
else None )
320
- fields .append (Field (typename , id , seq = is_seq , opt = is_opt ))
330
+ fields .append (Field (typename , id , quantifiers = quantifiers ))
321
331
if self .cur_token .kind == TokenKind .RParen :
322
332
break
323
333
elif self .cur_token .kind == TokenKind .Comma :
@@ -339,14 +349,14 @@ def _parse_optional_attributes(self):
339
349
return None
340
350
341
351
def _parse_optional_field_quantifier (self ):
342
- is_seq , is_opt = False , False
343
- if self .cur_token .kind == TokenKind .Asterisk :
344
- is_seq = True
345
- self . _advance ( )
346
- elif self .cur_token .kind == TokenKind .Question :
347
- is_opt = True
352
+ quantifiers = []
353
+ while self .cur_token .kind in ( TokenKind .Asterisk , TokenKind . Question ) :
354
+ if self . cur_token . kind == TokenKind . Asterisk :
355
+ quantifiers . append ( Quantifier . SEQUENCE )
356
+ elif self .cur_token .kind == TokenKind .Question :
357
+ quantifiers . append ( Quantifier . OPTIONAL )
348
358
self ._advance ()
349
- return is_seq , is_opt
359
+ return quantifiers
350
360
351
361
def _advance (self ):
352
362
""" Return the value of the current token and read the next one into
0 commit comments