blob: f73bd53752c393bd8359b88647ce8b0c676fa862 [file] [log] [blame]
Dusan Klinecccaa0d92014-11-09 03:21:31 +01001__author__ = "Dusan (Ph4r05) Klinec"
Sapan Bhatiab1225872017-03-29 20:47:47 +02002
Dusan Klinecccaa0d92014-11-09 03:21:31 +01003__copyright__ = "Copyright (C) 2014 Dusan (ph4r05) Klinec"
4__license__ = "Apache License, Version 2.0"
5__version__ = "1.0"
6
7import ply.lex as lex
8import ply.yacc as yacc
9from .model import *
10
Sapan Bhatiab1225872017-03-29 20:47:47 +020011import pdb
Sapan Bhatia64c72512017-06-23 02:32:45 -070012from helpers import LexHelper, LU
13from logicparser import FOLParser, FOLLexer
Sapan Bhatiaad79fee2017-06-26 23:35:57 -070014import ast
15
16class PythonError(Exception):
17 pass
Sapan Bhatiab1225872017-03-29 20:47:47 +020018
Dusan Klinecccaa0d92014-11-09 03:21:31 +010019class ProtobufLexer(object):
20 keywords = ('double', 'float', 'int32', 'int64', 'uint32', 'uint64', 'sint32', 'sint64',
21 'fixed32', 'fixed64', 'sfixed32', 'sfixed64', 'bool', 'string', 'bytes',
Sapan Bhatia78fee772017-04-21 19:00:48 +020022 'message', 'required', 'optional', 'repeated', 'enum', 'extensions', 'max', 'extend',
Sapan Bhatiad85f7f02017-07-13 21:25:23 -040023 'to', 'package', '_service', 'rpc', 'returns', 'true', 'false', 'option', 'import', 'manytoone', 'manytomany', 'onetoone', 'policy', 'map', 'reduce')
Dusan Klinecccaa0d92014-11-09 03:21:31 +010024
25 tokens = [
Sapan Bhatia64c72512017-06-23 02:32:45 -070026 'POLICYBODY',
Dusan Klinecccaa0d92014-11-09 03:21:31 +010027 'NAME',
28 'NUM',
29 'STRING_LITERAL',
Sapan Bhatia78fee772017-04-21 19:00:48 +020030 #'LINE_COMMENT', 'BLOCK_COMMENT',
Dusan Klinecccaa0d92014-11-09 03:21:31 +010031 'LBRACE', 'RBRACE', 'LBRACK', 'RBRACK',
Dusan Klinecc9b031a2014-11-10 13:21:08 +010032 'LPAR', 'RPAR', 'EQ', 'SEMI', 'DOT',
Sapan Bhatia78fee772017-04-21 19:00:48 +020033 'ARROW', 'COLON', 'COMMA', 'SLASH',
Sapan Bhatia64c72512017-06-23 02:32:45 -070034 'DOUBLECOLON',
Dusan Klinecaa9ff472014-11-10 18:02:03 +010035 'STARTTOKEN'
Dusan Klinecccaa0d92014-11-09 03:21:31 +010036 ] + [k.upper() for k in keywords]
Sapan Bhatia64c72512017-06-23 02:32:45 -070037
38
Sapan Bhatia5d76b242017-07-19 12:48:15 -040039 t_POLICYBODY = r'< (.|\n)*? [^-]>'
Sapan Bhatia64c72512017-06-23 02:32:45 -070040
Dusan Klinecccaa0d92014-11-09 03:21:31 +010041 literals = '()+-*/=?:,.^|&~!=[]{};<>@%'
42
Sapan Bhatia87792a12017-04-10 19:35:05 -070043 t_NUM = r'[+-]?\d+(\.\d+)?'
Dusan Klinecccaa0d92014-11-09 03:21:31 +010044 t_STRING_LITERAL = r'\"([^\\\n]|(\\.))*?\"'
45
46 t_ignore_LINE_COMMENT = '//.*'
47 def t_BLOCK_COMMENT(self, t):
48 r'/\*(.|\n)*?\*/'
49 t.lexer.lineno += t.value.count('\n')
50
51 t_LBRACE = '{'
52 t_RBRACE = '}'
53 t_LBRACK = '\\['
54 t_RBRACK = '\\]'
Sapan Bhatia64c72512017-06-23 02:32:45 -070055
56
Dusan Klinecccaa0d92014-11-09 03:21:31 +010057 t_LPAR = '\\('
58 t_RPAR = '\\)'
59 t_EQ = '='
60 t_SEMI = ';'
Sapan Bhatiab1225872017-03-29 20:47:47 +020061 t_ARROW = '\\-\\>'
62 t_COLON = '\\:'
Sapan Bhatia78fee772017-04-21 19:00:48 +020063 t_SLASH = '\\/'
Sapan Bhatiab1225872017-03-29 20:47:47 +020064 t_COMMA = '\\,'
Dusan Klineca4fae112014-11-10 08:50:27 +010065 t_DOT = '\\.'
Dusan Klinecccaa0d92014-11-09 03:21:31 +010066 t_ignore = ' \t\f'
Dusan Klinecaa9ff472014-11-10 18:02:03 +010067 t_STARTTOKEN = '\\+'
Sapan Bhatia64c72512017-06-23 02:32:45 -070068 t_DOUBLECOLON = '\\:\\:'
Dusan Klinecccaa0d92014-11-09 03:21:31 +010069
70 def t_NAME(self, t):
Sapan Bhatia78fee772017-04-21 19:00:48 +020071 '[A-Za-z_$][A-Za-z0-9_+$]*'
Dusan Klinecccaa0d92014-11-09 03:21:31 +010072 if t.value in ProtobufLexer.keywords:
Dusan Klineca4fae112014-11-10 08:50:27 +010073 #print "type: %s val %s t %s" % (t.type, t.value, t)
Dusan Klinecccaa0d92014-11-09 03:21:31 +010074 t.type = t.value.upper()
75 return t
76
77 def t_newline(self, t):
78 r'\n+'
79 t.lexer.lineno += len(t.value)
80
81 def t_newline2(self, t):
82 r'(\r\n)+'
83 t.lexer.lineno += len(t.value) / 2
84
85 def t_error(self, t):
86 print("Illegal character '{}' ({}) in line {}".format(t.value[0], hex(ord(t.value[0])), t.lexer.lineno))
87 t.lexer.skip(1)
88
Dusan Klinecc9b031a2014-11-10 13:21:08 +010089
Sapan Bhatiab1225872017-03-29 20:47:47 +020090def srcPort(x):
91 if (x):
92 return [FieldDirective(Name('port'),x)]
93 else:
94 return []
95
96
Dusan Klinecccaa0d92014-11-09 03:21:31 +010097class ProtobufParser(object):
98 tokens = ProtobufLexer.tokens
Dusan Klinecaa9ff472014-11-10 18:02:03 +010099 offset = 0
100 lh = LexHelper()
Sapan Bhatia64c72512017-06-23 02:32:45 -0700101 fol_lexer = lex.lex(module=FOLLexer())#, optimize=1)
102 fol_parser = yacc.yacc(module=FOLParser(), start='goal')
Dusan Klinecaa9ff472014-11-10 18:02:03 +0100103
104 def setOffset(self, of):
105 self.offset = of
106 self.lh.offset = of
Dusan Klinecccaa0d92014-11-09 03:21:31 +0100107
108 def p_empty(self, p):
109 '''empty :'''
110 pass
111
112 def p_field_modifier(self,p):
113 '''field_modifier : REQUIRED
114 | OPTIONAL
115 | REPEATED'''
Dusan Klinecaa9ff472014-11-10 18:02:03 +0100116 p[0] = LU.i(p,1)
Dusan Klinecccaa0d92014-11-09 03:21:31 +0100117
118 def p_primitive_type(self, p):
119 '''primitive_type : DOUBLE
120 | FLOAT
121 | INT32
122 | INT64
123 | UINT32
124 | UINT64
125 | SINT32
126 | SINT64
127 | FIXED32
128 | FIXED64
129 | SFIXED32
130 | SFIXED64
131 | BOOL
132 | STRING
133 | BYTES'''
Dusan Klinecaa9ff472014-11-10 18:02:03 +0100134 p[0] = LU.i(p,1)
Dusan Klinecccaa0d92014-11-09 03:21:31 +0100135
Sapan Bhatiab1225872017-03-29 20:47:47 +0200136 def p_link_type(self, p):
137 '''link_type : ONETOONE
138 | MANYTOONE
139 | MANYTOMANY'''
140 p[0] = LU.i(p,1)
141
Dusan Klinecccaa0d92014-11-09 03:21:31 +0100142 def p_field_id(self, p):
143 '''field_id : NUM'''
Dusan Klinecaa9ff472014-11-10 18:02:03 +0100144 p[0] = LU.i(p,1)
Dusan Klinecccaa0d92014-11-09 03:21:31 +0100145
146 def p_rvalue(self, p):
147 '''rvalue : NUM
148 | TRUE
149 | FALSE'''
Dusan Klinecaa9ff472014-11-10 18:02:03 +0100150 p[0] = LU.i(p,1)
Dusan Klinecccaa0d92014-11-09 03:21:31 +0100151
Sapan Bhatiab1225872017-03-29 20:47:47 +0200152 def p_rvalue3(self, p):
153 '''rvalue : STRING_LITERAL'''
154 p[0] = Name(LU.i(p, 1))
155 self.lh.set_parse_object(p[0], p)
156 p[0].deriveLex()
157
Dusan Klinecccaa0d92014-11-09 03:21:31 +0100158 def p_rvalue2(self, p):
159 '''rvalue : NAME'''
Dusan Klinecaa9ff472014-11-10 18:02:03 +0100160 p[0] = Name(LU.i(p, 1))
161 self.lh.set_parse_object(p[0], p)
162 p[0].deriveLex()
Dusan Klinecccaa0d92014-11-09 03:21:31 +0100163
Sapan Bhatiab1225872017-03-29 20:47:47 +0200164 def p_field_directives2(self, p):
165 '''field_directives : empty'''
166 p[0] = []
167
168 def p_field_directives(self, p):
169 '''field_directives : LBRACK field_directive_times RBRACK'''
170 p[0] = p[2]
171 #self.lh.set_parse_object(p[0], p)
172
Dusan Klinecccaa0d92014-11-09 03:21:31 +0100173 def p_field_directive(self, p):
Sapan Bhatiab1225872017-03-29 20:47:47 +0200174 '''field_directive : NAME EQ rvalue'''
175 p[0] = FieldDirective(Name(LU.i(p, 1)), LU.i(p, 3))
Dusan Klinecaa9ff472014-11-10 18:02:03 +0100176 self.lh.set_parse_object(p[0], p)
Dusan Klinecccaa0d92014-11-09 03:21:31 +0100177
Sapan Bhatiaa3686022017-06-24 07:24:19 -0700178 def p_policy_opt_explicit(self, p):
179 '''policy_opt : DOUBLECOLON NAME'''
180 p[0] = p[2]
181
Sapan Bhatiaa3686022017-06-24 07:24:19 -0700182 def p_policy_opt_empty(self, p):
183 '''policy_opt : empty'''
184 p[0] = None
Sapan Bhatia87792a12017-04-10 19:35:05 -0700185
186 def p_csv_expr(self, p):
187 '''csv_expr : LPAR csv RPAR'''
188 p[0] = p[2]
189
190 def p_csv_expr2(self, p):
191 '''csv_expr : empty'''
192 p[0] = []
193
194 def p_csv2(self, p):
195 '''csv : empty'''
196
197 def p_csv(self, p):
Sapan Bhatia2ddf83a2017-06-10 04:31:40 -0700198 '''csv : dotname
199 | csv COMMA dotname'''
Sapan Bhatia87792a12017-04-10 19:35:05 -0700200
201 if len(p) == 2:
202 p[0] = [LU(p,1)]
203 else:
204 p[0] = p[1] + [LU(p,3)]
205
Dusan Klinecccaa0d92014-11-09 03:21:31 +0100206 def p_field_directive_times(self, p):
207 '''field_directive_times : field_directive_plus'''
208 p[0] = p[1]
209
210 def p_field_directive_times2(self, p):
211 '''field_directive_times : empty'''
212 p[0] = []
213
214 def p_field_directive_plus(self, p):
215 '''field_directive_plus : field_directive
Sapan Bhatiab1225872017-03-29 20:47:47 +0200216 | field_directive_plus COMMA field_directive'''
Dusan Klinecccaa0d92014-11-09 03:21:31 +0100217 if len(p) == 2:
Dusan Klineca9f6d362014-11-10 21:07:08 +0100218 p[0] = [LU(p,1)]
Dusan Klinecccaa0d92014-11-09 03:21:31 +0100219 else:
Sapan Bhatiab1225872017-03-29 20:47:47 +0200220 p[0] = p[1] + [LU(p,3)]
Dusan Klinecccaa0d92014-11-09 03:21:31 +0100221
Dusan Klineca4fae112014-11-10 08:50:27 +0100222 def p_dotname(self, p):
223 '''dotname : NAME
224 | dotname DOT NAME'''
Dusan Klinecaa9ff472014-11-10 18:02:03 +0100225 if len(p) == 2:
226 p[0] = [LU(p,1)]
227 else:
228 p[0] = p[1] + [LU(p,3)]
Dusan Klineca4fae112014-11-10 08:50:27 +0100229
230 # Hack for cases when there is a field named 'message' or 'max'
231 def p_fieldName(self, p):
Sapan Bhatia78fee772017-04-21 19:00:48 +0200232 '''field_name : STARTTOKEN
233 | NAME
Dusan Klineca4fae112014-11-10 08:50:27 +0100234 | MESSAGE
235 | MAX'''
Dusan Klinecaa9ff472014-11-10 18:02:03 +0100236 p[0] = Name(LU.i(p,1))
237 self.lh.set_parse_object(p[0], p)
238 p[0].deriveLex()
Dusan Klineca4fae112014-11-10 08:50:27 +0100239
Dusan Klinecccaa0d92014-11-09 03:21:31 +0100240 def p_field_type(self, p):
241 '''field_type : primitive_type'''
Dusan Klinecaa9ff472014-11-10 18:02:03 +0100242 p[0] = FieldType(LU.i(p,1))
243 self.lh.set_parse_object(p[0], p)
Dusan Klinecccaa0d92014-11-09 03:21:31 +0100244
245 def p_field_type2(self, p):
Dusan Klineca4fae112014-11-10 08:50:27 +0100246 '''field_type : dotname'''
Dusan Klinecaa9ff472014-11-10 18:02:03 +0100247 p[0] = DotName(LU.i(p, 1))
248 self.lh.set_parse_object(p[0], p)
249 p[0].deriveLex()
Dusan Klinecccaa0d92014-11-09 03:21:31 +0100250
Sapan Bhatia78fee772017-04-21 19:00:48 +0200251 def p_slash_name(self, p):
Sapan Bhatia2ddf83a2017-06-10 04:31:40 -0700252 '''slash_name : SLASH dotname'''
Sapan Bhatia78fee772017-04-21 19:00:48 +0200253 p[0] = p[2]
254 #self.lh.set_parse_object(p[0], p)
255
256 def p_slash_name2(self, p):
257 '''slash_name : empty'''
258 p[0] = None
259
Sapan Bhatiab1225872017-03-29 20:47:47 +0200260 def p_colon_fieldname(self, p):
261 '''colon_fieldname : COLON field_name'''
262 p[0] = p[2]
263 self.lh.set_parse_object(p[0], p)
264
265 def p_colon_fieldname2(self, p):
266 '''colon_fieldname : empty'''
267 p[0] = None
268
269 # TODO: Add directives to link definition
270 def p_link_definition(self, p):
Sapan Bhatiad70c3782017-06-28 22:47:22 -0700271 '''link_definition : field_modifier link_type field_name policy_opt ARROW dotname slash_name colon_fieldname EQ field_id field_directives SEMI'''
Sapan Bhatiab1225872017-03-29 20:47:47 +0200272 p[0] = LinkSpec(
Sapan Bhatiad70c3782017-06-28 22:47:22 -0700273 FieldDefinition(LU.i(p,1), Name('int32'), LU.i(p, 3), LU.i(p,4), LU.i(p, 10), [FieldDirective(Name('type'), Name('link')), FieldDirective(Name('model'),LU.i(p, 6))] + srcPort(LU.i(p,8)) + LU.i(p,11)),
274 LinkDefinition(LU.i(p,2), LU.i(p,3), LU.i(p,6), LU.i(p,7), LU.i(p,8)))
Sapan Bhatiab1225872017-03-29 20:47:47 +0200275
276 self.lh.set_parse_object(p[0], p)
277
Dusan Klinecccaa0d92014-11-09 03:21:31 +0100278 # Root of the field declaration.
279 def p_field_definition(self, p):
Sapan Bhatiaa3686022017-06-24 07:24:19 -0700280 '''field_definition : field_modifier field_type field_name policy_opt EQ field_id field_directives SEMI'''
281 p[0] = FieldDefinition(LU.i(p,1), LU.i(p,2), LU.i(p, 3), LU.i(p,4), LU.i(p,6), LU.i(p,7))
Dusan Klinecaa9ff472014-11-10 18:02:03 +0100282 self.lh.set_parse_object(p[0], p)
Dusan Klinecccaa0d92014-11-09 03:21:31 +0100283
284 # Root of the enum field declaration.
285 def p_enum_field(self, p):
Dusan Klineca4fae112014-11-10 08:50:27 +0100286 '''enum_field : field_name EQ NUM SEMI'''
Dusan Klinecaa9ff472014-11-10 18:02:03 +0100287 p[0] = EnumFieldDefinition(LU.i(p, 1), LU.i(p,3))
288 self.lh.set_parse_object(p[0], p)
Dusan Klinecccaa0d92014-11-09 03:21:31 +0100289
290 def p_enum_body_part(self, p):
291 '''enum_body_part : enum_field
292 | option_directive'''
293 p[0] = p[1]
294
295 def p_enum_body(self, p):
296 '''enum_body : enum_body_part
297 | enum_body enum_body_part'''
298 if len(p) == 2:
299 p[0] = [p[1]]
300 else:
301 p[0] = p[1] + [p[2]]
302
303 def p_enum_body_opt(self, p):
304 '''enum_body_opt : empty'''
305 p[0] = []
306
307 def p_enum_body_opt2(self, p):
308 '''enum_body_opt : enum_body'''
309 p[0] = p[1]
310
Sapan Bhatiaad79fee2017-06-26 23:35:57 -0700311 def p_reduce_definition(self, p):
312 '''reduce_definition : REDUCE NAME POLICYBODY'''
313 ltxt = p[3].lstrip('<').rstrip('>')
314 l = ast.parse(ltxt).body[0]
315 if not isinstance(l, ast.Expr):
316 raise PythonError("reduce operator needs to be an expression")
317 elif not isinstance(l.value, ast.Lambda):
318 raise PythonError("reduce operator needs to be a lambda")
319
320 p[0] = ReduceDefinition(Name(LU.i(p, 2)), ltxt)
321 self.lh.set_parse_object(p[0], p)
322
323 def p_map_definition(self, p):
324 '''map_definition : MAP NAME POLICYBODY'''
325 ltxt = p[3].lstrip('<').rstrip('>')
326 l = ast.parse(ltxt).body[0]
327 if not isinstance(l, ast.Expr):
328 raise PythonError("map operator needs to be an expression")
329 elif not isinstance(l.value, ast.Lambda):
330 raise PythonError("map operator needs to be a lambda")
331
332 p[0] = MapDefinition(Name(LU.i(p, 2)), ltxt)
333 self.lh.set_parse_object(p[0], p)
334
Sapan Bhatia64c72512017-06-23 02:32:45 -0700335 def p_policy_definition(self, p):
336 '''policy_definition : POLICY NAME POLICYBODY'''
337 fol = self.fol_parser.parse(p[3], lexer = self.fol_lexer)
338 p[0] = PolicyDefinition(Name(LU.i(p, 2)), fol)
339 self.lh.set_parse_object(p[0], p)
340
Dusan Klinecccaa0d92014-11-09 03:21:31 +0100341 # Root of the enum declaration.
342 # enum_definition ::= 'enum' ident '{' { ident '=' integer ';' }* '}'
343 def p_enum_definition(self, p):
344 '''enum_definition : ENUM NAME LBRACE enum_body_opt RBRACE'''
Dusan Klinecaa9ff472014-11-10 18:02:03 +0100345 p[0] = EnumDefinition(Name(LU.i(p, 2)), LU.i(p,4))
346 self.lh.set_parse_object(p[0], p)
Dusan Klinecccaa0d92014-11-09 03:21:31 +0100347
348 def p_extensions_to(self, p):
349 '''extensions_to : MAX'''
350 p[0] = ExtensionsMax()
Dusan Klinecaa9ff472014-11-10 18:02:03 +0100351 self.lh.set_parse_object(p[0], p)
Dusan Klinecccaa0d92014-11-09 03:21:31 +0100352
353 def p_extensions_to2(self, p):
354 '''extensions_to : NUM'''
Dusan Klinecaa9ff472014-11-10 18:02:03 +0100355 p[0] = LU.i(p, 1)
Dusan Klinecccaa0d92014-11-09 03:21:31 +0100356
357 # extensions_definition ::= 'extensions' integer 'to' integer ';'
358 def p_extensions_definition(self, p):
359 '''extensions_definition : EXTENSIONS NUM TO extensions_to SEMI'''
Dusan Klinecaa9ff472014-11-10 18:02:03 +0100360 p[0] = ExtensionsDirective(LU.i(p,2), LU.i(p,4))
361 self.lh.set_parse_object(p[0], p)
Dusan Klinecccaa0d92014-11-09 03:21:31 +0100362
363 # message_extension ::= 'extend' ident '{' message_body '}'
364 def p_message_extension(self, p):
365 '''message_extension : EXTEND NAME LBRACE message_body RBRACE'''
Dusan Klinecaa9ff472014-11-10 18:02:03 +0100366 p[0] = MessageExtension(Name(LU.i(p, 2)), LU.i(p,4))
367 self.lh.set_parse_object(p[0], p)
Dusan Klinecccaa0d92014-11-09 03:21:31 +0100368
369 def p_message_body_part(self, p):
370 '''message_body_part : field_definition
Sapan Bhatiab1225872017-03-29 20:47:47 +0200371 | link_definition
Dusan Klinecccaa0d92014-11-09 03:21:31 +0100372 | enum_definition
Sapan Bhatia4a159ac2017-04-29 20:10:05 +0200373 | option_directive
Dusan Klinecccaa0d92014-11-09 03:21:31 +0100374 | message_definition
375 | extensions_definition
376 | message_extension'''
377 p[0] = p[1]
378
379 # message_body ::= { field_definition | enum_definition | message_definition | extensions_definition | message_extension }*
380 def p_message_body(self, p):
381 '''message_body : empty'''
382 p[0] = []
383
384 # message_body ::= { field_definition | enum_definition | message_definition | extensions_definition | message_extension }*
385 def p_message_body2(self, p):
386 '''message_body : message_body_part
387 | message_body message_body_part'''
388 if len(p) == 2:
389 p[0] = [p[1]]
390 else:
391 p[0] = p[1] + [p[2]]
392
393 # Root of the message declaration.
394 # message_definition = MESSAGE_ - ident("messageId") + LBRACE + message_body("body") + RBRACE
395 def p_message_definition(self, p):
Sapan Bhatiaa3686022017-06-24 07:24:19 -0700396 '''message_definition : MESSAGE NAME policy_opt csv_expr LBRACE message_body RBRACE'''
397 p[0] = MessageDefinition(Name(LU.i(p, 2)), LU.i(p,3), LU.i(p, 4), LU.i(p,6))
Dusan Klinecaa9ff472014-11-10 18:02:03 +0100398 self.lh.set_parse_object(p[0], p)
Dusan Klinecccaa0d92014-11-09 03:21:31 +0100399
400 # method_definition ::= 'rpc' ident '(' [ ident ] ')' 'returns' '(' [ ident ] ')' ';'
401 def p_method_definition(self, p):
402 '''method_definition : RPC NAME LPAR NAME RPAR RETURNS LPAR NAME RPAR'''
Dusan Klinecaa9ff472014-11-10 18:02:03 +0100403 p[0] = MethodDefinition(Name(LU.i(p, 2)), Name(LU.i(p, 4)), Name(LU.i(p, 8)))
404 self.lh.set_parse_object(p[0], p)
Dusan Klinecccaa0d92014-11-09 03:21:31 +0100405
406 def p_method_definition_opt(self, p):
407 '''method_definition_opt : empty'''
408 p[0] = []
409
410 def p_method_definition_opt2(self, p):
411 '''method_definition_opt : method_definition
412 | method_definition_opt method_definition'''
413 if len(p) == 2:
414 p[0] = [p[1]]
415 else:
416 p[0] = p[1] + [p[2]]
417
418 # service_definition ::= 'service' ident '{' method_definition* '}'
419 # service_definition = SERVICE_ - ident("serviceName") + LBRACE + ZeroOrMore(Group(method_definition)) + RBRACE
420 def p_service_definition(self, p):
Sapan Bhatiab1225872017-03-29 20:47:47 +0200421 '''service_definition : _SERVICE NAME LBRACE method_definition_opt RBRACE'''
Dusan Klinecaa9ff472014-11-10 18:02:03 +0100422 p[0] = ServiceDefinition(Name(LU.i(p, 2)), LU.i(p,4))
423 self.lh.set_parse_object(p[0], p)
Dusan Klinecccaa0d92014-11-09 03:21:31 +0100424
425 # package_directive ::= 'package' ident [ '.' ident]* ';'
426 def p_package_directive(self,p):
Dusan Klineca4fae112014-11-10 08:50:27 +0100427 '''package_directive : PACKAGE dotname SEMI'''
Dusan Klinecaa9ff472014-11-10 18:02:03 +0100428 p[0] = PackageStatement(Name(LU.i(p, 2)))
429 self.lh.set_parse_object(p[0], p)
Dusan Klinecccaa0d92014-11-09 03:21:31 +0100430
431 # import_directive = IMPORT_ - quotedString("importFileSpec") + SEMI
432 def p_import_directive(self, p):
433 '''import_directive : IMPORT STRING_LITERAL SEMI'''
Dusan Klinecaa9ff472014-11-10 18:02:03 +0100434 p[0] = ImportStatement(Literal(LU.i(p,2)))
435 self.lh.set_parse_object(p[0], p)
Dusan Klinecccaa0d92014-11-09 03:21:31 +0100436
437 def p_option_rvalue(self, p):
438 '''option_rvalue : NUM
439 | TRUE
440 | FALSE'''
Dusan Klinecaa9ff472014-11-10 18:02:03 +0100441 p[0] = LU(p, 1)
Dusan Klinecccaa0d92014-11-09 03:21:31 +0100442
443 def p_option_rvalue2(self, p):
444 '''option_rvalue : STRING_LITERAL'''
Dusan Klinecaa9ff472014-11-10 18:02:03 +0100445 p[0] = Literal(LU(p,1))
446
447 def p_option_rvalue3(self, p):
448 '''option_rvalue : NAME'''
449 p[0] = Name(LU.i(p,1))
Dusan Klinecccaa0d92014-11-09 03:21:31 +0100450
451 # option_directive = OPTION_ - ident("optionName") + EQ + quotedString("optionValue") + SEMI
452 def p_option_directive(self, p):
453 '''option_directive : OPTION NAME EQ option_rvalue SEMI'''
Dusan Klinecaa9ff472014-11-10 18:02:03 +0100454 p[0] = OptionStatement(Name(LU.i(p, 2)), LU.i(p,4))
455 self.lh.set_parse_object(p[0], p)
Dusan Klinecccaa0d92014-11-09 03:21:31 +0100456
Sapan Bhatiaff86b012017-06-11 14:44:15 -0700457 # topLevelStatement = Group(message_definition | message_extension | enum_definition | service_definition | import_directive | option_directive | package_definition)
Dusan Klinecccaa0d92014-11-09 03:21:31 +0100458 def p_topLevel(self,p):
459 '''topLevel : message_definition
460 | message_extension
461 | enum_definition
Sapan Bhatia64c72512017-06-23 02:32:45 -0700462 | policy_definition
Sapan Bhatia89bbaa52017-06-28 22:58:15 -0700463 | map_definition
464 | reduce_definition
Dusan Klinecccaa0d92014-11-09 03:21:31 +0100465 | service_definition
466 | import_directive
Sapan Bhatiaff86b012017-06-11 14:44:15 -0700467 | package_directive
Dusan Klinecccaa0d92014-11-09 03:21:31 +0100468 | option_directive'''
469 p[0] = p[1]
470
Dusan Klinecccaa0d92014-11-09 03:21:31 +0100471 def p_statements2(self, p):
472 '''statements : topLevel
473 | statements topLevel'''
474 if len(p) == 2:
475 p[0] = [p[1]]
476 else:
477 p[0] = p[1] + [p[2]]
478
479 def p_statements(self, p):
480 '''statements : empty'''
481 p[0] = []
482
483 # parser = Optional(package_directive) + ZeroOrMore(topLevelStatement)
Dusan Klinecc9b031a2014-11-10 13:21:08 +0100484 def p_protofile(self, p):
Sapan Bhatiaff86b012017-06-11 14:44:15 -0700485 '''protofile : statements'''
486 p[0] = ProtoFile(LU.i(p,1))
Dusan Klinecaa9ff472014-11-10 18:02:03 +0100487 self.lh.set_parse_object(p[0], p)
Dusan Klinecc9b031a2014-11-10 13:21:08 +0100488
489 # Parsing starting point
490 def p_goal(self, p):
Dusan Klinecaa9ff472014-11-10 18:02:03 +0100491 '''goal : STARTTOKEN protofile'''
Dusan Klinecc9b031a2014-11-10 13:21:08 +0100492 p[0] = p[2]
Dusan Klinecccaa0d92014-11-09 03:21:31 +0100493
494 def p_error(self, p):
495 print('error: {}'.format(p))
496
497class ProtobufAnalyzer(object):
498
499 def __init__(self):
Sapan Bhatiab1225872017-03-29 20:47:47 +0200500 self.lexer = lex.lex(module=ProtobufLexer())#, optimize=1)
Sapan Bhatia44609112017-05-15 00:00:25 +0200501 self.parser = yacc.yacc(module=ProtobufParser(), start='goal', debug=0, outputdir='/tmp')#optimize=1)
Dusan Klinecccaa0d92014-11-09 03:21:31 +0100502
503 def tokenize_string(self, code):
504 self.lexer.input(code)
505 for token in self.lexer:
506 print(token)
507
508 def tokenize_file(self, _file):
509 if type(_file) == str:
510 _file = file(_file)
511 content = ''
512 for line in _file:
513 content += line
514 return self.tokenize_string(content)
515
Dusan Klinecaa9ff472014-11-10 18:02:03 +0100516 def parse_string(self, code, debug=0, lineno=1, prefix='+'):
Dusan Klinecccaa0d92014-11-09 03:21:31 +0100517 self.lexer.lineno = lineno
Dusan Klinecaa9ff472014-11-10 18:02:03 +0100518 self.parser.offset = len(prefix)
Dusan Klinecccaa0d92014-11-09 03:21:31 +0100519 return self.parser.parse(prefix + code, lexer=self.lexer, debug=debug)
520
521 def parse_file(self, _file, debug=0):
522 if type(_file) == str:
523 _file = file(_file)
524 content = ''
525 for line in _file:
526 content += line
527 return self.parse_string(content, debug=debug)