|  | # | 
|  | # simple generator for Thrift | 
|  | # | 
|  |  | 
|  | import sys | 
|  | import os | 
|  | import cStringIO | 
|  | import operator | 
|  |  | 
|  | import parser | 
|  | import ezt | 
|  |  | 
|  |  | 
|  | ### temporary | 
|  | PATH = '/Users/gstein/src/asf/thrift/compiler/py/src/templates-py' | 
|  | t_py = ezt.Template(os.path.join(PATH, 'py.ezt'), | 
|  | compress_whitespace=False) | 
|  | t_py_ser = ezt.Template(os.path.join(PATH, 'py_ser.ezt'), | 
|  | compress_whitespace=False) | 
|  | t_py_deser = ezt.Template(os.path.join(PATH, 'py_deser.ezt'), | 
|  | compress_whitespace=False) | 
|  | t_py_cvalue = ezt.Template(os.path.join(PATH, 'py_cvalue.ezt'), | 
|  | compress_whitespace=False) | 
|  |  | 
|  |  | 
|  | def generate(program): | 
|  | t_py.generate(sys.stdout, Proxy(program)) | 
|  |  | 
|  |  | 
|  | class AutoVars(object): | 
|  | def __init__(self): | 
|  | self._counter = 0 | 
|  | self._mapping = { } | 
|  | self._saved = [ ] | 
|  |  | 
|  | def open_context(self): | 
|  | self._saved.append(self._mapping) | 
|  | self._mapping = { } | 
|  |  | 
|  | def close_context(self): | 
|  | self._mapping = self._saved.pop() | 
|  |  | 
|  | def __getattr__(self, name): | 
|  | if name.startswith('__'): | 
|  | raise AttributeError(name) | 
|  |  | 
|  | if name in self._mapping: | 
|  | return self._mapping[name] | 
|  | var = '%s%d' % (name, self._counter) | 
|  | self._counter += 1 | 
|  | self._mapping[name] = var | 
|  | return var | 
|  |  | 
|  |  | 
|  | class Proxy(object): | 
|  | def __init__(self, ob): | 
|  | self._ob = ob | 
|  |  | 
|  | for name, value in vars(ob).items(): | 
|  | proxy = custom_proxy(value) | 
|  | if proxy: | 
|  | value = proxy(value) | 
|  | elif isinstance(value, list) and value: | 
|  | # lists are homogenous, so check the first item | 
|  | proxy = custom_proxy(value[0]) | 
|  | if proxy: | 
|  | value = [proxy(ob) for ob in value] | 
|  | elif hasattr(value[0], '__dict__'): | 
|  | value = [Proxy(ob) for ob in value] | 
|  | setattr(self, name, value) | 
|  |  | 
|  | def __getattr__(self, name): | 
|  | if name == 'auto': | 
|  | return g_auto | 
|  | raise AttributeError(name) | 
|  |  | 
|  |  | 
|  | class ProxyFieldType(Proxy): | 
|  | def __getattr__(self, name): | 
|  | if name == 'serializer': | 
|  | return Subtemplate(t_py_ser, self) | 
|  | if name == 'deserializer': | 
|  | return Subtemplate(t_py_deser, self) | 
|  | return Proxy.__getattr__(self, name) | 
|  |  | 
|  |  | 
|  | class Subtemplate(object): | 
|  | def __init__(self, template, data): | 
|  | self._template = template | 
|  | self._data = data | 
|  |  | 
|  | def __getattr__(self, name): | 
|  | # jam the name of the result variable into the data params | 
|  | self._data.result_var = getattr(g_auto, name) | 
|  |  | 
|  | # use a new variable context for this template generation | 
|  | g_auto.open_context() | 
|  | value = gen_value(self._template, self._data) | 
|  | g_auto.close_context() | 
|  |  | 
|  | return value | 
|  |  | 
|  |  | 
|  | class ProxyField(Proxy): | 
|  | def __getattr__(self, name): | 
|  | if name == 'type_enum': | 
|  | return TYPE_ENUM.get(self._ob.field_type.ident, | 
|  | self._ob.field_type.ident.tvalue) | 
|  | return Proxy.__getattr__(self, name) | 
|  |  | 
|  |  | 
|  | class ProxyStruct(Proxy): | 
|  | def __getattr__(self, name): | 
|  | if name == 'sorted_fields': | 
|  | highest = max(int(f.field_id or -1) for f in self._ob.fields) | 
|  | fields = [None] * (highest + 1) | 
|  | for field in self._ob.fields: | 
|  | if field.field_id: | 
|  | id = int(field.field_id) | 
|  | if id > 0: | 
|  | fields[id] = ProxyField(field) | 
|  | return fields | 
|  | return Proxy.__getattr__(self, name) | 
|  |  | 
|  |  | 
|  | class ProxyConstValue(Proxy): | 
|  | def __getattr__(self, name): | 
|  | if name == 'cvalue': | 
|  | return gen_value(t_py_cvalue, self) | 
|  | return Proxy.__getattr__(self, name) | 
|  |  | 
|  |  | 
|  | def custom_proxy(value): | 
|  | if isinstance(value, parser.FieldType): | 
|  | return ProxyFieldType | 
|  | if isinstance(value, parser.Field): | 
|  | return ProxyField | 
|  | if isinstance(value, parser.Struct): | 
|  | return ProxyStruct | 
|  | if isinstance(value, parser.ConstValue): | 
|  | return ProxyConstValue | 
|  | return None | 
|  |  | 
|  |  | 
|  | TYPE_ENUM = { | 
|  | parser.ID_STRING: 'TType.STRING', | 
|  | parser.ID_BOOL: 'TType.BOOL', | 
|  | parser.ID_BYTE: 'TType.BYTE', | 
|  | parser.ID_I16: 'TType.I16', | 
|  | parser.ID_I32: 'TType.I32', | 
|  | parser.ID_I64: 'TType.I64', | 
|  | parser.ID_DOUBLE: 'TType.DOUBLE', | 
|  | parser.ID_MAP: 'TType.MAP', | 
|  | parser.ID_SET: 'TType.SET', | 
|  | parser.ID_LIST: 'TType.LIST', | 
|  | # TType.STRUCT and TType.I32 for enums | 
|  | } | 
|  |  | 
|  |  | 
|  | def gen_value(template, ob): | 
|  | buf = cStringIO.StringIO() | 
|  | template.generate(buf, ob) | 
|  | return buf.getvalue() | 
|  |  | 
|  |  | 
|  | if __name__ == '__main__': | 
|  | import sys | 
|  | program = parser.parse(open(sys.argv[1]).read()) | 
|  | generate(program) |