blob: af428fbce5861775720cc7f3a622242854055452 [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):
37 def __init__(self, lexToken):
38 Error.__init__(self, lexToken.lineno, lexToken.lineno, "syntax error "+str(lexToken.value))
39
40class SymanticsError(Error):
41
42 def __init__(self, definition, message):
43 Error.__init__(self, definition.start, definition.end, message)
44 self.definition = definition
45
46 def __str__(self):
47 return str(self.start)+": error: "+self.message
48
49class ErrorException(Exception):
50
51 def __init__(self, errors=None):
52 self.errors = errors
53
54class Definition(object):
55 """ Abstract thrift IDL definition unit """
56
57 def __init__(self, symbols=None, name="", id=None):
58 if symbols:
59 self.lines(symbols)
60 self.name = name
61 self.id = id
62
63 def validate(self):
64 pass
65
66 def lines(self, symbols):
67 self.start = symbols.lineno(1)
68 self.end = symbols.lineno(len(symbols) - 1)
69
70class Identifier(Definition):
71 """ An Identifier - name and optional integer id """
72
73 def __init__(self, symbols, name, id=None):
74 Definition.__init__(self, symbols, name, id)
75
76 def __str__(self):
77 result = self.name
78 if self.id != 0:
79 result+="="+str(self.id)
80 return result
81
82class Type(Definition):
83 """ Abstract Type definition """
84
85 def __init__(self, symbols, name):
86 Definition.__init__(self, symbols, name)
87 self.name = name
88
89 def __str__(self):
90 return self.name
91
92class TypeDef(Type):
93
94 def __init__(self, symbols, name, definitionType):
95 Type.__init__(self, symbols, name)
96 self.definitionType = definitionType
97
98 def __str__(self):
99 return self.name+"<"+str(self.name)+", "+str(self.definitionType)+">"
100
101""" Primitive Types """
102
103class PrimitiveType(Type):
104
105 def __init__(self, name):
106 Type.__init__(self, None, name)
107
108
Marc Slemkoc0e07a22006-08-09 23:34:57 +0000109STOP_TYPE = PrimitiveType("stop")
Marc Slemkob2039e72006-08-09 01:00:17 +0000110VOID_TYPE = PrimitiveType("void")
111BOOL_TYPE = PrimitiveType("bool")
112STRING_TYPE =PrimitiveType("utf7")
113UTF7_TYPE = PrimitiveType("utf7")
114UTF8_TYPE = PrimitiveType("utf8")
115UTF16_TYPE = PrimitiveType("utf16")
116BYTE_TYPE = PrimitiveType("u08")
117I08_TYPE = PrimitiveType("i08")
118I16_TYPE = PrimitiveType("i16")
119I32_TYPE = PrimitiveType("i32")
120I64_TYPE = PrimitiveType("i64")
121U08_TYPE = PrimitiveType("u08")
122U16_TYPE = PrimitiveType("u16")
123U32_TYPE = PrimitiveType("u32")
124U64_TYPE = PrimitiveType("u64")
125FLOAT_TYPE = PrimitiveType("float")
126
127PRIMITIVE_MAP = {
Marc Slemkoc0e07a22006-08-09 23:34:57 +0000128 "stop" : STOP_TYPE,
Marc Slemkob2039e72006-08-09 01:00:17 +0000129 "void" : VOID_TYPE,
130 "bool" : BOOL_TYPE,
131 "string": UTF7_TYPE,
132 "utf7": UTF7_TYPE,
133 "utf8": UTF8_TYPE,
134 "utf16": UTF16_TYPE,
135 "byte" : U08_TYPE,
136 "i08": I08_TYPE,
137 "i16": I16_TYPE,
138 "i32": I32_TYPE,
139 "i64": I64_TYPE,
140 "u08": U08_TYPE,
141 "u16": U16_TYPE,
142 "u32": U32_TYPE,
143 "u64": U64_TYPE,
144 "float": FLOAT_TYPE
145}
146
147""" Collection Types """
148
149class CollectionType(Type):
150
151 def __init__(self, symbols, name):
152 Type.__init__(self, symbols, name)
153
154class Map(CollectionType):
155
156 def __init__(self, symbols, keyType, valueType):
157 CollectionType.__init__(self, symbols, "map<"+keyType.name+","+valueType.name +">")
158 self.keyType = keyType
159 self.valueType = valueType
160
161class Set(CollectionType):
162
163 def __init__(self, symbols, valueType):
164 CollectionType.__init__(self, symbols, "set<"+valueType.name+">")
165 self.valueType = valueType
166
167class List(CollectionType):
168
169 def __init__(self, symbols, valueType):
170 CollectionType.__init__(self, symbols, "list<"+valueType.name+">")
171 self.valueType = valueType
172
173class Enum(Definition):
174
175 def __init__(self, symbols, name, enumDefs):
176 Definition.__init__(self, symbols, name)
177 self.enumDefs = enumDefs
178
179 def validate(self):
180 ids = {}
181 names = {}
182 errors = []
183
184 for enumDef in self.enumDefs:
185
186 if enumDef.name in names:
187 errors.append(SymanticsError(enumDef, self.name+"."+str(enumDef.name)+" already defined at line "+str(names[enumDef.name].start)))
188 else:
189 names[enumDef.name] = enumDef
190
191 if enumDef.id != None:
192 oldEnumDef = ids.get(enumDef.id)
193 if oldEnumDef:
194 errors.append(SymanticsError(enumDef, "enum "+self.name+" \""+str(enumDef.name)+"\" uses constant already assigned to \""+oldEnumDef.name+"\""))
195 else:
196 ids[enumDef.id] = enumDef
197
198 if len(errors):
199 raise ErrorException(errors)
200
201 def assignId(enumDef, currentId, ids):
202 'Finds the next available id number for an enum definition'
203
204 id= currentId + 1
205
206 while id in ids:
207 id += 1
208
209 enumDef.id = id
210
211 ids[enumDef.id] = enumDef
212
213 # assign ids for all enum defs with unspecified ids
214
215 currentId = 0
216
217 for enumDef in self.enumDefs:
218 if not enumDef.id:
219 assignId(enumDef, currentId, ids)
220 currentId = enumDef.id
221
222 def __repr__(self):
223 return str(self)
224
225 def __str__(self):
226 return self.name+"<"+string.join(map(lambda enumDef: str(enumDef), self.enumDefs), ", ")
227
228class EnumDef(Definition):
229
230 def __init__(self, symbols, name, id=None):
231 Definition.__init__(self, symbols, name, id)
232
233 def __repr__(self):
234 return str(self)
235
236 def __str__(self):
237 result = self.name
238 if self.id:
239 result+= ":"+str(self.id)
240 return result
241
242
243class Field(Definition):
244
245 def __init__(self, symbols, type, identifier):
246 Definition.__init__(self, symbols, identifier.name, identifier.id)
247 self.type = type
248 self.identifier = identifier
249
250 def __str__(self):
251 return "<"+str(self.type)+", "+str(self.identifier)+">"
252
253def validateFieldList(fieldList):
254
255 errors = []
256 names = {}
257 ids = {}
258
259 for field in fieldList:
260
261 if field.name in names:
262 oldField = names[field.name]
263 errors.append(SymanticsError(field, "field \""+field.name+"\" already defined at "+str(oldField.start)))
264 else:
265 names[field.name] = field
266
267 if field.id != None:
268 oldField = ids.get(field.id)
269 if oldField:
270 errors.append(SymanticsError(field, "field \""+field.name+"\" uses constant already assigned to \""+oldField.name+"\""))
271 else:
272 ids[field.id] = field
273
274 if len(errors):
275 raise ErrorException(errors)
276
Marc Slemkoc0e07a22006-08-09 23:34:57 +0000277 def assignId(field, currentId, ids):
278 'Finds the next available id number for a field'
279 id= currentId - 1
280
281 while id in ids:
282 id -= 1
283
284 field.id = id
285
286 ids[field.id] = field
287
288 return id
289
290 # assign ids for all fields with unspecified ids
291
292 currentId = 0
293
294 for fields in fieldList:
295 if not field.id:
296 currentId = assignId(field, currentId, ids)
297
Marc Slemkob2039e72006-08-09 01:00:17 +0000298class Struct(Type):
299
300 def __init__(self, symbols, name, fieldList):
301 Type.__init__(self, symbols, name)
302 self.fieldList = fieldList
303
304 def validate(self):
305 validateFieldList(self.fieldList)
306
307 def __str__(self):
308 return self.name+"<"+string.join(map(lambda a: str(a), self.fieldList), ", ")+">"
309
310class Function(Definition):
311
312 def __init__(self, symbols, name, resultType, argFieldList):
313 Definition.__init__(self, symbols, name)
314 self.resultType = resultType
315 self.argFieldList = argFieldList
316
317 def validate(self):
318 validateFieldList(self.argFieldList)
319
320 def __str__(self):
321 return self.name+"("+string.join(map(lambda a: str(a), self.argFieldList), ", ")+") => "+str(self.resultType)
322
323class Service(Definition):
324
325 def __init__(self, symbols, name, functionList):
326 Definition.__init__(self, symbols, name)
327 self.functionList = functionList
328
329 def validate(self):
330
331 errors = []
332 functionNames = {}
333 for function in self.functionList:
334 if function.name in functionNames:
335 oldFunction = functionName[function.name]
336 errors.append(SymanticsError(function, "function "+function.name+" already defined at "+str(oldFunction.start)))
337
338 if len(errors):
339 raise ErrorException(errors)
340
341 def __str__(self):
342 return self.name+"("+string.join(map(lambda a: str(a), self.functionList), ", ")+")"
343
344class Program(object):
345
346 def __init__(self, symbols=None, name="", definitions=None, serviceMap=None, typedefMap=None, enumMap=None, structMap=None, collectionMap=None,
347 primitiveMap=None):
348
349 self.name = name
350
351 if not definitions:
352 definitions = []
353 self.definitions = definitions
354
355 if not serviceMap:
356 serviceMap = {}
357 self.serviceMap = serviceMap
358
359 if not typedefMap:
360 typedefMap = {}
361 self.typedefMap = typedefMap
362
363 if not enumMap:
364 enumMap = {}
365 self.enumMap = enumMap
366
367 if not structMap:
368 structMap = {}
369 self.structMap = structMap
370
371 if not collectionMap:
372 collectionMap = {}
373 self.collectionMap = collectionMap
374
375 if not primitiveMap:
376 primitiveMap = PRIMITIVE_MAP
377 self.primitiveMap = primitiveMap
378
379 def addDefinition(self, definition, definitionMap, definitionTypeName):
380
381 oldDefinition = definitionMap.get(definition.name)
382 if oldDefinition:
383 raise ErrorException([SymanticsError(definition, definitionTypeName+" "+definition.name+" is already defined at "+str(oldDefinition.start))])
384 else:
385 definitionMap[definition.name] = definition
386
387 # keep an ordered list of definitions so that stub/skel generators can determine the original order
388
389 self.definitions.append(definition)
390
391 def addStruct(self, struct):
392 self.addDefinition(struct, self.structMap, "struct")
393
394 def addTypedef(self, typedef):
395 self.addDefinition(typedef, self.typedefMap, "typedef")
396
397 def addEnum(self, enum):
398 self.addDefinition(enum, self.enumMap, "enum")
399
400 def addService(self, service):
401 self.addDefinition(service, self.serviceMap, "service")
402
403 def addCollection(self, collection):
404 if collection.name in self.collectionMap:
Marc Slemkoc0e07a22006-08-09 23:34:57 +0000405 return self.collectionMap[collection.name]
Marc Slemkob2039e72006-08-09 01:00:17 +0000406 else:
407 self.collectionMap[collection.name] = collection
Marc Slemkoc0e07a22006-08-09 23:34:57 +0000408 return collection
Marc Slemkob2039e72006-08-09 01:00:17 +0000409
410 def getType(self, parent, symbol):
411 """ Get the type definition for a symbol"""
412
413 typeName = None
414
415 if isinstance(symbol, Type):
416 return symbol
417 elif isinstance(symbol, Field):
418 typeName = symbol.type.name
419 elif isinstance(symbol, Identifier):
420 typeName = symbol.name
421 else:
422 raise ErrorException([SymanticsError(parent, "unknown symbol \""+str(symbol)+"\"")])
423
424 for map in (self.primitiveMap, self.collectionMap, self.typedefMap, self.enumMap, self.structMap):
425 if typeName in map:
426 return map[typeName]
427
428 raise ErrorException([SymanticsError(parent, "\""+typeName+"\" is not defined.")])
429
430 def hasType(self, parent, symbol):
431 """ Determine if a type definition exists for the symbol"""
432
433 return self.getType(parent, symbol) == True
434
435 def validate(self):
436
437 errors = []
438
439 # Verify that struct fields types, collection key and element types, and typedef defined types exists and replaces
440 # type names with references to the type objects
441
442 for struct in self.structMap.values():
443 for field in struct.fieldList:
444 try:
445 field.type = self.getType(struct, field)
446 except ErrorException, e:
447 errors+= e.errors
448
449 for collection in self.collectionMap.values():
450 try:
451 if isinstance(collection, Map):
452 collection.keyType = self.getType(collection, collection.keyType)
453
454 collection.valueType = self.getType(collection, collection.valueType)
455
456 except ErrorException, e:
457 errors+= e.errors
458
459 for typedef in self.typedefMap.values():
460 try:
461 typedef.definitionType = self.getType(self, typedef.definitionType)
462
463 except ErrorException, e:
464 errors+= e.errors
465
Marc Slemkoc0e07a22006-08-09 23:34:57 +0000466 # 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 +0000467
468 for service in self.serviceMap.values():
Marc Slemkoc0e07a22006-08-09 23:34:57 +0000469
Marc Slemkob2039e72006-08-09 01:00:17 +0000470 for function in service.functionList:
471 try:
Marc Slemkoc0e07a22006-08-09 23:34:57 +0000472 function.resultType = self.getType(service, function.resultType)
Marc Slemkob2039e72006-08-09 01:00:17 +0000473 except ErrorException, e:
474 errors+= e.errors
475
476 for field in function.argFieldList:
477 try:
478 field.type = self.getType(function, field)
479 except ErrorException, e:
480 errors+= e.errors
481
482 if len(errors):
483 raise ErrorException(errors)
484
485
486class Parser(object):
487
488 reserved = ("BYTE",
489 # "CONST",
490 "DOUBLE",
491 "ENUM",
492 # "EXCEPTION",
493 # "EXTENDS",
494 "I08",
495 "I16",
496 "I32",
497 "I64",
498 "LIST",
499 "MAP",
500 "SERVICE",
501 "SET",
502 # "STATIC",
503 "STRING",
504 "STRUCT",
505 # "SYNCHRONIZED",
506 "TYPEDEF",
507 "U08",
508 "U16",
509 "U32",
510 "U64",
511 "UTF16",
512 "UTF8",
513 "VOID"
514 )
515
516 tokens = reserved + (
517 # Literals (identifier, integer constant, float constant, string constant, char const)
518 'ID', 'ICONST', 'SCONST', 'FCONST',
519 # Operators default=, optional*, variable...
520 'ASSIGN', #'OPTIONAL', 'ELLIPSIS',
521 # Delimeters ( ) { } < > , . ; :
522 'LPAREN', 'RPAREN',
523 'LBRACE', 'RBRACE',
524 'LANGLE', 'RANGLE',
525 'COMMA' #, 'PERIOD', 'SEMI' , 'COLON'
526 )
527
528 precendence = ()
529
530 reserved_map = {}
531
532 for r in reserved:
533 reserved_map[r.lower()] = r
534
535 def t_ID(self, t):
536 r'[A-Za-z_][\w_]*'
537 t.type = self.reserved_map.get(t.value,"ID")
538 return t
539
540 # Completely ignored characters
541 t_ignore = ' \t\x0c'
542
543# t_OPTIONAL = r'\*'
544 t_ASSIGN = r'='
545
546 # Delimeters
547 t_LPAREN = r'\('
548 t_RPAREN = r'\)'
549 t_LANGLE = r'\<'
550 t_RANGLE = r'\>'
551 t_LBRACE = r'\{'
552 t_RBRACE = r'\}'
553 t_COMMA = r','
554# t_PERIOD = r'\.'
555# t_SEMI = r';'
556# t_COLON = r':'
557# t_ELLIPSIS = r'\.\.\.'
558
559 # Integer literal
560 t_ICONST = r'\d+([uU]|[lL]|[uU][lL]|[lL][uU])?'
561
562 # Floating literal
563 t_FCONST = r'((\d+)(\.\d+)(e(\+|-)?(\d+))? | (\d+)e(\+|-)?(\d+))([lL]|[fF])?'
564
565 # String literal
566 t_SCONST = r'\"([^\\\n]|(\\.))*?\"'
567
568 # Comments
569 def t_comment(self, t):
570 r'(?:/\*(.|\n)*?\*/)|(?://[^\n]*\n)'
571 t.lineno += t.value.count('\n')
572
573 def t_error(self, t):
574 print "Illegal character %s" % repr(t.value[0])
575 t.skip(1)
576
577 # Newlines
578 def t_newline(self, t):
579 r'\n+'
580 t.lineno += t.value.count("\n")
581
582 def p_program(self, p):
583 'program : definitionlist'
584 pass
585
586 def p_definitionlist_1(self, p):
587 'definitionlist : definitionlist definition'
588 pass
589
590 def p_definitionlist_2(self, p):
591 'definitionlist :'
592 pass
593
594 def p_definition_1(self, p):
595 'definition : typedef'
596 self.pdebug("p_definition_1", p)
597 p[0] = p[1]
598 try:
599 self.program.addTypedef(p[0])
600 except ErrorException, e:
601 self.errors+= e.errors
602
603 def p_definition_2(self, p):
604 'definition : enum'
605 self.pdebug("p_definition_2", p)
606 p[0] = p[1]
607 try:
608 self.program.addEnum(p[0])
609 except ErrorException, e:
610 self.errors+= e.errors
611
612 def p_definition_3(self, p):
613 'definition : struct'
614 self.pdebug("p_definition_3", p)
615 p[0] = p[1]
616 try:
617 self.program.addStruct(p[0])
618 except ErrorException, e:
619 self.errors+= e.errors
620
621 def p_definition_4(self, p):
622 'definition : service'
623 self.pdebug("p_definition_4", p)
624 p[0] = p[1]
625 try:
626 self.program.addService(p[0])
627 except ErrorException, e:
628 self.errors+= e.errors
629
630 def p_typedef(self, p):
631 'typedef : TYPEDEF definitiontype ID'
632 self.pdebug("p_typedef", p)
633 p[0] = TypeDef(p, p[3], p[2])
634 try:
635 p[0].validate()
636
637 except ErrorException, e:
638 self.errors+= e.errors
639
640# def p_definition_or_referencye_type_1(self, p):
641# XXX need to all typedef struct foo foo_t by allowing references
642# pass
643
644 def p_enum(self, p):
645 'enum : ENUM ID LBRACE enumdeflist RBRACE'
646 self.pdebug("p_enum", p)
647 p[0] = Enum(p, p[2], p[4])
648
649 try:
650 p[0].validate()
651 except ErrorException, e:
652 self.errors+= e.errors
653
654 def p_enumdeflist_1(self, p):
655 'enumdeflist : enumdeflist COMMA enumdef'
656 self.pdebug("p_enumdeflist_1", p)
657 p[0] = p[1] + (p[3],)
658
659 def p_enumdeflist_2(self, p):
660 'enumdeflist : enumdef'
661 self.pdebug("p_enumdeflist_2", p)
662 p[0] = (p[1],)
663
664 def p_enumdef_0(self, p):
665 'enumdef : ID ASSIGN ICONST'
666 self.pdebug("p_enumdef_0", p)
667 p[0] = EnumDef(p, p[1], int(p[3]))
668
669 def p_enumdef_1(self, p):
670 'enumdef : ID'
671 self.pdebug("p_enumdef_1", p)
672 p[0] = EnumDef(p, p[1])
673
674 def p_struct(self, p):
675 'struct : STRUCT ID LBRACE fieldlist RBRACE'
676 self.pdebug("p_struct", p)
677 p[0] = Struct(p, p[2], p[4])
678
679 try:
680 p[0].validate()
681 except ErrorException, e:
682 self.errors+= e.errors
683
684 def p_service(self, p):
685 'service : SERVICE ID LBRACE functionlist RBRACE'
686 self.pdebug("p_service", p)
687 p[0] = Service(p, p[2], p[4])
688 try:
689 p[0].validate()
690 except ErrorException, e:
691 self.errors+= e.errors
692
693 def p_functionlist_1(self, p):
694 'functionlist : functionlist function'
695 self.pdebug("p_functionlist_1", p)
696 p[0] = p[1] + (p[2],)
697
698 def p_functionlist_2(self, p):
699 'functionlist :'
700 self.pdebug("p_functionlist_2", p)
701 p[0] = ()
702
703 def p_function(self, p):
704 'function : functiontype functionmodifiers ID LPAREN fieldlist RPAREN'
705 self.pdebug("p_function", p)
706 p[0] = Function(p, p[3], p[1], p[5])
707 try:
708 p[0].validate()
709 except ErrorException, e:
710 self.errors+= e.errors
711
712 def p_functionmodifiers(self, p):
713 'functionmodifiers :'
714 self.pdebug("p_functionmodifiers", p)
715 p[0] = ()
716
717 def p_fieldlist_1(self, p):
718 'fieldlist : fieldlist COMMA field'
719 self.pdebug("p_fieldlist_1", p)
720 p[0] = p[1] + (p[3],)
721
722 def p_fieldlist_2(self, p):
723 'fieldlist : field'
724 self.pdebug("p_fieldlist_2", p)
725 p[0] = (p[1],)
726
727 def p_fieldlist_3(self, p):
728 'fieldlist :'
729 self.pdebug("p_fieldlist_3", p)
730 p[0] = ()
731
732 def p_field_1(self, p):
733 'field : fieldtype ID ASSIGN ICONST'
734 self.pdebug("p_field_1", p)
735 p[0] = Field(p, p[1], Identifier(None, p[2], int(p[4])))
736
737 def p_field_2(self, p):
738 'field : fieldtype ID'
739 self.pdebug("p_field_2", p)
740 p[0] = Field(p, p[1], Identifier(None, p[2]))
741
742 def p_definitiontype_1(self, p):
743 'definitiontype : basetype'
744 self.pdebug("p_definitiontype_1", p)
745 p[0] = p[1]
746
747 def p_definitiontype_2(self, p):
748 'definitiontype : collectiontype'
749 self.pdebug("p_definitiontype_2", p)
750 p[0] = p[1]
751
752 def p_functiontype_1(self, p):
753 'functiontype : fieldtype'
754 self.pdebug("p_functiontype_1", p)
755 p[0] = p[1]
756
757 def p_functiontype_2(self, p):
758 'functiontype : VOID'
759 self.pdebug("p_functiontype_2", p)
760 p[0] = self.program.primitiveMap[p[1].lower()]
761
762 def p_fieldtype_1(self, p):
763 'fieldtype : ID'
764 self.pdebug("p_fieldtype_1", p)
765 p[0] = Identifier(p, p[1])
766
767 def p_fieldtype_2(self, p):
768 'fieldtype : basetype'
769 self.pdebug("p_fieldtype_2", p)
770 p[0] = p[1]
771
772 def p_fieldtype_3(self, p):
773 'fieldtype : collectiontype'
774 self.pdebug("p_fieldtype_3", p)
775 p[0] = p[1]
776
777 def p_basetype_1(self, p):
778 'basetype : STRING'
779 self.pdebug("p_basetype_1", p)
780 p[0] = self.program.primitiveMap[p[1].lower()]
781
782 def p_basetype_2(self, p):
783 'basetype : BYTE'
784 self.pdebug("p_basetype_2", p)
785 p[0] = self.program.primitiveMap[p[1].lower()]
786
787 def p_basetype_3(self, p):
788 'basetype : I08'
789 self.pdebug("p_basetype_3", p)
790 p[0] = self.program.primitiveMap[p[1].lower()]
791
792 def p_basetype_4(self, p):
793 'basetype : U08'
794 self.pdebug("p_basetype_4", p)
795 p[0] = self.program.primitiveMap[p[1].lower()]
796
797 def p_basetype_5(self, p):
798 'basetype : I16'
799 self.pdebug("p_basetype_5", p)
800 p[0] = self.program.primitiveMap[p[1].lower()]
801
802 def p_basetype_6(self, p):
803 'basetype : U16'
804 self.pdebug("p_basetype_6", p)
805 p[0] = self.program.primitiveMap[p[1].lower()]
806
807 def p_basetype_7(self, p):
808 'basetype : I32'
809 self.pdebug("p_basetype_7", p)
810 p[0] = self.program.primitiveMap[p[1].lower()]
811
812 def p_basetype_8(self, p):
813 'basetype : U32'
814 self.pdebug("p_basetype_8", p)
815 p[0] = self.program.primitiveMap[p[1].lower()]
816
817 def p_basetype_9(self, p):
818 'basetype : I64'
819 self.pdebug("p_basetype_9", p)
820 p[0] = self.program.primitiveMap[p[1].lower()]
821
822 def p_basetype_10(self, p):
823 'basetype : U64'
824 self.pdebug("p_basetype_10", p)
825 p[0] = self.program.primitiveMap[p[1].lower()]
826
827 def p_basetype_11(self, p):
828 'basetype : UTF8'
829 self.pdebug("p_basetype_11", p)
830 p[0] = self.program.primitiveMap[p[1].lower()]
831
832 def p_basetype_12(self, p):
833 'basetype : UTF16'
834 self.pdebug("p_basetype_12", p)
835 p[0] = self.program.primitiveMap[p[1].lower()]
836
837 def p_basetype_13(self, p):
838 'basetype : DOUBLE'
839 self.pdebug("p_basetype_13", p)
840 p[0] = self.program.primitiveMap[p[1].lower()]
841
842 def p_collectiontype_1(self, p):
843 'collectiontype : maptype'
844 self.pdebug("p_collectiontype_1", p)
Marc Slemkoc0e07a22006-08-09 23:34:57 +0000845 p[0] = self.program.addCollection(p[1])
Marc Slemkob2039e72006-08-09 01:00:17 +0000846
847 def p_collectiontype_2(self, p):
848 'collectiontype : settype'
849 self.pdebug("p_collectiontype_2", p)
Marc Slemkoc0e07a22006-08-09 23:34:57 +0000850 p[0] = self.program.addCollection(p[1])
Marc Slemkob2039e72006-08-09 01:00:17 +0000851
852 def p_collectiontype_3(self, p):
853 'collectiontype : listtype'
854 self.pdebug("p_collectiontype_3", p)
Marc Slemkoc0e07a22006-08-09 23:34:57 +0000855 p[0] = self.program.addCollection(p[1])
Marc Slemkob2039e72006-08-09 01:00:17 +0000856
857 def p_maptype(self, p):
858 'maptype : MAP LANGLE fieldtype COMMA fieldtype RANGLE'
859 self.pdebug("p_maptype", p)
860 p[0] = Map(p, p[3], p[5])
861
862 def p_settype(self, p):
863 'settype : SET LANGLE fieldtype RANGLE'
864 self.pdebug("p_settype", p)
865 p[0] = Set(p, p[3])
866
867 def p_listtype(self, p):
868 'listtype : LIST LANGLE fieldtype RANGLE'
869 self.pdebug("p_listtype", p)
Marc Slemkoc4eb9e82006-08-10 03:29:29 +0000870 p[0] = List(p, p[3])
Marc Slemkob2039e72006-08-09 01:00:17 +0000871
872 def p_error(self, p):
873 self.errors.append(SyntaxError(p))
874
875 def pdebug(self, name, p):
876 if self.debug:
877 print(name+"("+string.join(map(lambda t: "<<"+str(t)+">>", p), ", ")+")")
878
879 def __init__(self, **kw):
880 self.debug = kw.get('debug', 0)
881 self.names = { }
882 self.program = Program()
883 self.errors = []
884
885 try:
886 modname = os.path.split(os.path.splitext(__file__)[0])[1] + "_" + self.__class__.__name__
887 except:
888 modname = "parser"+"_"+self.__class__.__name__
889 self.debugfile = modname + ".dbg"
890 self.tabmodule = modname + "_" + "parsetab"
891 #print self.debugfile, self.tabmodule
892
893 # Build the lexer and parser
894 lex.lex(module=self, debug=self.debug)
895 yacc.yacc(module=self,
896 debug=self.debug,
897 debugfile=self.debugfile,
898 tabmodule=self.tabmodule)
899
900 def parsestring(self, s, filename=""):
901 yacc.parse(s)
902
903 if len(self.errors) == 0:
904 try:
905 self.program.validate()
906 except ErrorException, e:
907 self.errors+= e.errors
908
909 if len(self.errors):
910 for error in self.errors:
911 print(filename+":"+str(error))
912
913 def parse(self, filename, doPickle=True):
914
915 f = file(filename, "r")
916
917 self.parsestring(f.read(), filename)
918
919 if len(self.errors) == 0 and doPickle:
920
921 outf = file(os.path.splitext(filename)[0]+".thyc", "w")
922
923 pickle.dump(self.program, outf)