Implement compound rules
authorNick Downing <downing.nick@gmail.com>
Sun, 22 Jul 2018 04:18:34 +0000 (14:18 +1000)
committerNick Downing <downing.nick@gmail.com>
Sun, 22 Jul 2018 04:18:34 +0000 (14:18 +1000)
ast.py

diff --git a/ast.py b/ast.py
index 9f7d918..6a260d2 100644 (file)
--- a/ast.py
+++ b/ast.py
@@ -35,7 +35,8 @@ class Item(element.Element):
     section,
     name_to_start_condition,
     all_start_conditions,
-    inclusive_start_conditions
+    inclusive_start_conditions,
+    parent_start_conditions
   ):
     raise NotImplementedException
 
@@ -237,7 +238,8 @@ class PLex(element.Element):
         section,
         name_to_start_condition,
         all_start_conditions,
-        inclusive_start_conditions
+        inclusive_start_conditions,
+        parent_start_conditions
       ):
         section.code_blocks_text.append(self[0])
 
@@ -295,7 +297,8 @@ class PLex(element.Element):
       plex,
       name_to_start_condition,
       all_start_conditions,
-      inclusive_start_conditions
+      inclusive_start_conditions,
+      parent_start_conditions
     ):
       for i in self:
         i.post_process(
@@ -303,7 +306,8 @@ class PLex(element.Element):
           self,
           name_to_start_condition,
           all_start_conditions,
-          inclusive_start_conditions
+          inclusive_start_conditions,
+          parent_start_conditions
         )
 
   class Section1(Section1Or2):
@@ -577,7 +581,8 @@ class PLex(element.Element):
         section,
         name_to_start_condition,
         all_start_conditions,
-        inclusive_start_conditions
+        inclusive_start_conditions,
+        parent_start_conditions
       ):
         for i in self:
           i.post_process(section)
@@ -634,7 +639,8 @@ class PLex(element.Element):
         section,
         name_to_start_condition,
         all_start_conditions,
-        inclusive_start_conditions
+        inclusive_start_conditions,
+        parent_start_conditions
       ):
         for i in self:
           name = i.get_text()
@@ -757,7 +763,8 @@ class PLex(element.Element):
       plex,
       name_to_start_condition,
       all_start_conditions,
-      inclusive_start_conditions
+      inclusive_start_conditions,
+      parent_start_conditions
     ):
       self.ecs = False
       self.meta_ecs = False
@@ -769,19 +776,19 @@ class PLex(element.Element):
         plex,
         name_to_start_condition,
         all_start_conditions,
-        inclusive_start_conditions
+        inclusive_start_conditions,
+        parent_start_conditions
       )
 
   class Section2(Section1Or2):
-    class StartConditions(element.Element):
-      # GENERATE ELEMENT(bool wildcard) BEGIN
+    class CompoundRule(element.Element):
+      # GENERATE ELEMENT() BEGIN
       def __init__(
         self,
-        tag = 'PLex_Section2_StartConditions',
+        tag = 'PLex_Section2_CompoundRule',
         attrib = {},
         text = '',
-        children = [],
-        wildcard = False
+        children = []
       ):
         element.Element.__init__(
           self,
@@ -790,35 +797,43 @@ class PLex(element.Element):
           text,
           children
         )
-        self.wildcard = (
-          element.deserialize_bool(wildcard)
-        if isinstance(wildcard, str) else
-          wildcard
-        )
-      def serialize(self, ref_list):
-        element.Element.serialize(self, ref_list)
-        self.set('wildcard', element.serialize_bool(self.wildcard))
-      def deserialize(self, ref_list):
-        element.Element.deserialize(self, ref_list)
-        self.wildcard = element.deserialize_bool(self.get('wildcard', 'false'))
       def copy(self, factory = None):
         result = element.Element.copy(
           self,
-          StartConditions if factory is None else factory
+          CompoundRule if factory is None else factory
         )
-        result.wildcard = self.wildcard
         return result
-      def repr_serialize(self, params):
-        element.Element.repr_serialize(self, params)
-        if self.wildcard != False:
-          params.append(
-            'wildcard = {0:s}'.format(repr(self.wildcard))
-          )
       def __repr__(self):
         params = []
         self.repr_serialize(params)
-        return 'ast.PLex.Section2.StartConditions({0:s})'.format(', '.join(params))
+        return 'ast.PLex.Section2.CompoundRule({0:s})'.format(', '.join(params))
       # GENERATE END
+      def post_process(
+        self,
+        plex,
+        section,
+        name_to_start_condition,
+        all_start_conditions,
+        inclusive_start_conditions,
+        parent_start_conditions
+      ):
+        if self[0].wildcard:
+          start_conditions = all_start_conditions
+        else:
+          start_conditions = set(parent_start_conditions)
+          for i in self[0]:
+            start_conditions.add(
+              name_to_start_condition[i.get_text()]
+            )
+        for i in self[1:]:
+          i.post_process(
+            plex,
+            section,
+            name_to_start_condition,
+            all_start_conditions,
+            inclusive_start_conditions,
+            start_conditions # parent_start_conditions
+          )
 
     class Rule(Item):
       class BOLRule(element.Element):
@@ -956,41 +971,90 @@ class PLex(element.Element):
         section,
         name_to_start_condition,
         all_start_conditions,
-        inclusive_start_conditions
+        inclusive_start_conditions,
+        parent_start_conditions
       ):
-        default = False
         if self[0].wildcard:
-          start_condition_set = all_start_conditions
-        elif len(self[0]) == 0:
-          default = True
-          start_condition_set = inclusive_start_conditions
+          start_conditions = all_start_conditions
         else:
-          start_condition_set = set()
+          start_conditions = set(parent_start_conditions)
           for i in self[0]:
-            start_condition_set.add(
+            start_conditions.add(
               name_to_start_condition[i.get_text()]
             )
         if isinstance(self[1], PLex.Section2.Rule.EOFRule):
           assert isinstance(self[2], regex.RegexNone)
-          for i in start_condition_set:
-            if default and plex.start_conditions[i].eof_action != 0:
-              continue # rule applies to start conditions with no EOF rule yet
-            assert plex.start_conditions[i].eof_action == 0
-            plex.start_conditions[i].eof_action = len(plex.eof_actions_text)
+          if len(start_conditions) == 0:
+            for i in inclusive_start_conditions: # should be all?
+              if plex.start_conditions[i].eof_action == 0:
+                plex.start_conditions[i].eof_action = len(plex.eof_actions_text)
+          else:
+            for i in start_conditions:
+              assert plex.start_conditions[i].eof_action == 0
+              plex.start_conditions[i].eof_action = len(plex.eof_actions_text)
           plex.eof_actions_text.append(self[3][0])
         else:
+          if len(start_conditions) == 0:
+            start_conditions = inclusive_start_conditions
           if isinstance(self[1], PLex.Section2.Rule.BOLRule):
-            for i in start_condition_set:
+            for i in start_conditions:
               plex.start_conditions[i].bol_rules.append(self)
             self[1][0].post_process()
           else:
-            for i in start_condition_set:
+            for i in start_conditions:
               plex.start_conditions[i].rules.append(self)
               plex.start_conditions[i].bol_rules.append(self)
             self[1].post_process()
           self[2].post_process()
           self.action = len(plex.actions_text)
           plex.actions_text.append(self[3][0])
+    class StartConditions(element.Element):
+      # GENERATE ELEMENT(bool wildcard) BEGIN
+      def __init__(
+        self,
+        tag = 'PLex_Section2_StartConditions',
+        attrib = {},
+        text = '',
+        children = [],
+        wildcard = False
+      ):
+        element.Element.__init__(
+          self,
+          tag,
+          attrib,
+          text,
+          children
+        )
+        self.wildcard = (
+          element.deserialize_bool(wildcard)
+        if isinstance(wildcard, str) else
+          wildcard
+        )
+      def serialize(self, ref_list):
+        element.Element.serialize(self, ref_list)
+        self.set('wildcard', element.serialize_bool(self.wildcard))
+      def deserialize(self, ref_list):
+        element.Element.deserialize(self, ref_list)
+        self.wildcard = element.deserialize_bool(self.get('wildcard', 'false'))
+      def copy(self, factory = None):
+        result = element.Element.copy(
+          self,
+          StartConditions if factory is None else factory
+        )
+        result.wildcard = self.wildcard
+        return result
+      def repr_serialize(self, params):
+        element.Element.repr_serialize(self, params)
+        if self.wildcard != False:
+          params.append(
+            'wildcard = {0:s}'.format(repr(self.wildcard))
+          )
+      def __repr__(self):
+        params = []
+        self.repr_serialize(params)
+        return 'ast.PLex.Section2.StartConditions({0:s})'.format(', '.join(params))
+      # GENERATE END
 
     # GENERATE ELEMENT() BEGIN
     def __init__(
@@ -1166,19 +1230,22 @@ class PLex(element.Element):
     name_to_start_condition = {'INITIAL': 0}
     all_start_conditions = set([0])
     inclusive_start_conditions = set([0])
+    start_conditions = set()
 
     # perform the semantic analysis pass
     self[0].post_process(
       self,
       name_to_start_condition,
       all_start_conditions,
-      inclusive_start_conditions
+      inclusive_start_conditions,
+      start_conditions # parent_start_conditions
     )
     self[1].post_process(
       self,
       name_to_start_condition,
       all_start_conditions,
-      inclusive_start_conditions
+      inclusive_start_conditions,
+      start_conditions # parent_start_conditions
     )
     self.default_action = len(self.actions_text)
     self.actions_text.append(PLex.Text(text = 'ECHO;\n'))
@@ -1262,11 +1329,12 @@ tag_to_class = {
   'PLex_Section1_Options_YYWrap': PLex.Section1.Options.YYWrap,
   'PLex_Section1_StartConditions': PLex.Section1.StartConditions,
   'PLex_Section2': PLex.Section2,
-  'PLex_Section2_StartConditions': PLex.Section2.StartConditions,
+  'PLex_Section2_CompoundRule': PLex.Section2.CompoundRule,
   'PLex_Section2_Rule': PLex.Section2.Rule,
   'PLex_Section2_Rule_BOLRule': PLex.Section2.Rule.BOLRule,
   'PLex_Section2_Rule_EOFRule': PLex.Section2.Rule.EOFRule,
   'PLex_Section2_Rule_Action': PLex.Section2.Rule.Action,
+  'PLex_Section2_StartConditions': PLex.Section2.StartConditions,
   'PLex_Section3': PLex.Section3
 }
 def factory(tag, attrib = {}, *args, **kwargs):