blob: 87633f4a533f65db3736cd6e0d99697fd35f9293 [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):
Marc Slemkob2039e72006-08-09 01:00:17 +000053 def __init__(self, errors=None):
Marc Slemkoc6936402006-08-23 02:15:31 +000054 Exception.__init__(self)
Marc Slemkob2039e72006-08-09 01:00:17 +000055 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 +000085def toCanonicalType(ttype):
Marc Slemko5b126d62006-08-11 23:03:42 +000086 if isinstance(ttype, TypedefType):
Marc Slemko27340eb2006-08-10 20:45:55 +000087 return toCanonicalType(ttype.definitionType)
88 else:
89 return ttype
90
Marc Slemkoc6936402006-08-23 02:15:31 +000091def isVoidType(ttype):
92 """Is canonnical type of the specified type void?"""
93 return toCanonicalType(ttype) == VOID_TYPE
94
Marc Slemko27340eb2006-08-10 20:45:55 +000095def isComparableType(ttype):
Marc Slemkoc6936402006-08-23 02:15:31 +000096 """Is the type one that is implicitly comparable and thus is suitable for use in C++ maps and sets and java Sets and Maps?"""
Marc Slemko27340eb2006-08-10 20:45:55 +000097 ttype = toCanonicalType(ttype)
Marc Slemko5b126d62006-08-11 23:03:42 +000098 return isinstance(ttype, PrimitiveType) or isinstance(ttype, EnumType)
Marc Slemko27340eb2006-08-10 20:45:55 +000099
Marc Slemkob2039e72006-08-09 01:00:17 +0000100class Type(Definition):
101 """ Abstract Type definition """
102
103 def __init__(self, symbols, name):
104 Definition.__init__(self, symbols, name)
105 self.name = name
106
107 def __str__(self):
108 return self.name
109
Marc Slemko5b126d62006-08-11 23:03:42 +0000110class TypedefType(Type):
Marc Slemkob2039e72006-08-09 01:00:17 +0000111
112 def __init__(self, symbols, name, definitionType):
113 Type.__init__(self, symbols, name)
114 self.definitionType = definitionType
115
116 def __str__(self):
117 return self.name+"<"+str(self.name)+", "+str(self.definitionType)+">"
118
119""" Primitive Types """
120
121class PrimitiveType(Type):
122
123 def __init__(self, name):
124 Type.__init__(self, None, name)
125
Marc Slemkoc0e07a22006-08-09 23:34:57 +0000126STOP_TYPE = PrimitiveType("stop")
Marc Slemkob2039e72006-08-09 01:00:17 +0000127VOID_TYPE = PrimitiveType("void")
128BOOL_TYPE = PrimitiveType("bool")
Marc Slemkobf4fd192006-08-15 21:29:39 +0000129STRING_TYPE = PrimitiveType("utf7")
130UTF7_TYPE = STRING_TYPE
Marc Slemkob2039e72006-08-09 01:00:17 +0000131UTF8_TYPE = PrimitiveType("utf8")
132UTF16_TYPE = PrimitiveType("utf16")
133BYTE_TYPE = PrimitiveType("u08")
134I08_TYPE = PrimitiveType("i08")
135I16_TYPE = PrimitiveType("i16")
136I32_TYPE = PrimitiveType("i32")
137I64_TYPE = PrimitiveType("i64")
138U08_TYPE = PrimitiveType("u08")
139U16_TYPE = PrimitiveType("u16")
140U32_TYPE = PrimitiveType("u32")
141U64_TYPE = PrimitiveType("u64")
142FLOAT_TYPE = PrimitiveType("float")
Marc Slemkod8b10512006-08-14 23:30:37 +0000143DOUBLE_TYPE = PrimitiveType("double")
Marc Slemkob2039e72006-08-09 01:00:17 +0000144
145PRIMITIVE_MAP = {
Marc Slemkoc0e07a22006-08-09 23:34:57 +0000146 "stop" : STOP_TYPE,
Marc Slemkob2039e72006-08-09 01:00:17 +0000147 "void" : VOID_TYPE,
148 "bool" : BOOL_TYPE,
149 "string": UTF7_TYPE,
150 "utf7": UTF7_TYPE,
151 "utf8": UTF8_TYPE,
152 "utf16": UTF16_TYPE,
153 "byte" : U08_TYPE,
154 "i08": I08_TYPE,
155 "i16": I16_TYPE,
156 "i32": I32_TYPE,
157 "i64": I64_TYPE,
158 "u08": U08_TYPE,
159 "u16": U16_TYPE,
160 "u32": U32_TYPE,
161 "u64": U64_TYPE,
Marc Slemkod8b10512006-08-14 23:30:37 +0000162 "float": FLOAT_TYPE,
163 "double": DOUBLE_TYPE
Marc Slemkob2039e72006-08-09 01:00:17 +0000164}
165
166""" Collection Types """
167
168class CollectionType(Type):
169
170 def __init__(self, symbols, name):
171 Type.__init__(self, symbols, name)
172
Marc Slemko27340eb2006-08-10 20:45:55 +0000173 def validate(self):
174 return True
175
Marc Slemko5b126d62006-08-11 23:03:42 +0000176class MapType(CollectionType):
Marc Slemkob2039e72006-08-09 01:00:17 +0000177
178 def __init__(self, symbols, keyType, valueType):
179 CollectionType.__init__(self, symbols, "map<"+keyType.name+","+valueType.name +">")
180 self.keyType = keyType
181 self.valueType = valueType
182
Marc Slemko27340eb2006-08-10 20:45:55 +0000183 def validate(self):
184 if not isComparableType(self.keyType):
185 raise ErrorException([SymanticsError(self, "key type \""+str(self.keyType)+"\" is not a comparable type.")])
186
Marc Slemko5b126d62006-08-11 23:03:42 +0000187class SetType(CollectionType):
Marc Slemkob2039e72006-08-09 01:00:17 +0000188
189 def __init__(self, symbols, valueType):
190 CollectionType.__init__(self, symbols, "set<"+valueType.name+">")
191 self.valueType = valueType
192
Marc Slemko27340eb2006-08-10 20:45:55 +0000193 def validate(self):
194 if not isComparableType(self.valueType):
195 raise ErrorException([SymanticsError(self, "value type \""+str(self.valueType)+"\" is not a comparable type.")])
196
Marc Slemko5b126d62006-08-11 23:03:42 +0000197class ListType(CollectionType):
Marc Slemkob2039e72006-08-09 01:00:17 +0000198
199 def __init__(self, symbols, valueType):
200 CollectionType.__init__(self, symbols, "list<"+valueType.name+">")
201 self.valueType = valueType
202
Marc Slemko5b126d62006-08-11 23:03:42 +0000203class EnumType(Definition):
Marc Slemkob2039e72006-08-09 01:00:17 +0000204
205 def __init__(self, symbols, name, enumDefs):
206 Definition.__init__(self, symbols, name)
207 self.enumDefs = enumDefs
208
209 def validate(self):
210 ids = {}
211 names = {}
212 errors = []
213
214 for enumDef in self.enumDefs:
215
216 if enumDef.name in names:
217 errors.append(SymanticsError(enumDef, self.name+"."+str(enumDef.name)+" already defined at line "+str(names[enumDef.name].start)))
218 else:
219 names[enumDef.name] = enumDef
220
221 if enumDef.id != None:
222 oldEnumDef = ids.get(enumDef.id)
223 if oldEnumDef:
224 errors.append(SymanticsError(enumDef, "enum "+self.name+" \""+str(enumDef.name)+"\" uses constant already assigned to \""+oldEnumDef.name+"\""))
225 else:
226 ids[enumDef.id] = enumDef
227
228 if len(errors):
229 raise ErrorException(errors)
230
231 def assignId(enumDef, currentId, ids):
232 'Finds the next available id number for an enum definition'
233
Marc Slemkoc6936402006-08-23 02:15:31 +0000234 eid= currentId + 1
Marc Slemkob2039e72006-08-09 01:00:17 +0000235
Marc Slemkoc6936402006-08-23 02:15:31 +0000236 while eid in ids:
237 eid += 1
Marc Slemkob2039e72006-08-09 01:00:17 +0000238
Marc Slemkoc6936402006-08-23 02:15:31 +0000239 enumDef.id = eid
Marc Slemkob2039e72006-08-09 01:00:17 +0000240
241 ids[enumDef.id] = enumDef
Marc Slemkoc6936402006-08-23 02:15:31 +0000242
243 return eid
Marc Slemkob2039e72006-08-09 01:00:17 +0000244
245 # assign ids for all enum defs with unspecified ids
246
247 currentId = 0
248
249 for enumDef in self.enumDefs:
250 if not enumDef.id:
251 assignId(enumDef, currentId, ids)
252 currentId = enumDef.id
253
254 def __repr__(self):
255 return str(self)
256
257 def __str__(self):
258 return self.name+"<"+string.join(map(lambda enumDef: str(enumDef), self.enumDefs), ", ")
259
260class EnumDef(Definition):
261
262 def __init__(self, symbols, name, id=None):
263 Definition.__init__(self, symbols, name, id)
264
265 def __repr__(self):
266 return str(self)
267
268 def __str__(self):
269 result = self.name
270 if self.id:
271 result+= ":"+str(self.id)
272 return result
273
274
275class Field(Definition):
276
277 def __init__(self, symbols, type, identifier):
278 Definition.__init__(self, symbols, identifier.name, identifier.id)
279 self.type = type
280 self.identifier = identifier
281
282 def __str__(self):
283 return "<"+str(self.type)+", "+str(self.identifier)+">"
284
285def validateFieldList(fieldList):
286
287 errors = []
288 names = {}
289 ids = {}
290
291 for field in fieldList:
292
293 if field.name in names:
294 oldField = names[field.name]
295 errors.append(SymanticsError(field, "field \""+field.name+"\" already defined at "+str(oldField.start)))
296 else:
297 names[field.name] = field
298
299 if field.id != None:
300 oldField = ids.get(field.id)
301 if oldField:
302 errors.append(SymanticsError(field, "field \""+field.name+"\" uses constant already assigned to \""+oldField.name+"\""))
303 else:
304 ids[field.id] = field
305
306 if len(errors):
307 raise ErrorException(errors)
308
Marc Slemkoc0e07a22006-08-09 23:34:57 +0000309 def assignId(field, currentId, ids):
310 'Finds the next available id number for a field'
Marc Slemkoc6936402006-08-23 02:15:31 +0000311 fid = currentId - 1
Marc Slemkoc0e07a22006-08-09 23:34:57 +0000312
Marc Slemkoc6936402006-08-23 02:15:31 +0000313 while fid in ids:
314 fid-= 1
Marc Slemkoc0e07a22006-08-09 23:34:57 +0000315
Marc Slemkoc6936402006-08-23 02:15:31 +0000316 field.id = fid
Marc Slemkoc0e07a22006-08-09 23:34:57 +0000317
318 ids[field.id] = field
319
Marc Slemkoc6936402006-08-23 02:15:31 +0000320 return fid
Marc Slemkoc0e07a22006-08-09 23:34:57 +0000321
322 # assign ids for all fields with unspecified ids
323
324 currentId = 0
325
Marc Slemko0b4ffa92006-08-11 02:49:29 +0000326 for field in fieldList:
Marc Slemkoc0e07a22006-08-09 23:34:57 +0000327 if not field.id:
328 currentId = assignId(field, currentId, ids)
329
Marc Slemko5b126d62006-08-11 23:03:42 +0000330class StructType(Type):
Marc Slemkob2039e72006-08-09 01:00:17 +0000331
332 def __init__(self, symbols, name, fieldList):
333 Type.__init__(self, symbols, name)
334 self.fieldList = fieldList
335
336 def validate(self):
337 validateFieldList(self.fieldList)
338
339 def __str__(self):
340 return self.name+"<"+string.join(map(lambda a: str(a), self.fieldList), ", ")+">"
341
Marc Slemkod8b10512006-08-14 23:30:37 +0000342class ExceptionType(StructType):
343
344 def __init__(self, symbols, name, fieldList):
345 StructType.__init__(self, symbols, name, fieldList)
346
Marc Slemkob2039e72006-08-09 01:00:17 +0000347class Function(Definition):
348
Marc Slemkoc6936402006-08-23 02:15:31 +0000349 def __init__(self, symbols, name, resultStruct, argsStruct):
Marc Slemkob2039e72006-08-09 01:00:17 +0000350 Definition.__init__(self, symbols, name)
Marc Slemko5b126d62006-08-11 23:03:42 +0000351 self.resultStruct = resultStruct
Marc Slemko0b4ffa92006-08-11 02:49:29 +0000352 self.argsStruct = argsStruct
Marc Slemkob2039e72006-08-09 01:00:17 +0000353
354 def validate(self):
Marc Slemko0b4ffa92006-08-11 02:49:29 +0000355 validateFieldList(self.argsStruct.fieldList)
Marc Slemkod8b10512006-08-14 23:30:37 +0000356 validateFieldList(self.resultStruct.fieldList)
Marc Slemko5b126d62006-08-11 23:03:42 +0000357
358 def args(self):
359 return self.argsStruct.fieldList
360
361 def returnType(self):
362 return self.resultStruct.fieldList[0].type
Marc Slemkod8b10512006-08-14 23:30:37 +0000363
364 def exceptions(self):
365 return self.resultStruct.fieldList[1:]
Marc Slemkob2039e72006-08-09 01:00:17 +0000366
367 def __str__(self):
Marc Slemkod8b10512006-08-14 23:30:37 +0000368 return self.name+"("+str(self.argsStruct)+") => "+str(self.resultStruct)
Marc Slemkob2039e72006-08-09 01:00:17 +0000369
370class Service(Definition):
371
372 def __init__(self, symbols, name, functionList):
373 Definition.__init__(self, symbols, name)
374 self.functionList = functionList
375
376 def validate(self):
377
378 errors = []
379 functionNames = {}
380 for function in self.functionList:
381 if function.name in functionNames:
Marc Slemkoc6936402006-08-23 02:15:31 +0000382 oldFunction = functionNames[function.name]
Marc Slemkob2039e72006-08-09 01:00:17 +0000383 errors.append(SymanticsError(function, "function "+function.name+" already defined at "+str(oldFunction.start)))
384
385 if len(errors):
386 raise ErrorException(errors)
387
388 def __str__(self):
389 return self.name+"("+string.join(map(lambda a: str(a), self.functionList), ", ")+")"
390
391class Program(object):
392
Marc Slemkoc6936402006-08-23 02:15:31 +0000393 def __init__(self, symbols=None, name="",
Marc Slemko17859852006-08-15 00:21:31 +0000394 namespace="",
395 definitions=None,
396 serviceMap=None,
397 typedefMap=None,
398 enumMap=None, structMap=None,
399 collectionMap=None,
Marc Slemkob2039e72006-08-09 01:00:17 +0000400 primitiveMap=None):
401
402 self.name = name
403
Marc Slemko17859852006-08-15 00:21:31 +0000404 self.namespace = namespace
405
Marc Slemkob2039e72006-08-09 01:00:17 +0000406 if not definitions:
407 definitions = []
408 self.definitions = definitions
409
410 if not serviceMap:
411 serviceMap = {}
412 self.serviceMap = serviceMap
413
414 if not typedefMap:
415 typedefMap = {}
416 self.typedefMap = typedefMap
417
418 if not enumMap:
419 enumMap = {}
420 self.enumMap = enumMap
421
422 if not structMap:
423 structMap = {}
424 self.structMap = structMap
425
426 if not collectionMap:
427 collectionMap = {}
428 self.collectionMap = collectionMap
429
430 if not primitiveMap:
431 primitiveMap = PRIMITIVE_MAP
432 self.primitiveMap = primitiveMap
433
434 def addDefinition(self, definition, definitionMap, definitionTypeName):
435
436 oldDefinition = definitionMap.get(definition.name)
437 if oldDefinition:
438 raise ErrorException([SymanticsError(definition, definitionTypeName+" "+definition.name+" is already defined at "+str(oldDefinition.start))])
439 else:
440 definitionMap[definition.name] = definition
441
442 # keep an ordered list of definitions so that stub/skel generators can determine the original order
443
444 self.definitions.append(definition)
445
446 def addStruct(self, struct):
447 self.addDefinition(struct, self.structMap, "struct")
448
449 def addTypedef(self, typedef):
450 self.addDefinition(typedef, self.typedefMap, "typedef")
451
452 def addEnum(self, enum):
453 self.addDefinition(enum, self.enumMap, "enum")
454
455 def addService(self, service):
456 self.addDefinition(service, self.serviceMap, "service")
457
458 def addCollection(self, collection):
459 if collection.name in self.collectionMap:
Marc Slemkoc0e07a22006-08-09 23:34:57 +0000460 return self.collectionMap[collection.name]
Marc Slemkob2039e72006-08-09 01:00:17 +0000461 else:
462 self.collectionMap[collection.name] = collection
Marc Slemkoc0e07a22006-08-09 23:34:57 +0000463 return collection
Marc Slemkob2039e72006-08-09 01:00:17 +0000464
465 def getType(self, parent, symbol):
466 """ Get the type definition for a symbol"""
467
468 typeName = None
469
470 if isinstance(symbol, Type):
471 return symbol
472 elif isinstance(symbol, Field):
473 typeName = symbol.type.name
474 elif isinstance(symbol, Identifier):
475 typeName = symbol.name
476 else:
477 raise ErrorException([SymanticsError(parent, "unknown symbol \""+str(symbol)+"\"")])
478
Marc Slemkoc6936402006-08-23 02:15:31 +0000479 for tmap in (self.primitiveMap, self.collectionMap, self.typedefMap, self.enumMap, self.structMap):
480 if typeName in tmap:
481 return tmap[typeName]
Marc Slemkob2039e72006-08-09 01:00:17 +0000482
483 raise ErrorException([SymanticsError(parent, "\""+typeName+"\" is not defined.")])
484
485 def hasType(self, parent, symbol):
486 """ Determine if a type definition exists for the symbol"""
487
Marc Slemkoc6936402006-08-23 02:15:31 +0000488 return self.getType(parent, symbol) != None
Marc Slemkob2039e72006-08-09 01:00:17 +0000489
490 def validate(self):
491
492 errors = []
493
494 # Verify that struct fields types, collection key and element types, and typedef defined types exists and replaces
495 # type names with references to the type objects
496
497 for struct in self.structMap.values():
498 for field in struct.fieldList:
499 try:
500 field.type = self.getType(struct, field)
501 except ErrorException, e:
502 errors+= e.errors
503
504 for collection in self.collectionMap.values():
505 try:
Marc Slemko5b126d62006-08-11 23:03:42 +0000506 if isinstance(collection, MapType):
Marc Slemkob2039e72006-08-09 01:00:17 +0000507 collection.keyType = self.getType(collection, collection.keyType)
508
509 collection.valueType = self.getType(collection, collection.valueType)
Marc Slemko27340eb2006-08-10 20:45:55 +0000510
511 collection.validate()
Marc Slemkob2039e72006-08-09 01:00:17 +0000512
513 except ErrorException, e:
514 errors+= e.errors
515
516 for typedef in self.typedefMap.values():
517 try:
518 typedef.definitionType = self.getType(self, typedef.definitionType)
519
520 except ErrorException, e:
521 errors+= e.errors
522
Marc Slemkoc0e07a22006-08-09 23:34:57 +0000523 # 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 +0000524
525 for service in self.serviceMap.values():
Marc Slemkoc0e07a22006-08-09 23:34:57 +0000526
Marc Slemkob2039e72006-08-09 01:00:17 +0000527 for function in service.functionList:
Marc Slemko5b126d62006-08-11 23:03:42 +0000528
529 for field in function.resultStruct.fieldList:
530 try:
531 field.type = self.getType(function, field)
532 except ErrorException, e:
533 errors+= e.errors
Marc Slemkob2039e72006-08-09 01:00:17 +0000534
Marc Slemko0b4ffa92006-08-11 02:49:29 +0000535 for field in function.argsStruct.fieldList:
Marc Slemkob2039e72006-08-09 01:00:17 +0000536 try:
537 field.type = self.getType(function, field)
538 except ErrorException, e:
539 errors+= e.errors
540
541 if len(errors):
542 raise ErrorException(errors)
Marc Slemkob2039e72006-08-09 01:00:17 +0000543
Marc Slemko17859852006-08-15 00:21:31 +0000544 def validateNamespace(self, namespace):
545
546 if self.namespace != "":
547 raise ErrorException([SymanticsError, self, "namespace already defined as \""+self.namespace+"\""])
548 self.namespace = namespace
549
Marc Slemkob2039e72006-08-09 01:00:17 +0000550class Parser(object):
551
552 reserved = ("BYTE",
553 # "CONST",
554 "DOUBLE",
555 "ENUM",
Marc Slemkod8b10512006-08-14 23:30:37 +0000556 "EXCEPTION",
Marc Slemkob2039e72006-08-09 01:00:17 +0000557 # "EXTENDS",
558 "I08",
559 "I16",
560 "I32",
561 "I64",
562 "LIST",
563 "MAP",
Marc Slemko17859852006-08-15 00:21:31 +0000564 "NAMESPACE",
Marc Slemkob2039e72006-08-09 01:00:17 +0000565 "SERVICE",
566 "SET",
567 # "STATIC",
568 "STRING",
569 "STRUCT",
570 # "SYNCHRONIZED",
Marc Slemkod8b10512006-08-14 23:30:37 +0000571 "THROWS",
Marc Slemkob2039e72006-08-09 01:00:17 +0000572 "TYPEDEF",
573 "U08",
574 "U16",
575 "U32",
576 "U64",
577 "UTF16",
578 "UTF8",
579 "VOID"
580 )
581
582 tokens = reserved + (
583 # Literals (identifier, integer constant, float constant, string constant, char const)
Marc Slemko17859852006-08-15 00:21:31 +0000584 'ID', 'ICONST', # 'SCONST', 'FCONST',
Marc Slemkob2039e72006-08-09 01:00:17 +0000585 # Operators default=, optional*, variable...
586 'ASSIGN', #'OPTIONAL', 'ELLIPSIS',
587 # Delimeters ( ) { } < > , . ; :
588 'LPAREN', 'RPAREN',
589 'LBRACE', 'RBRACE',
590 'LANGLE', 'RANGLE',
Marc Slemko17859852006-08-15 00:21:31 +0000591 'COMMA', 'PERIOD' #, 'SEMI' , 'COLON'
Marc Slemkob2039e72006-08-09 01:00:17 +0000592 )
593
594 precendence = ()
595
596 reserved_map = {}
597
598 for r in reserved:
599 reserved_map[r.lower()] = r
600
601 def t_ID(self, t):
602 r'[A-Za-z_][\w_]*'
603 t.type = self.reserved_map.get(t.value,"ID")
604 return t
605
606 # Completely ignored characters
607 t_ignore = ' \t\x0c'
608
609# t_OPTIONAL = r'\*'
610 t_ASSIGN = r'='
611
612 # Delimeters
613 t_LPAREN = r'\('
614 t_RPAREN = r'\)'
615 t_LANGLE = r'\<'
616 t_RANGLE = r'\>'
617 t_LBRACE = r'\{'
618 t_RBRACE = r'\}'
619 t_COMMA = r','
Marc Slemko17859852006-08-15 00:21:31 +0000620 t_PERIOD = r'\.'
Marc Slemkob2039e72006-08-09 01:00:17 +0000621# t_SEMI = r';'
622# t_COLON = r':'
623# t_ELLIPSIS = r'\.\.\.'
624
625 # Integer literal
626 t_ICONST = r'\d+([uU]|[lL]|[uU][lL]|[lL][uU])?'
627
628 # Floating literal
Marc Slemko17859852006-08-15 00:21:31 +0000629# t_FCONST = r'((\d+)(\.\d+)(e(\+|-)?(\d+))? | (\d+)e(\+|-)?(\d+))([lL]|[fF])?'
Marc Slemkob2039e72006-08-09 01:00:17 +0000630
631 # String literal
Marc Slemko17859852006-08-15 00:21:31 +0000632# t_SCONST = r'\"([^\\\n]|(\\.))*?\"'
Marc Slemkob2039e72006-08-09 01:00:17 +0000633
634 # Comments
635 def t_comment(self, t):
636 r'(?:/\*(.|\n)*?\*/)|(?://[^\n]*\n)'
637 t.lineno += t.value.count('\n')
638
639 def t_error(self, t):
640 print "Illegal character %s" % repr(t.value[0])
641 t.skip(1)
642
643 # Newlines
644 def t_newline(self, t):
645 r'\n+'
646 t.lineno += t.value.count("\n")
647
648 def p_program(self, p):
649 'program : definitionlist'
650 pass
651
652 def p_definitionlist_1(self, p):
653 'definitionlist : definitionlist definition'
654 pass
655
656 def p_definitionlist_2(self, p):
657 'definitionlist :'
658 pass
659
660 def p_definition_1(self, p):
661 'definition : typedef'
662 self.pdebug("p_definition_1", p)
663 p[0] = p[1]
664 try:
665 self.program.addTypedef(p[0])
666 except ErrorException, e:
667 self.errors+= e.errors
668
669 def p_definition_2(self, p):
670 'definition : enum'
671 self.pdebug("p_definition_2", p)
672 p[0] = p[1]
673 try:
674 self.program.addEnum(p[0])
675 except ErrorException, e:
676 self.errors+= e.errors
677
678 def p_definition_3(self, p):
679 'definition : struct'
680 self.pdebug("p_definition_3", p)
681 p[0] = p[1]
682 try:
683 self.program.addStruct(p[0])
684 except ErrorException, e:
685 self.errors+= e.errors
686
687 def p_definition_4(self, p):
688 'definition : service'
689 self.pdebug("p_definition_4", p)
690 p[0] = p[1]
691 try:
692 self.program.addService(p[0])
693 except ErrorException, e:
694 self.errors+= e.errors
695
Marc Slemkod8b10512006-08-14 23:30:37 +0000696 def p_definition_5(self, p):
697 'definition : exception'
698 self.pdebug("p_definition_5", p)
699 p[0] = p[1]
700 try:
701 self.program.addStruct(p[0])
702 except ErrorException, e:
703 self.errors+= e.errors
704
Marc Slemko17859852006-08-15 00:21:31 +0000705 def p_definition_6(self, p):
706 'definition : namespace'
707 self.pdebug("p_definition_6", p)
708 p[0] = p[1]
709
Marc Slemkob2039e72006-08-09 01:00:17 +0000710 def p_typedef(self, p):
711 'typedef : TYPEDEF definitiontype ID'
712 self.pdebug("p_typedef", p)
Marc Slemko5b126d62006-08-11 23:03:42 +0000713 p[0] = TypedefType(p, p[3], p[2])
Marc Slemkob2039e72006-08-09 01:00:17 +0000714 try:
715 p[0].validate()
716
717 except ErrorException, e:
718 self.errors+= e.errors
719
Marc Slemkob2039e72006-08-09 01:00:17 +0000720 def p_enum(self, p):
721 'enum : ENUM ID LBRACE enumdeflist RBRACE'
722 self.pdebug("p_enum", p)
Marc Slemko5b126d62006-08-11 23:03:42 +0000723 p[0] = EnumType(p, p[2], p[4])
Marc Slemkob2039e72006-08-09 01:00:17 +0000724
725 try:
726 p[0].validate()
727 except ErrorException, e:
728 self.errors+= e.errors
729
730 def p_enumdeflist_1(self, p):
731 'enumdeflist : enumdeflist COMMA enumdef'
732 self.pdebug("p_enumdeflist_1", p)
733 p[0] = p[1] + (p[3],)
734
735 def p_enumdeflist_2(self, p):
736 'enumdeflist : enumdef'
737 self.pdebug("p_enumdeflist_2", p)
738 p[0] = (p[1],)
739
740 def p_enumdef_0(self, p):
741 'enumdef : ID ASSIGN ICONST'
742 self.pdebug("p_enumdef_0", p)
743 p[0] = EnumDef(p, p[1], int(p[3]))
744
745 def p_enumdef_1(self, p):
746 'enumdef : ID'
747 self.pdebug("p_enumdef_1", p)
748 p[0] = EnumDef(p, p[1])
749
750 def p_struct(self, p):
751 'struct : STRUCT ID LBRACE fieldlist RBRACE'
752 self.pdebug("p_struct", p)
Marc Slemko5b126d62006-08-11 23:03:42 +0000753 p[0] = StructType(p, p[2], p[4])
Marc Slemkob2039e72006-08-09 01:00:17 +0000754
755 try:
756 p[0].validate()
757 except ErrorException, e:
758 self.errors+= e.errors
759
Marc Slemkod8b10512006-08-14 23:30:37 +0000760 def p_exception(self, p):
761 'exception : EXCEPTION ID LBRACE fieldlist RBRACE'
762 self.pdebug("p_struct", p)
763 p[0] = ExceptionType(p, p[2], p[4])
764
765 try:
766 p[0].validate()
767 except ErrorException, e:
768 self.errors+= e.errors
769
Marc Slemko17859852006-08-15 00:21:31 +0000770 def p_namespace(self, p):
771 'namespace : NAMESPACE namespacespecifier'
772 self.pdebug("p_struct", p)
773 p[0] = p[2]
774
775 try:
776 self.program.validateNamespace(p[0])
777 except ErrorException, e:
778 self.errors+= e.errors
779
780 def p_namespacespecifier_1(self, p):
781 'namespacespecifier : ID'
782 self.pdebug("p_namespacespecifier", p)
783 p[0] = p[1]
784
785 def p_namespacespecifier_2(self, p):
786 'namespacespecifier : ID PERIOD namespacespecifier'
787 self.pdebug("p_namespacespecifier", p)
788 p[0] = p[1]+"."+p[3]
789
Marc Slemkob2039e72006-08-09 01:00:17 +0000790 def p_service(self, p):
791 'service : SERVICE ID LBRACE functionlist RBRACE'
792 self.pdebug("p_service", p)
793 p[0] = Service(p, p[2], p[4])
794 try:
795 p[0].validate()
796 except ErrorException, e:
797 self.errors+= e.errors
798
799 def p_functionlist_1(self, p):
Marc Slemkod8b10512006-08-14 23:30:37 +0000800 'functionlist : function COMMA functionlist'
Marc Slemkob2039e72006-08-09 01:00:17 +0000801 self.pdebug("p_functionlist_1", p)
Marc Slemkod8b10512006-08-14 23:30:37 +0000802 p[0] = (p[1],) + p[3]
Marc Slemkob2039e72006-08-09 01:00:17 +0000803
804 def p_functionlist_2(self, p):
Marc Slemkod8b10512006-08-14 23:30:37 +0000805 'functionlist : function'
Marc Slemkob2039e72006-08-09 01:00:17 +0000806 self.pdebug("p_functionlist_2", p)
Marc Slemkod8b10512006-08-14 23:30:37 +0000807 p[0] = (p[1],)
808
809 def p_functionlist_3(self, p):
810 'functionlist : '
811 self.pdebug("p_functionlist_3", p)
Marc Slemkob2039e72006-08-09 01:00:17 +0000812 p[0] = ()
813
814 def p_function(self, p):
Marc Slemkod8b10512006-08-14 23:30:37 +0000815 'function : functiontype functionmodifiers ID LPAREN fieldlist RPAREN exceptionspecifier'
Marc Slemkob2039e72006-08-09 01:00:17 +0000816 self.pdebug("p_function", p)
Marc Slemko5b126d62006-08-11 23:03:42 +0000817
Marc Slemkod8b10512006-08-14 23:30:37 +0000818 resultStruct = StructType(p, p[3]+"_result", (Field(p, p[1], Identifier(None, "success", 0)),)+p[7])
Marc Slemko5b126d62006-08-11 23:03:42 +0000819
820 p[0] = Function(p, p[3], resultStruct, StructType(p, p[3]+"_args", p[5]))
Marc Slemkob2039e72006-08-09 01:00:17 +0000821 try:
822 p[0].validate()
823 except ErrorException, e:
824 self.errors+= e.errors
825
826 def p_functionmodifiers(self, p):
827 'functionmodifiers :'
828 self.pdebug("p_functionmodifiers", p)
829 p[0] = ()
830
831 def p_fieldlist_1(self, p):
Marc Slemkod8b10512006-08-14 23:30:37 +0000832 'fieldlist : field COMMA fieldlist'
Marc Slemkob2039e72006-08-09 01:00:17 +0000833 self.pdebug("p_fieldlist_1", p)
Marc Slemkod8b10512006-08-14 23:30:37 +0000834 p[0] = (p[1],) + p[3]
Marc Slemkob2039e72006-08-09 01:00:17 +0000835
836 def p_fieldlist_2(self, p):
837 'fieldlist : field'
838 self.pdebug("p_fieldlist_2", p)
839 p[0] = (p[1],)
840
841 def p_fieldlist_3(self, p):
842 'fieldlist :'
843 self.pdebug("p_fieldlist_3", p)
844 p[0] = ()
845
846 def p_field_1(self, p):
847 'field : fieldtype ID ASSIGN ICONST'
848 self.pdebug("p_field_1", p)
849 p[0] = Field(p, p[1], Identifier(None, p[2], int(p[4])))
850
851 def p_field_2(self, p):
852 'field : fieldtype ID'
853 self.pdebug("p_field_2", p)
854 p[0] = Field(p, p[1], Identifier(None, p[2]))
855
Marc Slemkod8b10512006-08-14 23:30:37 +0000856 def p_exceptionSpecifier_1(self, p):
857 'exceptionspecifier : THROWS LPAREN fieldlist RPAREN'
858 self.pdebug("p_exceptionspecifier", p)
859 p[0] = p[3]
860
861 def p_exceptionSpecifier_2(self, p):
862 'exceptionspecifier : empty'
863 self.pdebug("p_exceptionspecifier", p)
864 p[0] = ()
865
Marc Slemkob2039e72006-08-09 01:00:17 +0000866 def p_definitiontype_1(self, p):
867 'definitiontype : basetype'
868 self.pdebug("p_definitiontype_1", p)
869 p[0] = p[1]
870
871 def p_definitiontype_2(self, p):
872 'definitiontype : collectiontype'
873 self.pdebug("p_definitiontype_2", p)
874 p[0] = p[1]
875
876 def p_functiontype_1(self, p):
877 'functiontype : fieldtype'
878 self.pdebug("p_functiontype_1", p)
879 p[0] = p[1]
880
881 def p_functiontype_2(self, p):
882 'functiontype : VOID'
883 self.pdebug("p_functiontype_2", p)
884 p[0] = self.program.primitiveMap[p[1].lower()]
885
886 def p_fieldtype_1(self, p):
887 'fieldtype : ID'
888 self.pdebug("p_fieldtype_1", p)
889 p[0] = Identifier(p, p[1])
890
891 def p_fieldtype_2(self, p):
892 'fieldtype : basetype'
893 self.pdebug("p_fieldtype_2", p)
894 p[0] = p[1]
895
896 def p_fieldtype_3(self, p):
897 'fieldtype : collectiontype'
898 self.pdebug("p_fieldtype_3", p)
899 p[0] = p[1]
900
901 def p_basetype_1(self, p):
902 'basetype : STRING'
903 self.pdebug("p_basetype_1", p)
904 p[0] = self.program.primitiveMap[p[1].lower()]
905
906 def p_basetype_2(self, p):
907 'basetype : BYTE'
908 self.pdebug("p_basetype_2", p)
909 p[0] = self.program.primitiveMap[p[1].lower()]
910
911 def p_basetype_3(self, p):
912 'basetype : I08'
913 self.pdebug("p_basetype_3", p)
914 p[0] = self.program.primitiveMap[p[1].lower()]
915
916 def p_basetype_4(self, p):
917 'basetype : U08'
918 self.pdebug("p_basetype_4", p)
919 p[0] = self.program.primitiveMap[p[1].lower()]
920
921 def p_basetype_5(self, p):
922 'basetype : I16'
923 self.pdebug("p_basetype_5", p)
924 p[0] = self.program.primitiveMap[p[1].lower()]
925
926 def p_basetype_6(self, p):
927 'basetype : U16'
928 self.pdebug("p_basetype_6", p)
929 p[0] = self.program.primitiveMap[p[1].lower()]
930
931 def p_basetype_7(self, p):
932 'basetype : I32'
933 self.pdebug("p_basetype_7", p)
934 p[0] = self.program.primitiveMap[p[1].lower()]
935
936 def p_basetype_8(self, p):
937 'basetype : U32'
938 self.pdebug("p_basetype_8", p)
939 p[0] = self.program.primitiveMap[p[1].lower()]
940
941 def p_basetype_9(self, p):
942 'basetype : I64'
943 self.pdebug("p_basetype_9", p)
944 p[0] = self.program.primitiveMap[p[1].lower()]
945
946 def p_basetype_10(self, p):
947 'basetype : U64'
948 self.pdebug("p_basetype_10", p)
949 p[0] = self.program.primitiveMap[p[1].lower()]
950
951 def p_basetype_11(self, p):
952 'basetype : UTF8'
953 self.pdebug("p_basetype_11", p)
954 p[0] = self.program.primitiveMap[p[1].lower()]
955
956 def p_basetype_12(self, p):
957 'basetype : UTF16'
958 self.pdebug("p_basetype_12", p)
959 p[0] = self.program.primitiveMap[p[1].lower()]
960
961 def p_basetype_13(self, p):
962 'basetype : DOUBLE'
963 self.pdebug("p_basetype_13", p)
964 p[0] = self.program.primitiveMap[p[1].lower()]
965
966 def p_collectiontype_1(self, p):
967 'collectiontype : maptype'
968 self.pdebug("p_collectiontype_1", p)
Marc Slemkoc0e07a22006-08-09 23:34:57 +0000969 p[0] = self.program.addCollection(p[1])
Marc Slemkob2039e72006-08-09 01:00:17 +0000970
971 def p_collectiontype_2(self, p):
972 'collectiontype : settype'
973 self.pdebug("p_collectiontype_2", p)
Marc Slemkoc0e07a22006-08-09 23:34:57 +0000974 p[0] = self.program.addCollection(p[1])
Marc Slemkob2039e72006-08-09 01:00:17 +0000975
976 def p_collectiontype_3(self, p):
977 'collectiontype : listtype'
978 self.pdebug("p_collectiontype_3", p)
Marc Slemkoc0e07a22006-08-09 23:34:57 +0000979 p[0] = self.program.addCollection(p[1])
Marc Slemkob2039e72006-08-09 01:00:17 +0000980
981 def p_maptype(self, p):
982 'maptype : MAP LANGLE fieldtype COMMA fieldtype RANGLE'
983 self.pdebug("p_maptype", p)
Marc Slemko5b126d62006-08-11 23:03:42 +0000984 p[0] = MapType(p, p[3], p[5])
Marc Slemkob2039e72006-08-09 01:00:17 +0000985
986 def p_settype(self, p):
987 'settype : SET LANGLE fieldtype RANGLE'
988 self.pdebug("p_settype", p)
Marc Slemko5b126d62006-08-11 23:03:42 +0000989 p[0] = SetType(p, p[3])
Marc Slemkob2039e72006-08-09 01:00:17 +0000990
991 def p_listtype(self, p):
992 'listtype : LIST LANGLE fieldtype RANGLE'
993 self.pdebug("p_listtype", p)
Marc Slemko5b126d62006-08-11 23:03:42 +0000994 p[0] = ListType(p, p[3])
Marc Slemkob2039e72006-08-09 01:00:17 +0000995
Marc Slemkod8b10512006-08-14 23:30:37 +0000996 def p_empty(self, p):
997 "empty : "
998 pass
999
Marc Slemkob2039e72006-08-09 01:00:17 +00001000 def p_error(self, p):
Marc Slemko27340eb2006-08-10 20:45:55 +00001001 # p_error is called with an empty token if eof was encountered unexpectedly.
1002 if not p:
1003 self.errors.append(SyntaxError("Unexpected end of file"))
1004 else:
1005 self.errors.append(SyntaxError(p))
Marc Slemkob2039e72006-08-09 01:00:17 +00001006
1007 def pdebug(self, name, p):
1008 if self.debug:
Marc Slemkod8b10512006-08-14 23:30:37 +00001009 print(name+"("+string.join(["P["+str(ix)+"]<<"+str(p[ix])+">>" for ix in range(len(p))], ", ")+")")
Marc Slemkob2039e72006-08-09 01:00:17 +00001010
1011 def __init__(self, **kw):
1012 self.debug = kw.get('debug', 0)
1013 self.names = { }
1014 self.program = Program()
1015 self.errors = []
1016
1017 try:
1018 modname = os.path.split(os.path.splitext(__file__)[0])[1] + "_" + self.__class__.__name__
1019 except:
1020 modname = "parser"+"_"+self.__class__.__name__
1021 self.debugfile = modname + ".dbg"
1022 self.tabmodule = modname + "_" + "parsetab"
1023 #print self.debugfile, self.tabmodule
1024
1025 # Build the lexer and parser
1026 lex.lex(module=self, debug=self.debug)
1027 yacc.yacc(module=self,
1028 debug=self.debug,
1029 debugfile=self.debugfile,
1030 tabmodule=self.tabmodule)
1031
1032 def parsestring(self, s, filename=""):
1033 yacc.parse(s)
1034
1035 if len(self.errors) == 0:
1036 try:
1037 self.program.validate()
1038 except ErrorException, e:
1039 self.errors+= e.errors
1040
1041 if len(self.errors):
1042 for error in self.errors:
1043 print(filename+":"+str(error))
1044
1045 def parse(self, filename, doPickle=True):
1046
1047 f = file(filename, "r")
1048
1049 self.parsestring(f.read(), filename)
1050
1051 if len(self.errors) == 0 and doPickle:
1052
1053 outf = file(os.path.splitext(filename)[0]+".thyc", "w")
1054
1055 pickle.dump(self.program, outf)