Use JSON encoding for attributes, to allow nested types such as list(list(int))
authorNick Downing <nick@ndcode.org>
Mon, 28 Jan 2019 07:56:21 +0000 (18:56 +1100)
committerNick Downing <nick@ndcode.org>
Mon, 28 Jan 2019 10:32:29 +0000 (21:32 +1100)
pitree.t
skel/element.py
skel/skel_py.py

index ce7fbbb..9009ccd 100644 (file)
--- a/pitree.t
+++ b/pitree.t
@@ -18,6 +18,7 @@
 
 %{
   import element
+  import json
   import sys
 %}
 
@@ -212,23 +213,27 @@ def generate_class_or_field_def(self, context):
       )
     )
     indent_save2 = context.indent
-    context.indent += '    '
+    context.indent += '      '
     for i in context.fields[n_base_fields:]:
       context.field_name = i[1].get_text()
       context.fout.write(
         '''{0:s}  self.set(
 {1:s}    '{2:s}',
-{3:s}    {4:s}
-{5:s}  )
+{3:s}    json.dumps(
+{4:s}      {5:s}
+{6:s}    )
+{7:s}  )
 '''.format(
           indent_save2,
           indent_save2,
           context.field_name,
           indent_save2,
+          indent_save2,
           i[0].generate_serialize(
             context,
             'self.{0:s}'.format(context.field_name)
           ),
+          indent_save2,
           indent_save2
         )
       )
@@ -253,14 +258,13 @@ def generate_class_or_field_def(self, context):
           context.field_name,
           i[0].generate_deserialize(
             context,
-            'self.get(\'{0:s}\'{1:s})'.format(
+            'json.loads(self.get(\'{0:s}\'{1:s}))'.format(
               context.field_name,
               (
                 ', \'{0:s}\''.format(
-                  i[2][0].
-                  generate_expression_serialized(context).
-                  replace('\\', '\\\\').
-                  replace('\'', '\\\'')
+                  json.dumps(
+                    i[2][0].generate_expression_json(i[0])
+                  ).replace('\\', '\\\\').replace('\'', '\\\'')
                 )
               if len(i[2]) else
                 ''
@@ -375,91 +379,137 @@ def generate_expression(self, _type):
 del generate_expression
 
 @method(AST.Expression)
-def generate_expression_serialized(self, context):
+def generate_expression_json(self, _type):
   raiseNotImplementedError
 @method(AST.LiteralBool)
-def generate_expression_serialized(self, context):
-  return "true" if self.value else "false"
+def generate_expression_json(self, _type):
+  assert isinstance(_type, AST.TypeBool)
+  return self.value
 @method(AST.LiteralDict)
-def generate_expression_serialized(self, context):
-  return ' '.join(
+def generate_expression_json(self, _type):
+  assert isinstance(_type, AST.TypeDict)
+  return (
+    {
+      i[0].generate_expression_json(_type[0]):
+      i[1].generate_expression_json(_type[1])
+      for i in self
+    }
+  if isinstance(_type[0], AST.TypeStr) else
     [
-      i.generate_expression_serialized(context)
+      [
+        i[0].generate_expression_json(_type[0]),
+        i[1].generate_expression_json(_type[1])
+      ]
       for i in self
     ]
   )
 @method(AST.LiteralInt)
-def generate_expression_serialized(self, context):
-  return str(self.get_value())
+def generate_expression_json(self, _type):
+  assert isinstance(_type, AST.TypeInt)
+  return self.get_value()
 @method(AST.LiteralList)
-def generate_expression_serialized(self, context):
-  return ' '.join(
-    [
-      i.generate_expression_serialized(context)
-      for i in self
-    ]
-  )
+def generate_expression_json(self, _type):
+  assert isinstance(_type, AST.TypeList)
+  return [
+    i.generate_expression_json(_type[0])
+    for i in self
+  ]
 @method(AST.LiteralRef)
-def generate_expression_serialized(self, context):
-  return '-1'
+def generate_expression_json(self, _type):
+  assert isinstance(_type, AST.TypeRef)
+  return -1
 @method(AST.LiteralSet)
-def generate_expression_serialized(self, context):
-  return ' '.join(
-    [
-      i.generate_expression_serialized(context)
-      for i in self
-    ]
-  )
+def generate_expression_json(self, _type):
+  assert isinstance(_type, AST.TypeSet)
+  return [
+    i.generate_expression_json(_type[0])
+    for i in self
+  ]
 @method(AST.LiteralStr)
-def generate_expression_serialized(self, context):
+def generate_expression_json(self, _type):
+  assert isinstance(_type, AST.TypeStr)
   return self[0].get_text()
-del generate_expression_serialized
+del generate_expression_json
 
 @method(AST.Type)
 def generate_serialize(self, context, expr):
-  return 'element.serialize_{0:s}({1:s})'.format(
-    element.to_text(self),
-    expr
-  )
-@method(AST.TypeList)
+  assert self.is_json
+  return expr
+@method(AST.TypeDict)
 def generate_serialize(self, context, expr):
-  indent_save = context.indent
-  context.indent += '    '
-  result = '''' '.join(
+  if self.is_json:
+    result = expr
+  elif isinstance(self[0], AST.TypeStr):
+    context.indent += '  '
+    result = '''{{
+{0:s}  {1:s}:
+{2:s}  {3:s}
+{4:s}  for i in {5:s}
+{6:s}}}'''.format(
+      indent_save,
+      self[0].generate_serialize(context, 'i[0]'),
+      indent_save,
+      self[0].generate_serialize(context, 'i[1]'),
+      indent_save,
+      expr,
+      indent_save
+    )
+  else:
+    context.indent += '    '
+    result = '''[
 {0:s}  [
-{1:s}    {2:s}
-{3:s}    for i in {4:s}
+{1:s}    {2:s},
+{3:s}    {4:s}
 {5:s}  ]
-{6:s})'''.format(
-    indent_save,
+{6:s}  for k, v in {7:s}.items()
+{8:s}}}'''.format(
+      indent_save,
+      indent_save,
+      self[0].generate_serialize(context, 'k'),
+      indent_save,
+      self[0].generate_serialize(context, 'v'),
+      indent_save,
+      indent_save,
+      expr,
+      indent_save
+    )
+  context.indent = indent_save
+  return result
+@method(AST.TypeList)
+def generate_serialize(self, context, expr):
+  if self.is_json:
+    return expr
+  indent_save = context.indent
+  context.indent += '  '
+  result = '''[
+{0:s}  {1:s}
+{2:s}  for i in {3:s}
+{4:s}]'''.format(
     indent_save,
     self[0].generate_serialize(context, 'i'),
     indent_save,
     expr,
-    indent_save,
     indent_save
   )
   context.indent = indent_save
   return result
 @method(AST.TypeRef)
 def generate_serialize(self, context, expr):
+  assert not self.is_json
   return 'element.serialize_ref({0:s}, ref_list)'.format(expr)
 @method(AST.TypeSet)
 def generate_serialize(self, context, expr):
+  assert not self.is_json
   indent_save = context.indent
-  context.indent += '    '
-  result = '''' '.join(
-{0:s}  [
-{1:s}    {2:s}
-{3:s}    for i in sorted({4:s})
-{5:s}  ]
-{6:s})'''.format(
-    indent_save,
+  context.indent += '  '
+  result = '''[
+{0:s}  {1:s}
+{2:s}  for i in {3:s}
+{4:s}]'''.format(
     indent_save,
     self[0].generate_serialize(context, 'i'),
     indent_save,
     expr,
-    indent_save,
     indent_save
   )
   context.indent = indent_save
@@ -467,47 +517,91 @@ def generate_serialize(self, context, expr):
 del generate_serialize
 
 @method(AST.Type)
-def generate_deserialize(self, context, expr): 
-  return 'element.deserialize_{0:s}({1:s})'.format(
-    element.to_text(self),
+def generate_deserialize(self, context, expr):
+  assert self.is_json
+  return expr
+@method(AST.TypeDict)
+def generate_deserialize(self, context, expr):
+  indent_save = context.indent
+  context.indent += '  '
+  result = (
     expr
+  if self.is_json else
+    '''{{
+{0:s}  {1:s}:
+{2:s}  {3:s}
+{4:s}  for k, v in {5:s}.items()
+{6:s}}}'''.format(
+      indent_save,
+      self[0].generate_deserialize(context, 'k'),
+      indent_save,
+      self[1].generate_deserialize(context, 'v'),
+      indent_save,
+      expr,
+      indent_save
+    )
+  if isinstance(self[0], AST.TypeStr) else
+    '''{{
+{0:s}  {1:s}:
+{2:s}  {3:s}
+{4:s}  for [k, v] in {5:s}
+{6:s}}}'''.format(
+      indent_save,
+      self[0].generate_deserialize(context, 'k'),
+      indent_save,
+      self[1].generate_deserialize(context, 'v'),
+      indent_save,
+      expr,
+      indent_save
+    )
   )
+  context.indent = indent_save
+  return result
 @method(AST.TypeList)
 def generate_deserialize(self, context, expr):
   indent_save = context.indent
   context.indent += '  '
-  result = '''[
+  result = (
+    expr
+  if self.is_json else
+    '''[
 {0:s}  {1:s}
-{2:s}  for i in {3:s}.split()
+{2:s}  for i in {3:s}
 {4:s}]'''.format(
-    indent_save,
-    self[0].generate_deserialize(context, 'i'),
-    indent_save,
-    expr,
-    indent_save
+      indent_save,
+      self[0].generate_deserialize(context, 'i'),
+      indent_save,
+      expr,
+      indent_save
+    )
   )
   context.indent = indent_save
   return result
 @method(AST.TypeRef)
-def generate_deserialize(self, context, expr): 
+def generate_deserialize(self, context, expr):
+  assert not self.is_json
   return 'element.deserialize_ref({0:s}, ref_list)'.format(expr)
 @method(AST.TypeSet)
 def generate_deserialize(self, context, expr):
   indent_save = context.indent
   context.indent += '    '
-  result = '''set(
+  result = (
+    'set({0:s})'.format(expr)
+  if self[0].is_json else
+    '''set(
 {0:s}  [
 {1:s}    {2:s}
-{3:s}    for i in {4:s}.split()
+{3:s}    for i in {4:s}
 {5:s}  ]
 {6:s})'''.format(
-    indent_save,
-    indent_save,
-    self[0].generate_deserialize(context, 'i'),
-    indent_save,
-    expr,
-    indent_save,
-    indent_save
+      indent_save,
+      indent_save,
+      self[0].generate_deserialize(context, 'i'),
+      indent_save,
+      expr,
+      indent_save,
+      indent_save
+    )
   )
   context.indent = indent_save
   return result
index e8732cc..d622c41 100644 (file)
@@ -41,22 +41,6 @@ class Element(xml.etree.ElementTree._Element_Py):
     result[:] = [i.copy() for i in self]
     return result
 
-bool_to_str = ['false', 'true']
-def serialize_bool(value):
-  return bool_to_str[int(value)]
-
-str_to_bool = {'false': False, 'true': True}
-def deserialize_bool(text):
-  assert text is not None
-  return str_to_bool[text]
-
-def serialize_int(value):
-  return str(value)
-
-def deserialize_int(text):
-  assert text is not None
-  return int(text)
-
 def serialize_ref(value, ref_list):
   if value is None:
     ref = -1
@@ -71,19 +55,11 @@ def serialize_ref(value, ref_list):
       # root, unless it is already parented or gets parented later on
       if not value.seen:
         value.serialize(ref_list)
-  return str(ref)
-
-def deserialize_ref(text, ref_list):
-  assert text is not None
-  ref = int(text)
-  return None if ref < 0 else ref_list[ref]
-
-def serialize_str(value):
-  return value
+  return ref
 
-def deserialize_str(text):
-  assert text is not None
-  return text
+def deserialize_ref(value, ref_list):
+  assert value is not None
+  return None if value < 0 else ref_list[value]
 
 def serialize(value, fout, encoding = 'unicode'):
   ref_list = []
index d365544..919f858 100644 (file)
@@ -24,6 +24,9 @@
 # files to be licensed under the GNU General Public License without this
 # special exception.
 
+import element
+import json
+
 # GENERATE SECTION1
 
 # GENERATE SECTION2