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