blob: 6213a07fc77336c97872fe982cbb5e04046cbeba [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
Sapan Bhatia9c579722018-01-12 13:45:09 -050013from logicparser import FOLParser, FOLLexer, FOLParsingError
Sapan Bhatiaad79fee2017-06-26 23:35:57 -070014import ast
15
16class PythonError(Exception):
17 pass
Sapan Bhatiab1225872017-03-29 20:47:47 +020018
Sapan Bhatia9c579722018-01-12 13:45:09 -050019class ParsingError(Exception):
20 def __init__(self, message, error_range):
21 super(ParsingError, self).__init__(message)
22 self.error_range = error_range
23
24
Dusan Klinecccaa0d92014-11-09 03:21:31 +010025class ProtobufLexer(object):
26 keywords = ('double', 'float', 'int32', 'int64', 'uint32', 'uint64', 'sint32', 'sint64',
27 'fixed32', 'fixed64', 'sfixed32', 'sfixed64', 'bool', 'string', 'bytes',
Sapan Bhatia78fee772017-04-21 19:00:48 +020028 'message', 'required', 'optional', 'repeated', 'enum', 'extensions', 'max', 'extend',
Sapan Bhatiad85f7f02017-07-13 21:25:23 -040029 'to', 'package', '_service', 'rpc', 'returns', 'true', 'false', 'option', 'import', 'manytoone', 'manytomany', 'onetoone', 'policy', 'map', 'reduce')
Dusan Klinecccaa0d92014-11-09 03:21:31 +010030
31 tokens = [
Sapan Bhatia64c72512017-06-23 02:32:45 -070032 'POLICYBODY',
Dusan Klinecccaa0d92014-11-09 03:21:31 +010033 'NAME',
34 'NUM',
35 'STRING_LITERAL',
Sapan Bhatia78fee772017-04-21 19:00:48 +020036 #'LINE_COMMENT', 'BLOCK_COMMENT',
Dusan Klinecccaa0d92014-11-09 03:21:31 +010037 'LBRACE', 'RBRACE', 'LBRACK', 'RBRACK',
Dusan Klinecc9b031a2014-11-10 13:21:08 +010038 'LPAR', 'RPAR', 'EQ', 'SEMI', 'DOT',
Sapan Bhatia78fee772017-04-21 19:00:48 +020039 'ARROW', 'COLON', 'COMMA', 'SLASH',
Sapan Bhatia64c72512017-06-23 02:32:45 -070040 'DOUBLECOLON',
Dusan Klinecaa9ff472014-11-10 18:02:03 +010041 'STARTTOKEN'
Dusan Klinecccaa0d92014-11-09 03:21:31 +010042 ] + [k.upper() for k in keywords]
Sapan Bhatia64c72512017-06-23 02:32:45 -070043
44
Sapan Bhatia9c579722018-01-12 13:45:09 -050045 def t_POLICYBODY(self, t):
46 r'< (.|\n)*? [^-]>'
47 t.lexer.lineno += t.value.count('\n')
48 return t
Sapan Bhatia64c72512017-06-23 02:32:45 -070049
Dusan Klinecccaa0d92014-11-09 03:21:31 +010050 literals = '()+-*/=?:,.^|&~!=[]{};<>@%'
51
Sapan Bhatia87792a12017-04-10 19:35:05 -070052 t_NUM = r'[+-]?\d+(\.\d+)?'
Dusan Klinecccaa0d92014-11-09 03:21:31 +010053 t_STRING_LITERAL = r'\"([^\\\n]|(\\.))*?\"'
54
55 t_ignore_LINE_COMMENT = '//.*'
56 def t_BLOCK_COMMENT(self, t):
57 r'/\*(.|\n)*?\*/'
58 t.lexer.lineno += t.value.count('\n')
59
60 t_LBRACE = '{'
61 t_RBRACE = '}'
62 t_LBRACK = '\\['
63 t_RBRACK = '\\]'
Sapan Bhatia64c72512017-06-23 02:32:45 -070064
65
Dusan Klinecccaa0d92014-11-09 03:21:31 +010066 t_LPAR = '\\('
67 t_RPAR = '\\)'
68 t_EQ = '='
69 t_SEMI = ';'
Sapan Bhatiab1225872017-03-29 20:47:47 +020070 t_ARROW = '\\-\\>'
71 t_COLON = '\\:'
Sapan Bhatia78fee772017-04-21 19:00:48 +020072 t_SLASH = '\\/'
Sapan Bhatiab1225872017-03-29 20:47:47 +020073 t_COMMA = '\\,'
Dusan Klineca4fae112014-11-10 08:50:27 +010074 t_DOT = '\\.'
Dusan Klinecccaa0d92014-11-09 03:21:31 +010075 t_ignore = ' \t\f'
Dusan Klinecaa9ff472014-11-10 18:02:03 +010076 t_STARTTOKEN = '\\+'
Sapan Bhatia64c72512017-06-23 02:32:45 -070077 t_DOUBLECOLON = '\\:\\:'
Dusan Klinecccaa0d92014-11-09 03:21:31 +010078
79 def t_NAME(self, t):
Sapan Bhatia78fee772017-04-21 19:00:48 +020080 '[A-Za-z_$][A-Za-z0-9_+$]*'
Dusan Klinecccaa0d92014-11-09 03:21:31 +010081 if t.value in ProtobufLexer.keywords:
Dusan Klineca4fae112014-11-10 08:50:27 +010082 #print "type: %s val %s t %s" % (t.type, t.value, t)
Dusan Klinecccaa0d92014-11-09 03:21:31 +010083 t.type = t.value.upper()
84 return t
85
86 def t_newline(self, t):
87 r'\n+'
88 t.lexer.lineno += len(t.value)
89
90 def t_newline2(self, t):
91 r'(\r\n)+'
92 t.lexer.lineno += len(t.value) / 2
93
94 def t_error(self, t):
95 print("Illegal character '{}' ({}) in line {}".format(t.value[0], hex(ord(t.value[0])), t.lexer.lineno))
96 t.lexer.skip(1)
97
Dusan Klinecc9b031a2014-11-10 13:21:08 +010098
Sapan Bhatiab1225872017-03-29 20:47:47 +020099def srcPort(x):
100 if (x):
101 return [FieldDirective(Name('port'),x)]
102 else:
103 return []
104
105
Dusan Klinecccaa0d92014-11-09 03:21:31 +0100106class ProtobufParser(object):
107 tokens = ProtobufLexer.tokens
Dusan Klinecaa9ff472014-11-10 18:02:03 +0100108 offset = 0
109 lh = LexHelper()
Sapan Bhatia64c72512017-06-23 02:32:45 -0700110 fol_lexer = lex.lex(module=FOLLexer())#, optimize=1)
Sapan Bhatia9c579722018-01-12 13:45:09 -0500111 fol_parser = yacc.yacc(module=FOLParser(), start='goal', outputdir='/tmp', debug=0)
Dusan Klinecaa9ff472014-11-10 18:02:03 +0100112
113 def setOffset(self, of):
114 self.offset = of
115 self.lh.offset = of
Dusan Klinecccaa0d92014-11-09 03:21:31 +0100116
117 def p_empty(self, p):
118 '''empty :'''
119 pass
120
121 def p_field_modifier(self,p):
122 '''field_modifier : REQUIRED
123 | OPTIONAL
124 | REPEATED'''
Dusan Klinecaa9ff472014-11-10 18:02:03 +0100125 p[0] = LU.i(p,1)
Dusan Klinecccaa0d92014-11-09 03:21:31 +0100126
127 def p_primitive_type(self, p):
128 '''primitive_type : DOUBLE
129 | FLOAT
130 | INT32
131 | INT64
132 | UINT32
133 | UINT64
134 | SINT32
135 | SINT64
136 | FIXED32
137 | FIXED64
138 | SFIXED32
139 | SFIXED64
140 | BOOL
141 | STRING
142 | BYTES'''
Dusan Klinecaa9ff472014-11-10 18:02:03 +0100143 p[0] = LU.i(p,1)
Dusan Klinecccaa0d92014-11-09 03:21:31 +0100144
Sapan Bhatiab1225872017-03-29 20:47:47 +0200145 def p_link_type(self, p):
146 '''link_type : ONETOONE
147 | MANYTOONE
148 | MANYTOMANY'''
149 p[0] = LU.i(p,1)
150
Dusan Klinecccaa0d92014-11-09 03:21:31 +0100151 def p_field_id(self, p):
152 '''field_id : NUM'''
Dusan Klinecaa9ff472014-11-10 18:02:03 +0100153 p[0] = LU.i(p,1)
Dusan Klinecccaa0d92014-11-09 03:21:31 +0100154
155 def p_rvalue(self, p):
156 '''rvalue : NUM
157 | TRUE
158 | FALSE'''
Dusan Klinecaa9ff472014-11-10 18:02:03 +0100159 p[0] = LU.i(p,1)
Dusan Klinecccaa0d92014-11-09 03:21:31 +0100160
Sapan Bhatiab1225872017-03-29 20:47:47 +0200161 def p_rvalue3(self, p):
162 '''rvalue : STRING_LITERAL'''
163 p[0] = Name(LU.i(p, 1))
164 self.lh.set_parse_object(p[0], p)
165 p[0].deriveLex()
166
Dusan Klinecccaa0d92014-11-09 03:21:31 +0100167 def p_rvalue2(self, p):
168 '''rvalue : NAME'''
Dusan Klinecaa9ff472014-11-10 18:02:03 +0100169 p[0] = Name(LU.i(p, 1))
170 self.lh.set_parse_object(p[0], p)
171 p[0].deriveLex()
Dusan Klinecccaa0d92014-11-09 03:21:31 +0100172
Sapan Bhatiab1225872017-03-29 20:47:47 +0200173 def p_field_directives2(self, p):
174 '''field_directives : empty'''
175 p[0] = []
176
177 def p_field_directives(self, p):
178 '''field_directives : LBRACK field_directive_times RBRACK'''
179 p[0] = p[2]
180 #self.lh.set_parse_object(p[0], p)
181
Dusan Klinecccaa0d92014-11-09 03:21:31 +0100182 def p_field_directive(self, p):
Sapan Bhatiab1225872017-03-29 20:47:47 +0200183 '''field_directive : NAME EQ rvalue'''
184 p[0] = FieldDirective(Name(LU.i(p, 1)), LU.i(p, 3))
Dusan Klinecaa9ff472014-11-10 18:02:03 +0100185 self.lh.set_parse_object(p[0], p)
Dusan Klinecccaa0d92014-11-09 03:21:31 +0100186
Sapan Bhatiaa3686022017-06-24 07:24:19 -0700187 def p_policy_opt_explicit(self, p):
188 '''policy_opt : DOUBLECOLON NAME'''
189 p[0] = p[2]
190
Sapan Bhatiaa3686022017-06-24 07:24:19 -0700191 def p_policy_opt_empty(self, p):
192 '''policy_opt : empty'''
193 p[0] = None
Sapan Bhatia87792a12017-04-10 19:35:05 -0700194
195 def p_csv_expr(self, p):
196 '''csv_expr : LPAR csv RPAR'''
197 p[0] = p[2]
198
199 def p_csv_expr2(self, p):
200 '''csv_expr : empty'''
201 p[0] = []
202
203 def p_csv2(self, p):
204 '''csv : empty'''
205
206 def p_csv(self, p):
Sapan Bhatia2ddf83a2017-06-10 04:31:40 -0700207 '''csv : dotname
208 | csv COMMA dotname'''
Sapan Bhatia87792a12017-04-10 19:35:05 -0700209
210 if len(p) == 2:
211 p[0] = [LU(p,1)]
212 else:
213 p[0] = p[1] + [LU(p,3)]
214
Dusan Klinecccaa0d92014-11-09 03:21:31 +0100215 def p_field_directive_times(self, p):
216 '''field_directive_times : field_directive_plus'''
217 p[0] = p[1]
218
219 def p_field_directive_times2(self, p):
220 '''field_directive_times : empty'''
221 p[0] = []
222
223 def p_field_directive_plus(self, p):
224 '''field_directive_plus : field_directive
Sapan Bhatiab1225872017-03-29 20:47:47 +0200225 | field_directive_plus COMMA field_directive'''
Dusan Klinecccaa0d92014-11-09 03:21:31 +0100226 if len(p) == 2:
Dusan Klineca9f6d362014-11-10 21:07:08 +0100227 p[0] = [LU(p,1)]
Dusan Klinecccaa0d92014-11-09 03:21:31 +0100228 else:
Sapan Bhatiab1225872017-03-29 20:47:47 +0200229 p[0] = p[1] + [LU(p,3)]
Dusan Klinecccaa0d92014-11-09 03:21:31 +0100230
Dusan Klineca4fae112014-11-10 08:50:27 +0100231 def p_dotname(self, p):
232 '''dotname : NAME
233 | dotname DOT NAME'''
Dusan Klinecaa9ff472014-11-10 18:02:03 +0100234 if len(p) == 2:
235 p[0] = [LU(p,1)]
236 else:
237 p[0] = p[1] + [LU(p,3)]
Dusan Klineca4fae112014-11-10 08:50:27 +0100238
239 # Hack for cases when there is a field named 'message' or 'max'
240 def p_fieldName(self, p):
Sapan Bhatia78fee772017-04-21 19:00:48 +0200241 '''field_name : STARTTOKEN
242 | NAME
Dusan Klineca4fae112014-11-10 08:50:27 +0100243 | MESSAGE
244 | MAX'''
Dusan Klinecaa9ff472014-11-10 18:02:03 +0100245 p[0] = Name(LU.i(p,1))
246 self.lh.set_parse_object(p[0], p)
247 p[0].deriveLex()
Dusan Klineca4fae112014-11-10 08:50:27 +0100248
Dusan Klinecccaa0d92014-11-09 03:21:31 +0100249 def p_field_type(self, p):
250 '''field_type : primitive_type'''
Dusan Klinecaa9ff472014-11-10 18:02:03 +0100251 p[0] = FieldType(LU.i(p,1))
252 self.lh.set_parse_object(p[0], p)
Dusan Klinecccaa0d92014-11-09 03:21:31 +0100253
254 def p_field_type2(self, p):
Dusan Klineca4fae112014-11-10 08:50:27 +0100255 '''field_type : dotname'''
Dusan Klinecaa9ff472014-11-10 18:02:03 +0100256 p[0] = DotName(LU.i(p, 1))
257 self.lh.set_parse_object(p[0], p)
258 p[0].deriveLex()
Dusan Klinecccaa0d92014-11-09 03:21:31 +0100259
Sapan Bhatia78fee772017-04-21 19:00:48 +0200260 def p_slash_name(self, p):
Sapan Bhatia2ddf83a2017-06-10 04:31:40 -0700261 '''slash_name : SLASH dotname'''
Sapan Bhatia78fee772017-04-21 19:00:48 +0200262 p[0] = p[2]
263 #self.lh.set_parse_object(p[0], p)
264
265 def p_slash_name2(self, p):
266 '''slash_name : empty'''
267 p[0] = None
268
Sapan Bhatiab1225872017-03-29 20:47:47 +0200269 def p_colon_fieldname(self, p):
270 '''colon_fieldname : COLON field_name'''
271 p[0] = p[2]
272 self.lh.set_parse_object(p[0], p)
273
274 def p_colon_fieldname2(self, p):
275 '''colon_fieldname : empty'''
276 p[0] = None
277
278 # TODO: Add directives to link definition
279 def p_link_definition(self, p):
Sapan Bhatiad70c3782017-06-28 22:47:22 -0700280 '''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 +0200281 p[0] = LinkSpec(
Sapan Bhatiad70c3782017-06-28 22:47:22 -0700282 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)),
283 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 +0200284
285 self.lh.set_parse_object(p[0], p)
286
Dusan Klinecccaa0d92014-11-09 03:21:31 +0100287 # Root of the field declaration.
288 def p_field_definition(self, p):
Sapan Bhatiaa3686022017-06-24 07:24:19 -0700289 '''field_definition : field_modifier field_type field_name policy_opt EQ field_id field_directives SEMI'''
290 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 +0100291 self.lh.set_parse_object(p[0], p)
Dusan Klinecccaa0d92014-11-09 03:21:31 +0100292
293 # Root of the enum field declaration.
294 def p_enum_field(self, p):
Dusan Klineca4fae112014-11-10 08:50:27 +0100295 '''enum_field : field_name EQ NUM SEMI'''
Dusan Klinecaa9ff472014-11-10 18:02:03 +0100296 p[0] = EnumFieldDefinition(LU.i(p, 1), LU.i(p,3))
297 self.lh.set_parse_object(p[0], p)
Dusan Klinecccaa0d92014-11-09 03:21:31 +0100298
299 def p_enum_body_part(self, p):
300 '''enum_body_part : enum_field
301 | option_directive'''
302 p[0] = p[1]
303
304 def p_enum_body(self, p):
305 '''enum_body : enum_body_part
306 | enum_body enum_body_part'''
307 if len(p) == 2:
308 p[0] = [p[1]]
309 else:
310 p[0] = p[1] + [p[2]]
311
312 def p_enum_body_opt(self, p):
313 '''enum_body_opt : empty'''
314 p[0] = []
315
316 def p_enum_body_opt2(self, p):
317 '''enum_body_opt : enum_body'''
318 p[0] = p[1]
319
Sapan Bhatiaad79fee2017-06-26 23:35:57 -0700320 def p_reduce_definition(self, p):
321 '''reduce_definition : REDUCE NAME POLICYBODY'''
322 ltxt = p[3].lstrip('<').rstrip('>')
323 l = ast.parse(ltxt).body[0]
324 if not isinstance(l, ast.Expr):
325 raise PythonError("reduce operator needs to be an expression")
326 elif not isinstance(l.value, ast.Lambda):
327 raise PythonError("reduce operator needs to be a lambda")
328
329 p[0] = ReduceDefinition(Name(LU.i(p, 2)), ltxt)
330 self.lh.set_parse_object(p[0], p)
331
332 def p_map_definition(self, p):
333 '''map_definition : MAP NAME POLICYBODY'''
334 ltxt = p[3].lstrip('<').rstrip('>')
335 l = ast.parse(ltxt).body[0]
336 if not isinstance(l, ast.Expr):
337 raise PythonError("map operator needs to be an expression")
338 elif not isinstance(l.value, ast.Lambda):
339 raise PythonError("map operator needs to be a lambda")
340
341 p[0] = MapDefinition(Name(LU.i(p, 2)), ltxt)
342 self.lh.set_parse_object(p[0], p)
343
Sapan Bhatia64c72512017-06-23 02:32:45 -0700344 def p_policy_definition(self, p):
345 '''policy_definition : POLICY NAME POLICYBODY'''
Sapan Bhatia9c579722018-01-12 13:45:09 -0500346 try:
347 fol = self.fol_parser.parse(p[3], lexer = self.fol_lexer)
348 except FOLParsingError, e:
349 lineno, lexpos, length = e.error_range
350 raise ParsingError("Policy parsing error in policy %s"%p[2], (p.lineno(3) + lineno,lexpos + p.lexpos(3), length))
Sapan Bhatia64c72512017-06-23 02:32:45 -0700351 p[0] = PolicyDefinition(Name(LU.i(p, 2)), fol)
352 self.lh.set_parse_object(p[0], p)
353
Dusan Klinecccaa0d92014-11-09 03:21:31 +0100354 # Root of the enum declaration.
355 # enum_definition ::= 'enum' ident '{' { ident '=' integer ';' }* '}'
356 def p_enum_definition(self, p):
357 '''enum_definition : ENUM NAME LBRACE enum_body_opt RBRACE'''
Dusan Klinecaa9ff472014-11-10 18:02:03 +0100358 p[0] = EnumDefinition(Name(LU.i(p, 2)), LU.i(p,4))
359 self.lh.set_parse_object(p[0], p)
Dusan Klinecccaa0d92014-11-09 03:21:31 +0100360
361 def p_extensions_to(self, p):
362 '''extensions_to : MAX'''
363 p[0] = ExtensionsMax()
Dusan Klinecaa9ff472014-11-10 18:02:03 +0100364 self.lh.set_parse_object(p[0], p)
Dusan Klinecccaa0d92014-11-09 03:21:31 +0100365
366 def p_extensions_to2(self, p):
367 '''extensions_to : NUM'''
Dusan Klinecaa9ff472014-11-10 18:02:03 +0100368 p[0] = LU.i(p, 1)
Dusan Klinecccaa0d92014-11-09 03:21:31 +0100369
370 # extensions_definition ::= 'extensions' integer 'to' integer ';'
371 def p_extensions_definition(self, p):
372 '''extensions_definition : EXTENSIONS NUM TO extensions_to SEMI'''
Dusan Klinecaa9ff472014-11-10 18:02:03 +0100373 p[0] = ExtensionsDirective(LU.i(p,2), LU.i(p,4))
374 self.lh.set_parse_object(p[0], p)
Dusan Klinecccaa0d92014-11-09 03:21:31 +0100375
376 # message_extension ::= 'extend' ident '{' message_body '}'
377 def p_message_extension(self, p):
378 '''message_extension : EXTEND NAME LBRACE message_body RBRACE'''
Dusan Klinecaa9ff472014-11-10 18:02:03 +0100379 p[0] = MessageExtension(Name(LU.i(p, 2)), LU.i(p,4))
380 self.lh.set_parse_object(p[0], p)
Dusan Klinecccaa0d92014-11-09 03:21:31 +0100381
382 def p_message_body_part(self, p):
383 '''message_body_part : field_definition
Sapan Bhatiab1225872017-03-29 20:47:47 +0200384 | link_definition
Dusan Klinecccaa0d92014-11-09 03:21:31 +0100385 | enum_definition
Sapan Bhatia4a159ac2017-04-29 20:10:05 +0200386 | option_directive
Dusan Klinecccaa0d92014-11-09 03:21:31 +0100387 | message_definition
388 | extensions_definition
389 | message_extension'''
390 p[0] = p[1]
391
392 # message_body ::= { field_definition | enum_definition | message_definition | extensions_definition | message_extension }*
393 def p_message_body(self, p):
394 '''message_body : empty'''
395 p[0] = []
396
397 # message_body ::= { field_definition | enum_definition | message_definition | extensions_definition | message_extension }*
398 def p_message_body2(self, p):
399 '''message_body : message_body_part
400 | message_body message_body_part'''
401 if len(p) == 2:
402 p[0] = [p[1]]
403 else:
404 p[0] = p[1] + [p[2]]
405
406 # Root of the message declaration.
407 # message_definition = MESSAGE_ - ident("messageId") + LBRACE + message_body("body") + RBRACE
408 def p_message_definition(self, p):
Sapan Bhatiaa3686022017-06-24 07:24:19 -0700409 '''message_definition : MESSAGE NAME policy_opt csv_expr LBRACE message_body RBRACE'''
410 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 +0100411 self.lh.set_parse_object(p[0], p)
Dusan Klinecccaa0d92014-11-09 03:21:31 +0100412
413 # method_definition ::= 'rpc' ident '(' [ ident ] ')' 'returns' '(' [ ident ] ')' ';'
414 def p_method_definition(self, p):
415 '''method_definition : RPC NAME LPAR NAME RPAR RETURNS LPAR NAME RPAR'''
Dusan Klinecaa9ff472014-11-10 18:02:03 +0100416 p[0] = MethodDefinition(Name(LU.i(p, 2)), Name(LU.i(p, 4)), Name(LU.i(p, 8)))
417 self.lh.set_parse_object(p[0], p)
Dusan Klinecccaa0d92014-11-09 03:21:31 +0100418
419 def p_method_definition_opt(self, p):
420 '''method_definition_opt : empty'''
421 p[0] = []
422
423 def p_method_definition_opt2(self, p):
424 '''method_definition_opt : method_definition
425 | method_definition_opt method_definition'''
426 if len(p) == 2:
427 p[0] = [p[1]]
428 else:
429 p[0] = p[1] + [p[2]]
430
431 # service_definition ::= 'service' ident '{' method_definition* '}'
432 # service_definition = SERVICE_ - ident("serviceName") + LBRACE + ZeroOrMore(Group(method_definition)) + RBRACE
433 def p_service_definition(self, p):
Sapan Bhatiab1225872017-03-29 20:47:47 +0200434 '''service_definition : _SERVICE NAME LBRACE method_definition_opt RBRACE'''
Dusan Klinecaa9ff472014-11-10 18:02:03 +0100435 p[0] = ServiceDefinition(Name(LU.i(p, 2)), LU.i(p,4))
436 self.lh.set_parse_object(p[0], p)
Dusan Klinecccaa0d92014-11-09 03:21:31 +0100437
438 # package_directive ::= 'package' ident [ '.' ident]* ';'
439 def p_package_directive(self,p):
Dusan Klineca4fae112014-11-10 08:50:27 +0100440 '''package_directive : PACKAGE dotname SEMI'''
Dusan Klinecaa9ff472014-11-10 18:02:03 +0100441 p[0] = PackageStatement(Name(LU.i(p, 2)))
442 self.lh.set_parse_object(p[0], p)
Dusan Klinecccaa0d92014-11-09 03:21:31 +0100443
444 # import_directive = IMPORT_ - quotedString("importFileSpec") + SEMI
445 def p_import_directive(self, p):
446 '''import_directive : IMPORT STRING_LITERAL SEMI'''
Dusan Klinecaa9ff472014-11-10 18:02:03 +0100447 p[0] = ImportStatement(Literal(LU.i(p,2)))
448 self.lh.set_parse_object(p[0], p)
Dusan Klinecccaa0d92014-11-09 03:21:31 +0100449
450 def p_option_rvalue(self, p):
451 '''option_rvalue : NUM
452 | TRUE
453 | FALSE'''
Dusan Klinecaa9ff472014-11-10 18:02:03 +0100454 p[0] = LU(p, 1)
Dusan Klinecccaa0d92014-11-09 03:21:31 +0100455
456 def p_option_rvalue2(self, p):
457 '''option_rvalue : STRING_LITERAL'''
Dusan Klinecaa9ff472014-11-10 18:02:03 +0100458 p[0] = Literal(LU(p,1))
459
460 def p_option_rvalue3(self, p):
461 '''option_rvalue : NAME'''
462 p[0] = Name(LU.i(p,1))
Dusan Klinecccaa0d92014-11-09 03:21:31 +0100463
464 # option_directive = OPTION_ - ident("optionName") + EQ + quotedString("optionValue") + SEMI
465 def p_option_directive(self, p):
466 '''option_directive : OPTION NAME EQ option_rvalue SEMI'''
Dusan Klinecaa9ff472014-11-10 18:02:03 +0100467 p[0] = OptionStatement(Name(LU.i(p, 2)), LU.i(p,4))
468 self.lh.set_parse_object(p[0], p)
Dusan Klinecccaa0d92014-11-09 03:21:31 +0100469
Sapan Bhatiaff86b012017-06-11 14:44:15 -0700470 # topLevelStatement = Group(message_definition | message_extension | enum_definition | service_definition | import_directive | option_directive | package_definition)
Dusan Klinecccaa0d92014-11-09 03:21:31 +0100471 def p_topLevel(self,p):
472 '''topLevel : message_definition
473 | message_extension
474 | enum_definition
Sapan Bhatia64c72512017-06-23 02:32:45 -0700475 | policy_definition
Sapan Bhatia89bbaa52017-06-28 22:58:15 -0700476 | map_definition
477 | reduce_definition
Dusan Klinecccaa0d92014-11-09 03:21:31 +0100478 | service_definition
479 | import_directive
Sapan Bhatiaff86b012017-06-11 14:44:15 -0700480 | package_directive
Dusan Klinecccaa0d92014-11-09 03:21:31 +0100481 | option_directive'''
482 p[0] = p[1]
483
Dusan Klinecccaa0d92014-11-09 03:21:31 +0100484 def p_statements2(self, p):
485 '''statements : topLevel
486 | statements topLevel'''
487 if len(p) == 2:
488 p[0] = [p[1]]
489 else:
490 p[0] = p[1] + [p[2]]
491
492 def p_statements(self, p):
493 '''statements : empty'''
494 p[0] = []
495
496 # parser = Optional(package_directive) + ZeroOrMore(topLevelStatement)
Dusan Klinecc9b031a2014-11-10 13:21:08 +0100497 def p_protofile(self, p):
Sapan Bhatiaff86b012017-06-11 14:44:15 -0700498 '''protofile : statements'''
499 p[0] = ProtoFile(LU.i(p,1))
Dusan Klinecaa9ff472014-11-10 18:02:03 +0100500 self.lh.set_parse_object(p[0], p)
Dusan Klinecc9b031a2014-11-10 13:21:08 +0100501
502 # Parsing starting point
503 def p_goal(self, p):
Dusan Klinecaa9ff472014-11-10 18:02:03 +0100504 '''goal : STARTTOKEN protofile'''
Dusan Klinecc9b031a2014-11-10 13:21:08 +0100505 p[0] = p[2]
Dusan Klinecccaa0d92014-11-09 03:21:31 +0100506
507 def p_error(self, p):
Sapan Bhatia9c579722018-01-12 13:45:09 -0500508 raise ParsingError("Parsing Error", (p.lineno,p.lexpos,len(p.value)))
Dusan Klinecccaa0d92014-11-09 03:21:31 +0100509
510class ProtobufAnalyzer(object):
511
512 def __init__(self):
Sapan Bhatia9c579722018-01-12 13:45:09 -0500513 self.lexer = lex.lex(module=ProtobufLexer())
514 self.parser = yacc.yacc(module=ProtobufParser(), start='goal', debug=0, outputdir='/tmp')
Dusan Klinecccaa0d92014-11-09 03:21:31 +0100515
516 def tokenize_string(self, code):
517 self.lexer.input(code)
518 for token in self.lexer:
519 print(token)
520
521 def tokenize_file(self, _file):
522 if type(_file) == str:
523 _file = file(_file)
524 content = ''
525 for line in _file:
526 content += line
527 return self.tokenize_string(content)
528
Dusan Klinecaa9ff472014-11-10 18:02:03 +0100529 def parse_string(self, code, debug=0, lineno=1, prefix='+'):
Dusan Klinecccaa0d92014-11-09 03:21:31 +0100530 self.lexer.lineno = lineno
Dusan Klinecaa9ff472014-11-10 18:02:03 +0100531 self.parser.offset = len(prefix)
Dusan Klinecccaa0d92014-11-09 03:21:31 +0100532 return self.parser.parse(prefix + code, lexer=self.lexer, debug=debug)
533
534 def parse_file(self, _file, debug=0):
535 if type(_file) == str:
536 _file = file(_file)
537 content = ''
538 for line in _file:
539 content += line
540 return self.parse_string(content, debug=debug)