blob: e5c875a4117c818d55e0e542c2346b919dd6695f [file] [log] [blame]
Marc Slemkoc0e07a22006-08-09 23:34:57 +00001#!python
Marc Slemkob2039e72006-08-09 01:00:17 +00002""" Thrift IDL parser/compiler
3
4 This parser uses the Python PLY LALR parser generator to build a parser for the Thrift IDL grammar.
5
6 If a compiles \"thyc\" file exists for a given source \"thrift\" file it computes a hash of the file and determines
7 if if it is the source of the \"thyc\" file. If so, it simply returns the parse tree previously computed, otherwise it
8 parses the source and generates a new \"thyc\" file (assuming of course the source file contains no errors.)
9
10 When the parser encounters import statements it searches for corresponding \"thrift\" or \"thyc\" files in paths corresponding to
11 the specified namespace.
12
13 Author(s): Mark Slee(mclee@facebook.com), Marc Kwiatkowski (marc@facebook.com)
14
15 $Id:
16"""
17
18import lex
19import os
20import pickle
21import string
Marc Slemkob2039e72006-08-09 01:00:17 +000022import yacc
23
24class Error(object):
25
26 def __init__(self, start=0, end=0, message=""):
27 if len(message) == 0:
28 raise Exception, "NO MESSAGE"
29 self.message = message
30 self.start = start
31 self.end = end
32
33 def __str__(self):
34 return str(self.start)+": error: "+self.message
35
36class SyntaxError(Error):
Marc Slemko27340eb2006-08-10 20:45:55 +000037 def __init__(self, yaccSymbol):
38 if isinstance(yaccSymbol, yacc.YaccSymbol):
39 Error.__init__(self, yaccSymbol.lineno, yaccSymbol.lineno, "syntax error "+str(yaccSymbol.value))
40 else:
41 Error.__init__(self, 1, 1, "syntax error "+str(yaccSymbol))
Marc Slemkob2039e72006-08-09 01:00:17 +000042
43class SymanticsError(Error):
44
45 def __init__(self, definition, message):
46 Error.__init__(self, definition.start, definition.end, message)
47 self.definition = definition
48
49 def __str__(self):
50 return str(self.start)+": error: "+self.message
51
52class ErrorException(Exception):
53
54 def __init__(self, errors=None):
55 self.errors = errors
56
57class Definition(object):
58 """ Abstract thrift IDL definition unit """
59
60 def __init__(self, symbols=None, name="", id=None):
61 if symbols:
62 self.lines(symbols)
63 self.name = name
64 self.id = id
65
66 def validate(self):
67 pass
68
69 def lines(self, symbols):
70 self.start = symbols.lineno(1)
71 self.end = symbols.lineno(len(symbols) - 1)
72
73class Identifier(Definition):
74 """ An Identifier - name and optional integer id """
75
76 def __init__(self, symbols, name, id=None):
77 Definition.__init__(self, symbols, name, id)
78
79 def __str__(self):
80 result = self.name
81 if self.id != 0:
82 result+="="+str(self.id)
83 return result
84
Marc Slemko27340eb2006-08-10 20:45:55 +000085
86def toCanonicalType(ttype):
Marc Slemko5b126d62006-08-11 23:03:42 +000087 if isinstance(ttype, TypedefType):
Marc Slemko27340eb2006-08-10 20:45:55 +000088 return toCanonicalType(ttype.definitionType)
89 else:
90 return ttype
91
92def isComparableType(ttype):
93 ttype = toCanonicalType(ttype)
Marc Slemko5b126d62006-08-11 23:03:42 +000094 return isinstance(ttype, PrimitiveType) or isinstance(ttype, EnumType)
Marc Slemko27340eb2006-08-10 20:45:55 +000095
Marc Slemkob2039e72006-08-09 01:00:17 +000096class Type(Definition):
97 """ Abstract Type definition """
98
99 def __init__(self, symbols, name):
100 Definition.__init__(self, symbols, name)
101 self.name = name
102
103 def __str__(self):
104 return self.name
105
Marc Slemko5b126d62006-08-11 23:03:42 +0000106class TypedefType(Type):
Marc Slemkob2039e72006-08-09 01:00:17 +0000107
108 def __init__(self, symbols, name, definitionType):
109 Type.__init__(self, symbols, name)
110 self.definitionType = definitionType
111
112 def __str__(self):
113 return self.name+"<"+str(self.name)+", "+str(self.definitionType)+">"
114
115""" Primitive Types """
116
117class PrimitiveType(Type):
118
119 def __init__(self, name):
120 Type.__init__(self, None, name)
121
Marc Slemkoc0e07a22006-08-09 23:34:57 +0000122STOP_TYPE = PrimitiveType("stop")
Marc Slemkob2039e72006-08-09 01:00:17 +0000123VOID_TYPE = PrimitiveType("void")
124BOOL_TYPE = PrimitiveType("bool")
125STRING_TYPE =PrimitiveType("utf7")
126UTF7_TYPE = PrimitiveType("utf7")
127UTF8_TYPE = PrimitiveType("utf8")
128UTF16_TYPE = PrimitiveType("utf16")
129BYTE_TYPE = PrimitiveType("u08")
130I08_TYPE = PrimitiveType("i08")
131I16_TYPE = PrimitiveType("i16")
132I32_TYPE = PrimitiveType("i32")
133I64_TYPE = PrimitiveType("i64")
134U08_TYPE = PrimitiveType("u08")
135U16_TYPE = PrimitiveType("u16")
136U32_TYPE = PrimitiveType("u32")
137U64_TYPE = PrimitiveType("u64")
138FLOAT_TYPE = PrimitiveType("float")
139
140PRIMITIVE_MAP = {
Marc Slemkoc0e07a22006-08-09 23:34:57 +0000141 "stop" : STOP_TYPE,
Marc Slemkob2039e72006-08-09 01:00:17 +0000142 "void" : VOID_TYPE,
143 "bool" : BOOL_TYPE,
144 "string": UTF7_TYPE,
145 "utf7": UTF7_TYPE,
146 "utf8": UTF8_TYPE,
147 "utf16": UTF16_TYPE,
148 "byte" : U08_TYPE,
149 "i08": I08_TYPE,
150 "i16": I16_TYPE,
151 "i32": I32_TYPE,
152 "i64": I64_TYPE,
153 "u08": U08_TYPE,
154 "u16": U16_TYPE,
155 "u32": U32_TYPE,
156 "u64": U64_TYPE,
157 "float": FLOAT_TYPE
158}
159
160""" Collection Types """
161
162class CollectionType(Type):
163
164 def __init__(self, symbols, name):
165 Type.__init__(self, symbols, name)
166
Marc Slemko27340eb2006-08-10 20:45:55 +0000167 def validate(self):
168 return True
169
Marc Slemko5b126d62006-08-11 23:03:42 +0000170class MapType(CollectionType):
Marc Slemkob2039e72006-08-09 01:00:17 +0000171
172 def __init__(self, symbols, keyType, valueType):
173 CollectionType.__init__(self, symbols, "map<"+keyType.name+","+valueType.name +">")
174 self.keyType = keyType
175 self.valueType = valueType
176
Marc Slemko27340eb2006-08-10 20:45:55 +0000177 def validate(self):
178 if not isComparableType(self.keyType):
179 raise ErrorException([SymanticsError(self, "key type \""+str(self.keyType)+"\" is not a comparable type.")])
180
Marc Slemko5b126d62006-08-11 23:03:42 +0000181class SetType(CollectionType):
Marc Slemkob2039e72006-08-09 01:00:17 +0000182
183 def __init__(self, symbols, valueType):
184 CollectionType.__init__(self, symbols, "set<"+valueType.name+">")
185 self.valueType = valueType
186
Marc Slemko27340eb2006-08-10 20:45:55 +0000187 def validate(self):
188 if not isComparableType(self.valueType):
189 raise ErrorException([SymanticsError(self, "value type \""+str(self.valueType)+"\" is not a comparable type.")])
190
Marc Slemko5b126d62006-08-11 23:03:42 +0000191class ListType(CollectionType):
Marc Slemkob2039e72006-08-09 01:00:17 +0000192
193 def __init__(self, symbols, valueType):
194 CollectionType.__init__(self, symbols, "list<"+valueType.name+">")
195 self.valueType = valueType
196
Marc Slemko5b126d62006-08-11 23:03:42 +0000197class EnumType(Definition):
Marc Slemkob2039e72006-08-09 01:00:17 +0000198
199 def __init__(self, symbols, name, enumDefs):
200 Definition.__init__(self, symbols, name)
201 self.enumDefs = enumDefs
202
203 def validate(self):
204 ids = {}
205 names = {}
206 errors = []
207
208 for enumDef in self.enumDefs:
209
210 if enumDef.name in names:
211 errors.append(SymanticsError(enumDef, self.name+"."+str(enumDef.name)+" already defined at line "+str(names[enumDef.name].start)))
212 else:
213 names[enumDef.name] = enumDef
214
215 if enumDef.id != None:
216 oldEnumDef = ids.get(enumDef.id)
217 if oldEnumDef:
218 errors.append(SymanticsError(enumDef, "enum "+self.name+" \""+str(enumDef.name)+"\" uses constant already assigned to \""+oldEnumDef.name+"\""))
219 else:
220 ids[enumDef.id] = enumDef
221
222 if len(errors):
223 raise ErrorException(errors)
224
225 def assignId(enumDef, currentId, ids):
226 'Finds the next available id number for an enum definition'
227
228 id= currentId + 1
229
230 while id in ids:
231 id += 1
232
233 enumDef.id = id
234
235 ids[enumDef.id] = enumDef
236
237 # assign ids for all enum defs with unspecified ids
238
239 currentId = 0
240
241 for enumDef in self.enumDefs:
242 if not enumDef.id:
243 assignId(enumDef, currentId, ids)
244 currentId = enumDef.id
245
246 def __repr__(self):
247 return str(self)
248
249 def __str__(self):
250 return self.name+"<"+string.join(map(lambda enumDef: str(enumDef), self.enumDefs), ", ")
251
252class EnumDef(Definition):
253
254 def __init__(self, symbols, name, id=None):
255 Definition.__init__(self, symbols, name, id)
256
257 def __repr__(self):
258 return str(self)
259
260 def __str__(self):
261 result = self.name
262 if self.id:
263 result+= ":"+str(self.id)
264 return result
265
266
267class Field(Definition):
268
269 def __init__(self, symbols, type, identifier):
270 Definition.__init__(self, symbols, identifier.name, identifier.id)
271 self.type = type
272 self.identifier = identifier
273
274 def __str__(self):
275 return "<"+str(self.type)+", "+str(self.identifier)+">"
276
277def validateFieldList(fieldList):
278
279 errors = []
280 names = {}
281 ids = {}
282
283 for field in fieldList:
284
285 if field.name in names:
286 oldField = names[field.name]
287 errors.append(SymanticsError(field, "field \""+field.name+"\" already defined at "+str(oldField.start)))
288 else:
289 names[field.name] = field
290
291 if field.id != None:
292 oldField = ids.get(field.id)
293 if oldField:
294 errors.append(SymanticsError(field, "field \""+field.name+"\" uses constant already assigned to \""+oldField.name+"\""))
295 else:
296 ids[field.id] = field
297
298 if len(errors):
299 raise ErrorException(errors)
300
Marc Slemkoc0e07a22006-08-09 23:34:57 +0000301 def assignId(field, currentId, ids):
302 'Finds the next available id number for a field'
Marc Slemko0b4ffa92006-08-11 02:49:29 +0000303 id = currentId - 1
Marc Slemkoc0e07a22006-08-09 23:34:57 +0000304
305 while id in ids:
Marc Slemko0b4ffa92006-08-11 02:49:29 +0000306 id-= 1
Marc Slemkoc0e07a22006-08-09 23:34:57 +0000307
308 field.id = id
309
310 ids[field.id] = field
311
312 return id
313
314 # assign ids for all fields with unspecified ids
315
316 currentId = 0
317
Marc Slemko0b4ffa92006-08-11 02:49:29 +0000318 for field in fieldList:
Marc Slemkoc0e07a22006-08-09 23:34:57 +0000319 if not field.id:
320 currentId = assignId(field, currentId, ids)
321
Marc Slemko5b126d62006-08-11 23:03:42 +0000322class StructType(Type):
Marc Slemkob2039e72006-08-09 01:00:17 +0000323
324 def __init__(self, symbols, name, fieldList):
325 Type.__init__(self, symbols, name)
326 self.fieldList = fieldList
327
328 def validate(self):
329 validateFieldList(self.fieldList)
330
331 def __str__(self):
332 return self.name+"<"+string.join(map(lambda a: str(a), self.fieldList), ", ")+">"
333
334class Function(Definition):
335
Marc Slemko5b126d62006-08-11 23:03:42 +0000336 def __init__(self, symbols, name, resultStruct, argsStruct, ):
Marc Slemkob2039e72006-08-09 01:00:17 +0000337 Definition.__init__(self, symbols, name)
Marc Slemko5b126d62006-08-11 23:03:42 +0000338 self.resultStruct = resultStruct
Marc Slemko0b4ffa92006-08-11 02:49:29 +0000339 self.argsStruct = argsStruct
Marc Slemkob2039e72006-08-09 01:00:17 +0000340
341 def validate(self):
Marc Slemko0b4ffa92006-08-11 02:49:29 +0000342 validateFieldList(self.argsStruct.fieldList)
Marc Slemko5b126d62006-08-11 23:03:42 +0000343
344 def args(self):
345 return self.argsStruct.fieldList
346
347 def returnType(self):
348 return self.resultStruct.fieldList[0].type
Marc Slemkob2039e72006-08-09 01:00:17 +0000349
350 def __str__(self):
Marc Slemko5b126d62006-08-11 23:03:42 +0000351 return self.name+"("+string.join(map(lambda a: str(a), self.argsStruct), ", ")+") => "+str(self.resultStruct)
Marc Slemkob2039e72006-08-09 01:00:17 +0000352
353class Service(Definition):
354
355 def __init__(self, symbols, name, functionList):
356 Definition.__init__(self, symbols, name)
357 self.functionList = functionList
358
359 def validate(self):
360
361 errors = []
362 functionNames = {}
363 for function in self.functionList:
364 if function.name in functionNames:
365 oldFunction = functionName[function.name]
366 errors.append(SymanticsError(function, "function "+function.name+" already defined at "+str(oldFunction.start)))
367
368 if len(errors):
369 raise ErrorException(errors)
370
371 def __str__(self):
372 return self.name+"("+string.join(map(lambda a: str(a), self.functionList), ", ")+")"
373
374class Program(object):
375
376 def __init__(self, symbols=None, name="", definitions=None, serviceMap=None, typedefMap=None, enumMap=None, structMap=None, collectionMap=None,
377 primitiveMap=None):
378
379 self.name = name
380
381 if not definitions:
382 definitions = []
383 self.definitions = definitions
384
385 if not serviceMap:
386 serviceMap = {}
387 self.serviceMap = serviceMap
388
389 if not typedefMap:
390 typedefMap = {}
391 self.typedefMap = typedefMap
392
393 if not enumMap:
394 enumMap = {}
395 self.enumMap = enumMap
396
397 if not structMap:
398 structMap = {}
399 self.structMap = structMap
400
401 if not collectionMap:
402 collectionMap = {}
403 self.collectionMap = collectionMap
404
405 if not primitiveMap:
406 primitiveMap = PRIMITIVE_MAP
407 self.primitiveMap = primitiveMap
408
409 def addDefinition(self, definition, definitionMap, definitionTypeName):
410
411 oldDefinition = definitionMap.get(definition.name)
412 if oldDefinition:
413 raise ErrorException([SymanticsError(definition, definitionTypeName+" "+definition.name+" is already defined at "+str(oldDefinition.start))])
414 else:
415 definitionMap[definition.name] = definition
416
417 # keep an ordered list of definitions so that stub/skel generators can determine the original order
418
419 self.definitions.append(definition)
420
421 def addStruct(self, struct):
422 self.addDefinition(struct, self.structMap, "struct")
423
424 def addTypedef(self, typedef):
425 self.addDefinition(typedef, self.typedefMap, "typedef")
426
427 def addEnum(self, enum):
428 self.addDefinition(enum, self.enumMap, "enum")
429
430 def addService(self, service):
431 self.addDefinition(service, self.serviceMap, "service")
432
433 def addCollection(self, collection):
434 if collection.name in self.collectionMap:
Marc Slemkoc0e07a22006-08-09 23:34:57 +0000435 return self.collectionMap[collection.name]
Marc Slemkob2039e72006-08-09 01:00:17 +0000436 else:
437 self.collectionMap[collection.name] = collection
Marc Slemkoc0e07a22006-08-09 23:34:57 +0000438 return collection
Marc Slemkob2039e72006-08-09 01:00:17 +0000439
440 def getType(self, parent, symbol):
441 """ Get the type definition for a symbol"""
442
443 typeName = None
444
445 if isinstance(symbol, Type):
446 return symbol
447 elif isinstance(symbol, Field):
448 typeName = symbol.type.name
449 elif isinstance(symbol, Identifier):
450 typeName = symbol.name
451 else:
452 raise ErrorException([SymanticsError(parent, "unknown symbol \""+str(symbol)+"\"")])
453
454 for map in (self.primitiveMap, self.collectionMap, self.typedefMap, self.enumMap, self.structMap):
455 if typeName in map:
456 return map[typeName]
457
458 raise ErrorException([SymanticsError(parent, "\""+typeName+"\" is not defined.")])
459
460 def hasType(self, parent, symbol):
461 """ Determine if a type definition exists for the symbol"""
462
463 return self.getType(parent, symbol) == True
464
465 def validate(self):
466
467 errors = []
468
469 # Verify that struct fields types, collection key and element types, and typedef defined types exists and replaces
470 # type names with references to the type objects
471
472 for struct in self.structMap.values():
473 for field in struct.fieldList:
474 try:
475 field.type = self.getType(struct, field)
476 except ErrorException, e:
477 errors+= e.errors
478
479 for collection in self.collectionMap.values():
480 try:
Marc Slemko5b126d62006-08-11 23:03:42 +0000481 if isinstance(collection, MapType):
Marc Slemkob2039e72006-08-09 01:00:17 +0000482 collection.keyType = self.getType(collection, collection.keyType)
483
484 collection.valueType = self.getType(collection, collection.valueType)
Marc Slemko27340eb2006-08-10 20:45:55 +0000485
486 collection.validate()
Marc Slemkob2039e72006-08-09 01:00:17 +0000487
488 except ErrorException, e:
489 errors+= e.errors
490
491 for typedef in self.typedefMap.values():
492 try:
493 typedef.definitionType = self.getType(self, typedef.definitionType)
494
495 except ErrorException, e:
496 errors+= e.errors
497
Marc Slemkoc0e07a22006-08-09 23:34:57 +0000498 # Verify that service function result and arg list types exist and replace type name with reference to definition
Marc Slemkob2039e72006-08-09 01:00:17 +0000499
500 for service in self.serviceMap.values():
Marc Slemkoc0e07a22006-08-09 23:34:57 +0000501
Marc Slemkob2039e72006-08-09 01:00:17 +0000502 for function in service.functionList:
Marc Slemko5b126d62006-08-11 23:03:42 +0000503
504 for field in function.resultStruct.fieldList:
505 try:
506 field.type = self.getType(function, field)
507 except ErrorException, e:
508 errors+= e.errors
Marc Slemkob2039e72006-08-09 01:00:17 +0000509
Marc Slemko0b4ffa92006-08-11 02:49:29 +0000510 for field in function.argsStruct.fieldList:
Marc Slemkob2039e72006-08-09 01:00:17 +0000511 try:
512 field.type = self.getType(function, field)
513 except ErrorException, e:
514 errors+= e.errors
515
516 if len(errors):
517 raise ErrorException(errors)
Marc Slemkob2039e72006-08-09 01:00:17 +0000518
519class Parser(object):
520
521 reserved = ("BYTE",
522 # "CONST",
523 "DOUBLE",
524 "ENUM",
525 # "EXCEPTION",
526 # "EXTENDS",
527 "I08",
528 "I16",
529 "I32",
530 "I64",
531 "LIST",
532 "MAP",
533 "SERVICE",
534 "SET",
535 # "STATIC",
536 "STRING",
537 "STRUCT",
538 # "SYNCHRONIZED",
539 "TYPEDEF",
540 "U08",
541 "U16",
542 "U32",
543 "U64",
544 "UTF16",
545 "UTF8",
546 "VOID"
547 )
548
549 tokens = reserved + (
550 # Literals (identifier, integer constant, float constant, string constant, char const)
551 'ID', 'ICONST', 'SCONST', 'FCONST',
552 # Operators default=, optional*, variable...
553 'ASSIGN', #'OPTIONAL', 'ELLIPSIS',
554 # Delimeters ( ) { } < > , . ; :
555 'LPAREN', 'RPAREN',
556 'LBRACE', 'RBRACE',
557 'LANGLE', 'RANGLE',
558 'COMMA' #, 'PERIOD', 'SEMI' , 'COLON'
559 )
560
561 precendence = ()
562
563 reserved_map = {}
564
565 for r in reserved:
566 reserved_map[r.lower()] = r
567
568 def t_ID(self, t):
569 r'[A-Za-z_][\w_]*'
570 t.type = self.reserved_map.get(t.value,"ID")
571 return t
572
573 # Completely ignored characters
574 t_ignore = ' \t\x0c'
575
576# t_OPTIONAL = r'\*'
577 t_ASSIGN = r'='
578
579 # Delimeters
580 t_LPAREN = r'\('
581 t_RPAREN = r'\)'
582 t_LANGLE = r'\<'
583 t_RANGLE = r'\>'
584 t_LBRACE = r'\{'
585 t_RBRACE = r'\}'
586 t_COMMA = r','
587# t_PERIOD = r'\.'
588# t_SEMI = r';'
589# t_COLON = r':'
590# t_ELLIPSIS = r'\.\.\.'
591
592 # Integer literal
593 t_ICONST = r'\d+([uU]|[lL]|[uU][lL]|[lL][uU])?'
594
595 # Floating literal
596 t_FCONST = r'((\d+)(\.\d+)(e(\+|-)?(\d+))? | (\d+)e(\+|-)?(\d+))([lL]|[fF])?'
597
598 # String literal
599 t_SCONST = r'\"([^\\\n]|(\\.))*?\"'
600
601 # Comments
602 def t_comment(self, t):
603 r'(?:/\*(.|\n)*?\*/)|(?://[^\n]*\n)'
604 t.lineno += t.value.count('\n')
605
606 def t_error(self, t):
607 print "Illegal character %s" % repr(t.value[0])
608 t.skip(1)
609
610 # Newlines
611 def t_newline(self, t):
612 r'\n+'
613 t.lineno += t.value.count("\n")
614
615 def p_program(self, p):
616 'program : definitionlist'
617 pass
618
619 def p_definitionlist_1(self, p):
620 'definitionlist : definitionlist definition'
621 pass
622
623 def p_definitionlist_2(self, p):
624 'definitionlist :'
625 pass
626
627 def p_definition_1(self, p):
628 'definition : typedef'
629 self.pdebug("p_definition_1", p)
630 p[0] = p[1]
631 try:
632 self.program.addTypedef(p[0])
633 except ErrorException, e:
634 self.errors+= e.errors
635
636 def p_definition_2(self, p):
637 'definition : enum'
638 self.pdebug("p_definition_2", p)
639 p[0] = p[1]
640 try:
641 self.program.addEnum(p[0])
642 except ErrorException, e:
643 self.errors+= e.errors
644
645 def p_definition_3(self, p):
646 'definition : struct'
647 self.pdebug("p_definition_3", p)
648 p[0] = p[1]
649 try:
650 self.program.addStruct(p[0])
651 except ErrorException, e:
652 self.errors+= e.errors
653
654 def p_definition_4(self, p):
655 'definition : service'
656 self.pdebug("p_definition_4", p)
657 p[0] = p[1]
658 try:
659 self.program.addService(p[0])
660 except ErrorException, e:
661 self.errors+= e.errors
662
663 def p_typedef(self, p):
664 'typedef : TYPEDEF definitiontype ID'
665 self.pdebug("p_typedef", p)
Marc Slemko5b126d62006-08-11 23:03:42 +0000666 p[0] = TypedefType(p, p[3], p[2])
Marc Slemkob2039e72006-08-09 01:00:17 +0000667 try:
668 p[0].validate()
669
670 except ErrorException, e:
671 self.errors+= e.errors
672
Marc Slemkob2039e72006-08-09 01:00:17 +0000673 def p_enum(self, p):
674 'enum : ENUM ID LBRACE enumdeflist RBRACE'
675 self.pdebug("p_enum", p)
Marc Slemko5b126d62006-08-11 23:03:42 +0000676 p[0] = EnumType(p, p[2], p[4])
Marc Slemkob2039e72006-08-09 01:00:17 +0000677
678 try:
679 p[0].validate()
680 except ErrorException, e:
681 self.errors+= e.errors
682
683 def p_enumdeflist_1(self, p):
684 'enumdeflist : enumdeflist COMMA enumdef'
685 self.pdebug("p_enumdeflist_1", p)
686 p[0] = p[1] + (p[3],)
687
688 def p_enumdeflist_2(self, p):
689 'enumdeflist : enumdef'
690 self.pdebug("p_enumdeflist_2", p)
691 p[0] = (p[1],)
692
693 def p_enumdef_0(self, p):
694 'enumdef : ID ASSIGN ICONST'
695 self.pdebug("p_enumdef_0", p)
696 p[0] = EnumDef(p, p[1], int(p[3]))
697
698 def p_enumdef_1(self, p):
699 'enumdef : ID'
700 self.pdebug("p_enumdef_1", p)
701 p[0] = EnumDef(p, p[1])
702
703 def p_struct(self, p):
704 'struct : STRUCT ID LBRACE fieldlist RBRACE'
705 self.pdebug("p_struct", p)
Marc Slemko5b126d62006-08-11 23:03:42 +0000706 p[0] = StructType(p, p[2], p[4])
Marc Slemkob2039e72006-08-09 01:00:17 +0000707
708 try:
709 p[0].validate()
710 except ErrorException, e:
711 self.errors+= e.errors
712
713 def p_service(self, p):
714 'service : SERVICE ID LBRACE functionlist RBRACE'
715 self.pdebug("p_service", p)
716 p[0] = Service(p, p[2], p[4])
717 try:
718 p[0].validate()
719 except ErrorException, e:
720 self.errors+= e.errors
721
722 def p_functionlist_1(self, p):
723 'functionlist : functionlist function'
724 self.pdebug("p_functionlist_1", p)
725 p[0] = p[1] + (p[2],)
726
727 def p_functionlist_2(self, p):
728 'functionlist :'
729 self.pdebug("p_functionlist_2", p)
730 p[0] = ()
731
732 def p_function(self, p):
733 'function : functiontype functionmodifiers ID LPAREN fieldlist RPAREN'
734 self.pdebug("p_function", p)
Marc Slemko5b126d62006-08-11 23:03:42 +0000735
736 resultStruct = StructType(p, p[3]+"_result", (Field(p, p[1], Identifier(None, "success", 1)),))
737
738 p[0] = Function(p, p[3], resultStruct, StructType(p, p[3]+"_args", p[5]))
Marc Slemkob2039e72006-08-09 01:00:17 +0000739 try:
740 p[0].validate()
741 except ErrorException, e:
742 self.errors+= e.errors
743
744 def p_functionmodifiers(self, p):
745 'functionmodifiers :'
746 self.pdebug("p_functionmodifiers", p)
747 p[0] = ()
748
749 def p_fieldlist_1(self, p):
750 'fieldlist : fieldlist COMMA field'
751 self.pdebug("p_fieldlist_1", p)
752 p[0] = p[1] + (p[3],)
753
754 def p_fieldlist_2(self, p):
755 'fieldlist : field'
756 self.pdebug("p_fieldlist_2", p)
757 p[0] = (p[1],)
758
759 def p_fieldlist_3(self, p):
760 'fieldlist :'
761 self.pdebug("p_fieldlist_3", p)
762 p[0] = ()
763
764 def p_field_1(self, p):
765 'field : fieldtype ID ASSIGN ICONST'
766 self.pdebug("p_field_1", p)
767 p[0] = Field(p, p[1], Identifier(None, p[2], int(p[4])))
768
769 def p_field_2(self, p):
770 'field : fieldtype ID'
771 self.pdebug("p_field_2", p)
772 p[0] = Field(p, p[1], Identifier(None, p[2]))
773
774 def p_definitiontype_1(self, p):
775 'definitiontype : basetype'
776 self.pdebug("p_definitiontype_1", p)
777 p[0] = p[1]
778
779 def p_definitiontype_2(self, p):
780 'definitiontype : collectiontype'
781 self.pdebug("p_definitiontype_2", p)
782 p[0] = p[1]
783
784 def p_functiontype_1(self, p):
785 'functiontype : fieldtype'
786 self.pdebug("p_functiontype_1", p)
787 p[0] = p[1]
788
789 def p_functiontype_2(self, p):
790 'functiontype : VOID'
791 self.pdebug("p_functiontype_2", p)
792 p[0] = self.program.primitiveMap[p[1].lower()]
793
794 def p_fieldtype_1(self, p):
795 'fieldtype : ID'
796 self.pdebug("p_fieldtype_1", p)
797 p[0] = Identifier(p, p[1])
798
799 def p_fieldtype_2(self, p):
800 'fieldtype : basetype'
801 self.pdebug("p_fieldtype_2", p)
802 p[0] = p[1]
803
804 def p_fieldtype_3(self, p):
805 'fieldtype : collectiontype'
806 self.pdebug("p_fieldtype_3", p)
807 p[0] = p[1]
808
809 def p_basetype_1(self, p):
810 'basetype : STRING'
811 self.pdebug("p_basetype_1", p)
812 p[0] = self.program.primitiveMap[p[1].lower()]
813
814 def p_basetype_2(self, p):
815 'basetype : BYTE'
816 self.pdebug("p_basetype_2", p)
817 p[0] = self.program.primitiveMap[p[1].lower()]
818
819 def p_basetype_3(self, p):
820 'basetype : I08'
821 self.pdebug("p_basetype_3", p)
822 p[0] = self.program.primitiveMap[p[1].lower()]
823
824 def p_basetype_4(self, p):
825 'basetype : U08'
826 self.pdebug("p_basetype_4", p)
827 p[0] = self.program.primitiveMap[p[1].lower()]
828
829 def p_basetype_5(self, p):
830 'basetype : I16'
831 self.pdebug("p_basetype_5", p)
832 p[0] = self.program.primitiveMap[p[1].lower()]
833
834 def p_basetype_6(self, p):
835 'basetype : U16'
836 self.pdebug("p_basetype_6", p)
837 p[0] = self.program.primitiveMap[p[1].lower()]
838
839 def p_basetype_7(self, p):
840 'basetype : I32'
841 self.pdebug("p_basetype_7", p)
842 p[0] = self.program.primitiveMap[p[1].lower()]
843
844 def p_basetype_8(self, p):
845 'basetype : U32'
846 self.pdebug("p_basetype_8", p)
847 p[0] = self.program.primitiveMap[p[1].lower()]
848
849 def p_basetype_9(self, p):
850 'basetype : I64'
851 self.pdebug("p_basetype_9", p)
852 p[0] = self.program.primitiveMap[p[1].lower()]
853
854 def p_basetype_10(self, p):
855 'basetype : U64'
856 self.pdebug("p_basetype_10", p)
857 p[0] = self.program.primitiveMap[p[1].lower()]
858
859 def p_basetype_11(self, p):
860 'basetype : UTF8'
861 self.pdebug("p_basetype_11", p)
862 p[0] = self.program.primitiveMap[p[1].lower()]
863
864 def p_basetype_12(self, p):
865 'basetype : UTF16'
866 self.pdebug("p_basetype_12", p)
867 p[0] = self.program.primitiveMap[p[1].lower()]
868
869 def p_basetype_13(self, p):
870 'basetype : DOUBLE'
871 self.pdebug("p_basetype_13", p)
872 p[0] = self.program.primitiveMap[p[1].lower()]
873
874 def p_collectiontype_1(self, p):
875 'collectiontype : maptype'
876 self.pdebug("p_collectiontype_1", p)
Marc Slemkoc0e07a22006-08-09 23:34:57 +0000877 p[0] = self.program.addCollection(p[1])
Marc Slemkob2039e72006-08-09 01:00:17 +0000878
879 def p_collectiontype_2(self, p):
880 'collectiontype : settype'
881 self.pdebug("p_collectiontype_2", p)
Marc Slemkoc0e07a22006-08-09 23:34:57 +0000882 p[0] = self.program.addCollection(p[1])
Marc Slemkob2039e72006-08-09 01:00:17 +0000883
884 def p_collectiontype_3(self, p):
885 'collectiontype : listtype'
886 self.pdebug("p_collectiontype_3", p)
Marc Slemkoc0e07a22006-08-09 23:34:57 +0000887 p[0] = self.program.addCollection(p[1])
Marc Slemkob2039e72006-08-09 01:00:17 +0000888
889 def p_maptype(self, p):
890 'maptype : MAP LANGLE fieldtype COMMA fieldtype RANGLE'
891 self.pdebug("p_maptype", p)
Marc Slemko5b126d62006-08-11 23:03:42 +0000892 p[0] = MapType(p, p[3], p[5])
Marc Slemkob2039e72006-08-09 01:00:17 +0000893
894 def p_settype(self, p):
895 'settype : SET LANGLE fieldtype RANGLE'
896 self.pdebug("p_settype", p)
Marc Slemko5b126d62006-08-11 23:03:42 +0000897 p[0] = SetType(p, p[3])
Marc Slemkob2039e72006-08-09 01:00:17 +0000898
899 def p_listtype(self, p):
900 'listtype : LIST LANGLE fieldtype RANGLE'
901 self.pdebug("p_listtype", p)
Marc Slemko5b126d62006-08-11 23:03:42 +0000902 p[0] = ListType(p, p[3])
Marc Slemkob2039e72006-08-09 01:00:17 +0000903
904 def p_error(self, p):
Marc Slemko27340eb2006-08-10 20:45:55 +0000905 # p_error is called with an empty token if eof was encountered unexpectedly.
906 if not p:
907 self.errors.append(SyntaxError("Unexpected end of file"))
908 else:
909 self.errors.append(SyntaxError(p))
Marc Slemkob2039e72006-08-09 01:00:17 +0000910
911 def pdebug(self, name, p):
912 if self.debug:
913 print(name+"("+string.join(map(lambda t: "<<"+str(t)+">>", p), ", ")+")")
914
915 def __init__(self, **kw):
916 self.debug = kw.get('debug', 0)
917 self.names = { }
918 self.program = Program()
919 self.errors = []
920
921 try:
922 modname = os.path.split(os.path.splitext(__file__)[0])[1] + "_" + self.__class__.__name__
923 except:
924 modname = "parser"+"_"+self.__class__.__name__
925 self.debugfile = modname + ".dbg"
926 self.tabmodule = modname + "_" + "parsetab"
927 #print self.debugfile, self.tabmodule
928
929 # Build the lexer and parser
930 lex.lex(module=self, debug=self.debug)
931 yacc.yacc(module=self,
932 debug=self.debug,
933 debugfile=self.debugfile,
934 tabmodule=self.tabmodule)
935
936 def parsestring(self, s, filename=""):
937 yacc.parse(s)
938
939 if len(self.errors) == 0:
940 try:
941 self.program.validate()
942 except ErrorException, e:
943 self.errors+= e.errors
944
945 if len(self.errors):
946 for error in self.errors:
947 print(filename+":"+str(error))
948
949 def parse(self, filename, doPickle=True):
950
951 f = file(filename, "r")
952
953 self.parsestring(f.read(), filename)
954
955 if len(self.errors) == 0 and doPickle:
956
957 outf = file(os.path.splitext(filename)[0]+".thyc", "w")
958
959 pickle.dump(self.program, outf)