Fix serialization so that nodes (e.g. PYACC.Production) can be parented within the...
authorNick Downing <downing.nick@gmail.com>
Thu, 19 Jul 2018 12:38:35 +0000 (22:38 +1000)
committerNick Downing <downing.nick@gmail.com>
Thu, 19 Jul 2018 12:38:35 +0000 (22:38 +1000)
ast.py
bootstrap_pyacc.py
element.py
generate.py

diff --git a/ast.py b/ast.py
index 569ecd6..70ef01e 100644 (file)
--- a/ast.py
+++ b/ast.py
@@ -64,8 +64,8 @@ class PYACC(element.Element):
       if isinstance(character_set, str) else
         character_set
       )
-    def serialize(self, ref_list, indent = 0):
-      element.Element.serialize(self, ref_list, indent)
+    def serialize(self, ref_list):
+      element.Element.serialize(self, ref_list)
       self.set('name', element.serialize_str(self.name))
       self.set(
         'character_set',
@@ -130,8 +130,8 @@ class PYACC(element.Element):
       if isinstance(precedence, str) else
         precedence
       )
-    def serialize(self, ref_list, indent = 0):
-      PYACC.Symbol.serialize(self, ref_list, indent)
+    def serialize(self, ref_list):
+      PYACC.Symbol.serialize(self, ref_list)
       self.set('precedence', element.serialize_int(self.precedence))
     def deserialize(self, ref_list):
       PYACC.Symbol.deserialize(self, ref_list)
@@ -320,8 +320,8 @@ class PYACC(element.Element):
       if isinstance(character, str) else
         character
       )
-    def serialize(self, ref_list, indent = 0):
-      element.Element.serialize(self, ref_list, indent)
+    def serialize(self, ref_list):
+      element.Element.serialize(self, ref_list)
       self.set('character', element.serialize_int(self.character))
     def deserialize(self, ref_list):
       element.Element.deserialize(self, ref_list)
@@ -587,8 +587,8 @@ class PYACC(element.Element):
         if isinstance(symbol, str) else
           symbol
         )
-      def serialize(self, ref_list, indent = 0):
-        PYACC.Production.Item.serialize(self, ref_list, indent)
+      def serialize(self, ref_list):
+        PYACC.Production.Item.serialize(self, ref_list)
         self.set('symbol', element.serialize_int(self.symbol))
       def deserialize(self, ref_list):
         PYACC.Production.Item.deserialize(self, ref_list)
@@ -652,8 +652,8 @@ class PYACC(element.Element):
         if isinstance(symbol, str) else
           symbol
         )
-      def serialize(self, ref_list, indent = 0):
-        PYACC.Production.Item.serialize(self, ref_list, indent)
+      def serialize(self, ref_list):
+        PYACC.Production.Item.serialize(self, ref_list)
         self.set('symbol', element.serialize_int(self.symbol))
       def deserialize(self, ref_list):
         PYACC.Production.Item.deserialize(self, ref_list)
@@ -752,8 +752,8 @@ class PYACC(element.Element):
       if isinstance(precedence_terminal, str) else
         precedence_terminal
       )
-    def serialize(self, ref_list, indent = 0):
-      element.Element.serialize(self, ref_list, indent)
+    def serialize(self, ref_list):
+      element.Element.serialize(self, ref_list)
       self.set('lhs_nonterminal', element.serialize_int(self.lhs_nonterminal))
       self.set('last_terminal', element.serialize_int(self.last_terminal))
       self.set('precedence_terminal', element.serialize_int(self.precedence_terminal))
@@ -908,8 +908,8 @@ class PYACC(element.Element):
       if isinstance(index, str) else
         index
       )
-    def serialize(self, ref_list, indent = 0):
-      element.Element.serialize(self, ref_list, indent)
+    def serialize(self, ref_list):
+      element.Element.serialize(self, ref_list)
       self.set('index', element.serialize_int(self.index))
     def deserialize(self, ref_list):
       element.Element.deserialize(self, ref_list)
@@ -955,8 +955,8 @@ class PYACC(element.Element):
       if isinstance(index, str) else
         index
       )
-    def serialize(self, ref_list, indent = 0):
-      element.Element.serialize(self, ref_list, indent)
+    def serialize(self, ref_list):
+      element.Element.serialize(self, ref_list)
       self.set('index', element.serialize_int(self.index))
     def deserialize(self, ref_list):
       element.Element.deserialize(self, ref_list)
@@ -1079,8 +1079,8 @@ class PYACC(element.Element):
       if isinstance(type, str) else
         type
       )
-    def serialize(self, ref_list, indent = 0):
-      PYACC.TagOrSymbolRef.serialize(self, ref_list, indent)
+    def serialize(self, ref_list):
+      PYACC.TagOrSymbolRef.serialize(self, ref_list)
       self.set('type', element.serialize_int(self.type))
     def deserialize(self, ref_list):
       PYACC.TagOrSymbolRef.deserialize(self, ref_list)
@@ -1142,8 +1142,8 @@ class PYACC(element.Element):
       if isinstance(user_token, str) else
         user_token
       )
-    def serialize(self, ref_list, indent = 0):
-      PYACC.TagOrSymbolRef.serialize(self, ref_list, indent)
+    def serialize(self, ref_list):
+      PYACC.TagOrSymbolRef.serialize(self, ref_list)
       self.set('terminal', element.serialize_int(self.terminal))
       self.set('user_token', element.serialize_int(self.user_token))
     def deserialize(self, ref_list):
@@ -1245,8 +1245,8 @@ class PYACC(element.Element):
       if isinstance(user_token, str) else
         user_token
       )
-    def serialize(self, ref_list, indent = 0):
-      PYACC.TagOrSymbolRef.serialize(self, ref_list, indent)
+    def serialize(self, ref_list):
+      PYACC.TagOrSymbolRef.serialize(self, ref_list)
       self.set('nonterminal', element.serialize_int(self.nonterminal))
       self.set('user_token', element.serialize_int(self.user_token))
     def deserialize(self, ref_list):
@@ -1466,8 +1466,8 @@ class PYACC(element.Element):
         if isinstance(type, str) else
           type
         )
-      def serialize(self, ref_list, indent = 0):
-        Item.serialize(self, ref_list, indent)
+      def serialize(self, ref_list):
+        Item.serialize(self, ref_list)
         self.set('type', element.serialize_int(self.type))
       def deserialize(self, ref_list):
         Item.deserialize(self, ref_list)
@@ -2543,8 +2543,8 @@ class PYACC(element.Element):
     if isinstance(associativities, str) else
       associativities
     )
-  def serialize(self, ref_list, indent = 0):
-    element.Element.serialize(self, ref_list, indent)
+  def serialize(self, ref_list):
+    element.Element.serialize(self, ref_list)
     self.set(
       'prologue_text',
       ' '.join([element.serialize_ref(i, ref_list) for i in self.prologue_text])
index ca2d57e..2db2f45 100755 (executable)
@@ -35,7 +35,9 @@ in_file = args[0]
 
 with open(in_file) as fin:
   pyacc = element.deserialize(fin, ast.factory)
-#element.serialize(pyacc, sys.stdout)
+element.serialize(pyacc, 'a.xml', 'utf-8')
+pyacc = element.deserialize('a.xml', ast.factory, 'utf-8')
 pyacc.post_process()
-#element.serialize(pyacc, sys.stdout)
+element.serialize(pyacc, 'b.xml', 'utf-8')
+pyacc = element.deserialize('b.xml', ast.factory, 'utf-8')
 bison_lr1dfa.generate(pyacc, skel_file, out_file)
index aa0b630..1f8e84f 100644 (file)
@@ -1,18 +1,20 @@
-import sys
 import xml.etree.ElementTree
 
 class Element(xml.etree.ElementTree._Element_Py):
   def __init__(self, tag = 'Element', attrib = {}, text = '', children = []):
     xml.etree.ElementTree._Element_Py.__init__(self, tag, attrib)
     self.ref = -1
+    self.seen = False
     set_text(self, 0, text)
     self[:] = children
-  def serialize(self, ref_list, indent = 0):
-    if len(self):
-      for i in range(len(self)):
-        set_text(self, i, '\n' + ' ' * (indent + 2))
-        self[i].serialize(ref_list, indent + 2)
-      set_text(self, len(self), '\n' + ' ' * indent)
+  def serialize(self, ref_list):
+    for i in self:
+      # parented, enforce that child can only be parented at most once
+      # (although there can be unlimited numbers of numeric refs to it)
+      assert not i.seen
+      i.seen = True
+      if i.ref == -1:
+        i.serialize(ref_list)
   def deserialize(self, ref_list):
     for i in self:
       i.deserialize(ref_list)
@@ -53,13 +55,15 @@ def serialize_ref(value, ref_list):
     ref = -1
   else:
     ref = value.ref
-    if ref < 0:
-      value.serialize(ref_list, 2)
+    if ref == -1:
       ref = len(ref_list)
-      set_text(ref_list, ref, '\n  ')
       ref_list.append(value)
       value.ref = ref
-      value.set('ref', serialize_int(ref))
+      value.set('ref', str(ref))
+      # this doesn't set the seen flag, so it will be parented by the
+      # 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):
@@ -72,34 +76,55 @@ def serialize_str(value):
 def deserialize_str(text):
   return text
 
-def serialize(root, fout, encoding = 'unicode'):
-  ref_list = Element('RefList')
-  root.serialize(ref_list, 2)
-  ref = len(ref_list)
-  set_text(ref_list, ref, '\n  ')
-  ref_list.append(root)
-  root.ref = ref
-  root.set('ref', serialize_int(ref))
-  set_text(ref_list, ref + 1, '\n')
-  ref_list.tail = '\n'
-  xml.etree.ElementTree.ElementTree(ref_list).write(fout, encoding)
+def serialize(value, fout, encoding = 'unicode'):
+  ref_list = []
+  serialize_ref(value, ref_list)
+  parents = [i for i in ref_list if not i.seen]
+  root = Element('root', children = parents)
+  for i in range(len(root)):
+    set_text(root, i, '\n  ')
+  set_text(root, len(root), '\n')
+  root.tail = '\n'
+  xml.etree.ElementTree.ElementTree(root).write(fout, encoding)
+  for i in root:
+    i.tail = None
   for i in ref_list:
     i.ref = -1
     del i.attrib['ref']
+  i = 0
+  while i < len(parents):
+    for j in parents[i]:
+      j.seen = False
+      parents.append(j)
+    i += 1
 
 def deserialize(fin, factory = Element, encoding = 'unicode'):
-  ref_list = xml.etree.ElementTree.parse(
+  root = xml.etree.ElementTree.parse(
     fin,
     xml.etree.ElementTree.XMLParser(
       target = xml.etree.ElementTree.TreeBuilder(factory),
       encoding = encoding
     )
   ).getroot()
-  for i in ref_list:
+  assert root.tag == 'root'
+  for i in root:
+    i.tail = None
+  i = 0
+  parents = root[:]
+  ref_list = []
+  while i < len(parents):
+    j = parents[i]
+    if 'ref' in j.attrib:
+      ref = int(j.attrib['ref'])
+      del j.attrib['ref']
+      if len(ref_list) < ref + 1:
+        ref_list.extend([None] * (ref + 1 - len(ref_list)))
+      ref_list[ref] = j
+    parents.extend(j[:])
+    i += 1
+  for i in root:
     i.deserialize(ref_list)
-    i.ref = -1
-    del i.attrib['ref']
-  return ref_list[-1]
+  return ref_list[0]
 
 # compatibility scheme to access arbitrary xml.etree.ElementTree.Element-like
 # objects (not just Element defined above) using a more consistent interface:
index 169c348..f9a633b 100755 (executable)
@@ -219,8 +219,8 @@ while len(line):
           )
       if len(fields):
         sys.stdout.write(
-          '''{0:s}def serialize(self, ref_list, indent = 0):
-{1:s}  {2:s}.serialize(self, ref_list, indent)
+          '''{0:s}def serialize(self, ref_list):
+{1:s}  {2:s}.serialize(self, ref_list)
 '''.format(indent, indent, full_base_class)
         )
         for type, name in fields: