import element
+import sys
+
+default_value = {
+ 'bool': 'False',
+ 'int': '-1',
+ 'ref': 'None',
+ 'str': '\'\'',
+ 'list(bool)': '[]',
+ 'list(int)': '[]',
+ 'list(ref)': '[]',
+ 'list(str)': '[]',
+ 'set(bool)': 'set()',
+ 'set(int)': 'set()',
+ 'set(ref)': 'set()',
+ 'set(str)': 'set()'
+}
+default_value_str = {
+ 'bool': 'false',
+ 'int': '-1',
+ 'ref': '-1',
+ 'str': ''
+}
+
+class Context:
+ def __init__(
+ self,
+ fout = sys.stdout,
+ package_name = 't_ast.',
+ indent = '',
+ stack = [],
+ classes = [],
+ base_classes = None,
+ fields = []
+ ):
+ self.fout = fout
+ self.package_name = package_name
+ self.indent = indent
+ self.stack = stack
+ self.classes = classes
+ self.base_classes = [{'element.Element': []}] if base_classes is None else base_classes # params
+ self.fields = fields
class AST(element.Element):
# internal classes:
+ class ClassOrFieldDef(element.Element):
+ # GENERATE ELEMENT() BEGIN
+ def __init__(
+ self,
+ tag = 'AST_ClassOrFieldDef',
+ attrib = {},
+ text = '',
+ children = []
+ ):
+ element.Element.__init__(
+ self,
+ tag,
+ attrib,
+ text,
+ children
+ )
+ def copy(self, factory = None):
+ result = element.Element.copy(
+ self,
+ ClassOrFieldDef if factory is None else factory
+ )
+ return result
+ def __repr__(self):
+ params = []
+ self.repr_serialize(params)
+ return 'ast.AST.ClassOrFieldDef({0:s})'.format(', '.join(params))
+ # GENERATE END
+ def generate_class_or_field_def(self, context):
+ raise NotImplementedError
class Expression(element.Element):
# GENERATE ELEMENT() BEGIN
def __init__(
self.repr_serialize(params)
return 'ast.AST.Identifier({0:s})'.format(', '.join(params))
# GENERATE END
+ def get_text(self):
+ return element.get_text(self, 0)
class LiteralBool(Expression):
# GENERATE ELEMENT(bool value) BEGIN
def __init__(
self.repr_serialize(params)
return 'ast.AST.Section2.ClassDef({0:s})'.format(', '.join(params))
# GENERATE END
+ def generate_class_or_field_def(self, context):
+ class_name = self[0].get_text()
+ if len(self[1]):
+ base_class = '.'.join([i.get_text() for i in self[1][0]])
+ else:
+ base_class = 'element.Element'
+ for i in range(len(context.base_classes) - 1, -1, -1):
+ if base_class in context.base_classes[i]:
+ full_base_class = '.'.join(context.stack[:i] + [base_class])
+ context.base_classes[-1][class_name] = \
+ context.base_classes[i][base_class].copy()
+ break
+ else:
+ assert False
+ context.fout.write(
+ '{0:s}class {1:s}({2:s}):\n'.format(
+ context.indent,
+ class_name,
+ base_class
+ )
+ )
+ indent_save = context.indent
+ context.indent += ' '
+ context.stack.append(class_name)
+ context.classes.append('.'.join(context.stack))
+ context.base_classes.append({})
+ fields_save = context.fields
+ context.fields = []
+ for i in self[2]:
+ i.generate_class_or_field_def(context)
+ i = len(context.base_classes[-2][class_name])
+ context.base_classes[-2][class_name].extend(context.fields)
+
+ context.fout.write(
+ '''{0:s}def __init__(
+{1:s} self,
+{2:s} tag = '{3:s}',
+{4:s} attrib = {{}},
+{5:s} text = '',
+{6:s} children = []{7:s}
+{8:s}):
+{9:s} {10:s}.__init__(
+{11:s} self,
+{12:s} tag,
+{13:s} attrib,
+{14:s} text,
+{15:s} children{16:s}
+{17:s} )
+'''.format(
+ context.indent,
+ context.indent,
+ context.indent,
+ '_'.join(context.stack),
+ context.indent,
+ context.indent,
+ context.indent,
+ ''.join(
+ [
+ ',\n{0:s} {1:s} = {2:s}'.format(
+ context.indent,
+ name,
+ default_value[type]
+ )
+ for type, name in context.base_classes[-2][class_name]
+ ]
+ ),
+ context.indent,
+ context.indent,
+ full_base_class,
+ context.indent,
+ context.indent,
+ context.indent,
+ context.indent,
+ context.indent,
+ ''.join(
+ [
+ ',\n{0:s} {1:s}'.format(
+ context.indent,
+ name
+ )
+ for type, name in context.base_classes[-2][class_name][:i]
+ ]
+ ),
+ context.indent
+ )
+ )
+ for type, name in context.fields:
+ if type == 'ref' or type == 'list(ref)' or type == 'set(ref)' or type == 'str':
+ context.fout.write(
+ '''{0:s} self.{1:s} = {2:s}
+'''.format(context.indent, name, name)
+ )
+ elif type[:5] == 'list(' and type[-1:] == ')':
+ subtype = type[5:-1]
+ context.fout.write(
+ '''{0:s} self.{1:s} = (
+{2:s} [element.deserialize_{3:s}(i) for i in {4:s}.split()]
+{5:s} if isinstance({6:s}, str) else
+{7:s} {8:s}
+{9:s} )
+'''.format(
+ context.indent,
+ name,
+ context.indent,
+ subtype,
+ name,
+ context.indent,
+ name,
+ context.indent,
+ name,
+ context.indent
+ )
+ )
+ elif type[:4] == 'set(' and type[-1:] == ')':
+ subtype = type[4:-1]
+ context.fout.write(
+ '''{0:s} self.{1:s} = (
+{2:s} set([element.deserialize_{3:s}(i) for i in {4:s}.split()])
+{5:s} if isinstance({6:s}, str) else
+{7:s} {8:s}
+{9:s} )
+'''.format(
+ context.indent,
+ name,
+ context.indent,
+ subtype,
+ name,
+ context.indent,
+ name,
+ context.indent,
+ name,
+ context.indent
+ )
+ )
+ else:
+ context.fout.write(
+ '''{0:s} self.{1:s} = (
+{2:s} element.deserialize_{3:s}({4:s})
+{5:s} if isinstance({6:s}, str) else
+{7:s} {8:s}
+{9:s} )
+'''.format(
+ context.indent,
+ name,
+ context.indent,
+ type,
+ name,
+ context.indent,
+ name,
+ context.indent,
+ name,
+ context.indent
+ )
+ )
+ if len(context.fields):
+ context.fout.write(
+ '''{0:s}def serialize(self, ref_list):
+{1:s} {2:s}.serialize(self, ref_list)
+'''.format(context.indent, context.indent, full_base_class)
+ )
+ for type, name in context.fields:
+ if type[:5] == 'list(' and type[-1:] == ')':
+ subtype = type[5:-1]
+ context.fout.write(
+ '''{0:s} self.set(
+{1:s} '{2:s}',
+{3:s} ' '.join([element.serialize_{4:s}(i{5:s}) for i in self.{6:s}])
+{7:s} )
+'''.format(
+ context.indent,
+ context.indent,
+ name,
+ context.indent,
+ subtype,
+ ', ref_list' if subtype == 'ref' else '',
+ name,
+ context.indent
+ )
+ )
+ elif type[:4] == 'set(' and type[-1:] == ')':
+ subtype = type[4:-1]
+ context.fout.write(
+ '''{0:s} self.set(
+{1:s} '{2:s}',
+{3:s} ' '.join([element.serialize_{4:s}(i{5:s}) for i in sorted(self.{6:s})])
+{7:s} )
+'''.format(
+ context.indent,
+ context.indent,
+ name,
+ context.indent,
+ subtype,
+ ', ref_list' if subtype == 'ref' else '',
+ name,
+ context.indent
+ )
+ )
+ else:
+ context.fout.write(
+ '''{0:s} self.set('{1:s}', element.serialize_{2:s}(self.{3:s}{4:s}))
+'''.format(
+ context.indent,
+ name,
+ type,
+ name,
+ ', ref_list' if type == 'ref' else ''
+ )
+ )
+ context.fout.write(
+ '''{0:s}def deserialize(self, ref_list):
+{1:s} {2:s}.deserialize(self, ref_list)
+'''.format(context.indent, context.indent, full_base_class)
+ )
+ for type, name in context.fields:
+ if type[:5] == 'list(' and type[-1:] == ')':
+ subtype = type[5:-1]
+ context.fout.write(
+ '''{0:s} self.{1:s} = [
+{2:s} element.deserialize_{3:s}(i{4:s})
+{5:s} for i in self.get('{6:s}', '').split()
+{7:s} ]
+'''.format(
+ context.indent,
+ name,
+ context.indent,
+ subtype,
+ ', ref_list' if subtype == 'ref' else '',
+ context.indent,
+ name,
+ context.indent
+ )
+ )
+ elif type[:4] == 'set(' and type[-1:] == ')':
+ subtype = type[4:-1]
+ context.fout.write(
+ '''{0:s} self.{1:s} = set(
+{2:s} [
+{3:s} element.deserialize_{4:s}(i{5:s})
+{6:s} for i in self.get('{7:s}', '').split()
+{8:s} ]
+{9:s} )
+'''.format(
+ context.indent,
+ name,
+ context.indent,
+ context.indent,
+ subtype,
+ ', ref_list' if subtype == 'ref' else '',
+ context.indent,
+ name,
+ context.indent,
+ context.indent
+ )
+ )
+ else:
+ context.fout.write(
+ '''{0:s} self.{1:s} = element.deserialize_{2:s}(self.get('{3:s}', '{4:s}'){5:s})
+'''.format(
+ context.indent,
+ name,
+ type,
+ name,
+ default_value_str[type],
+ ', ref_list' if type == 'ref' else ''
+ )
+ )
+ context.fout.write(
+ '''{0:s}def copy(self, factory = None):
+{1:s} result = {2:s}.copy(
+{3:s} self,
+{4:s} {5:s} if factory is None else factory
+{6:s} ){7:s}
+{8:s} return result
+'''.format(
+ context.indent,
+ context.indent,
+ full_base_class,
+ context.indent,
+ context.indent,
+ class_name,
+ context.indent,
+ ''.join(
+ [
+ '\n{0:s} result.{1:s} = self.{2:s}'.format(
+ context.indent,
+ name,
+ name
+ )
+ for _, name in context.fields
+ ]
+ ),
+ context.indent
+ )
+ )
+ if len(context.fields):
+ context.fout.write(
+ '''{0:s}def repr_serialize(self, params):
+{1:s} {2:s}.repr_serialize(self, params)
+'''.format(
+ context.indent,
+ context.indent,
+ full_base_class
+ )
+ )
+ for type, name in context.fields:
+ if type[:5] == 'list(' and type[-1:] == ')':
+ subtype = type[5:-1]
+ context.fout.write(
+ '''{0:s} if len(self.{1:s}):
+{2:s} params.append(
+{3:s} '{4:s} = [{{0:s}}]'.format(
+{5:s} ', '.join([repr(i) for i in self.{6:s}])
+{7:s} )
+{8:s} )
+'''.format(
+ context.indent,
+ name,
+ context.indent,
+ context.indent,
+ name,
+ context.indent,
+ name,
+ context.indent,
+ context.indent
+ )
+ )
+ elif type[:4] == 'set(' and type[-1:] == ')':
+ subtype = type[4:-1]
+ context.fout.write(
+ '''{0:s} if len(self.{1:s}):
+{2:s} params.append(
+{3:s} '{4:s} = set([{{0:s}}])'.format(
+{5:s} ', '.join([repr(i) for i in sorted(self.{6:s})])
+{7:s} )
+{8:s} )
+'''.format(
+ context.indent,
+ name,
+ context.indent,
+ context.indent,
+ name,
+ context.indent,
+ name,
+ context.indent,
+ context.indent
+ )
+ )
+ else:
+ context.fout.write(
+ '''{0:s} if self.{1:s} != {2:s}:
+{3:s} params.append(
+{4:s} '{5:s} = {{0:s}}'.format(repr(self.{6:s}))
+{7:s} )
+'''.format(
+ context.indent,
+ name,
+ default_value[type],
+ context.indent,
+ context.indent,
+ name,
+ name,
+ context.indent
+ )
+ )
+ context.fout.write(
+ '''{0:s}def __repr__(self):
+{1:s} params = []
+{2:s} self.repr_serialize(params)
+{3:s} return '{4:s}{5:s}({{0:s}})'.format(', '.join(params))
+'''.format(
+ context.indent,
+ context.indent,
+ context.indent,
+ context.indent,
+ context.package_name,
+ '.'.join(context.stack),
+ )
+ )
+
+ context.indent = indent_save
+ del context.stack[-1]
+ for temp_base_class, temp_fields in context.base_classes.pop().items():
+ context.base_classes[-1][
+ '{0:s}.{1:s}'.format(class_name, temp_base_class)
+ ] = temp_fields
+ context.fields = fields_save
class FieldDef(element.Element):
# GENERATE ELEMENT() BEGIN
def __init__(
self.repr_serialize(params)
return 'ast.AST.Section2.FieldDef({0:s})'.format(', '.join(params))
# GENERATE END
+ def generate_class_or_field_def(self, context):
+ context.fields.append((element.to_text(self[0]), self[1].get_text()))
# GENERATE ELEMENT() BEGIN
def __init__(
self,
# GENERATE FACTORY(element.Element) BEGIN
tag_to_class = {
'AST': AST,
+ 'AST_ClassOrFieldDef': AST.ClassOrFieldDef,
'AST_Expression': AST.Expression,
'AST_Type': AST.Type,
'AST_BaseClass': AST.BaseClass,
--- /dev/null
+import ast
+import element
+import os
+
+def text_to_python(text, indent):
+ #text_strip = text.strip()
+ #if text_strip[:1] == '{' and text_strip[-1:] == '}':
+ # text = text_strip[1:-1]
+ lines = text.rstrip().split('\n')
+ while len(lines) and len(lines[0].lstrip()) == 0:
+ lines = lines[1:]
+ while len(lines) and len(lines[-1].lstrip()) == 0:
+ lines = lines[:-1]
+ if len(lines) == 0:
+ return '' #{0:s}pass\n'.format(indent)
+ for j in range(len(lines[0])):
+ if lines[0][j] != '\t' and lines[0][j] != ' ':
+ break
+ else:
+ print(text)
+ assert False
+ #print('---')
+ #print(text)
+ prefix = lines[0][:j]
+ for j in range(len(lines)):
+ if len(lines[j]) == 0:
+ lines[j] = '\n'
+ else:
+ assert lines[j][:len(prefix)] == prefix
+ lines[j] = '{0:s}{1:s}\n'.format(indent, lines[j][len(prefix):])
+ return ''.join(lines)
+
+def generate_py(_ast, home_dir, skel_file, out_file):
+ if skel_file is None:
+ skel_file = os.path.join(home_dir, 'skel/skel_py.py')
+ if out_file is None:
+ out_file = 't_ast.py'
+ with open(skel_file, 'r') as fin:
+ with open(out_file, 'w+') as fout:
+ line = fin.readline()
+ while len(line):
+ if line == '# GENERATE SECTION1\n':
+ fout.write(
+ '''# GENERATE SECTION1 BEGIN
+{0:s}# GENERATE END
+'''.format(
+ ''.join(
+ [
+ text_to_python(element.get_text(i[0], 0), '')
+ for i in _ast[0]
+ ]
+ )
+ )
+ )
+ elif line == '# GENERATE SECTION2\n':
+ fout.write('# GENERATE SECTION2 BEGIN\n')
+ #package_name = os.path.basename(out_file)
+ #if package_name[-3:] == '.py':
+ # package_name = package_name[:-3]
+ context = ast.Context(fout, 'ast.') #, package_name + '.')
+ for i in _ast[1]:
+ assert isinstance(i, ast.AST.Section2.ClassDef)
+ i.generate_class_or_field_def(context)
+ fout.write(
+ '''tag_to_class = {{{0:s}
+}}
+# GENERATE END
+'''.format(
+ ','.join(
+ [
+ '\n \'{0:s}\': {1:s}'.format(
+ i.replace('.', '_'),
+ i
+ )
+ for i in context.classes
+ ]
+ )
+ )
+ )
+ elif line == '# GENERATE SECTION3\n':
+ fout.write(
+ '''# GENERATE SECTION3 BEGIN
+{0:s}# GENERATE END
+'''.format(
+ '' if len(_ast) < 3 else element.get_text(_ast[2], 0)
+ )
+ )
+ else:
+ fout.write(line)
+ line = fin.readline()