1.1 --- a/moinformat/parsers/common.py Wed Dec 13 00:50:09 2017 +0100
1.2 +++ b/moinformat/parsers/common.py Fri Jun 01 15:18:32 2018 +0200
1.3 @@ -19,6 +19,7 @@
1.4 this program. If not, see <http://www.gnu.org/licenses/>.
1.5 """
1.6
1.7 +from collections import defaultdict
1.8 from moinformat.tree import Block, Region, Text
1.9 import re
1.10
1.11 @@ -120,16 +121,6 @@
1.12
1.13
1.14
1.15 -# Utility functions.
1.16 -
1.17 -def new_block(region):
1.18 -
1.19 - "Start a new block in 'region'."
1.20 -
1.21 - region.add(Block([]))
1.22 -
1.23 -
1.24 -
1.25 # Parser abstractions.
1.26
1.27 class ParserBase:
1.28 @@ -146,6 +137,7 @@
1.29 """
1.30
1.31 self.formats = formats
1.32 + self.queued = defaultdict(list)
1.33
1.34 def get_parser(self, format_type):
1.35
1.36 @@ -225,7 +217,7 @@
1.37
1.38 # Define a block to hold text and start parsing.
1.39
1.40 - new_block(region)
1.41 + self.new_block(region)
1.42
1.43 if self.region_pattern_names:
1.44 self.parse_region_details(region, self.region_pattern_names)
1.45 @@ -284,9 +276,12 @@
1.46
1.47 # Parsing utilities.
1.48
1.49 - def parse_region_details(self, region, pattern_names):
1.50 + def parse_region_details(self, region, pattern_names, strict=False):
1.51
1.52 - "Search 'region' using the 'pattern_names'."
1.53 + """
1.54 + Search 'region' using the 'pattern_names'. If 'strict' is set to a true
1.55 + value, forbid the accumulation of additional textual padding.
1.56 + """
1.57
1.58 try:
1.59 while True:
1.60 @@ -295,7 +290,10 @@
1.61
1.62 preceding = self.read_until(pattern_names)
1.63 if preceding:
1.64 - region.append_inline(Text(preceding))
1.65 + if not strict:
1.66 + region.append_inline(Text(preceding))
1.67 + else:
1.68 + break
1.69
1.70 # End of input.
1.71
1.72 @@ -311,18 +309,60 @@
1.73
1.74 if handler:
1.75 handler(self, region)
1.76 + elif not strict:
1.77 + region.append_inline(Text(feature))
1.78 else:
1.79 - region.append_inline(Text(feature))
1.80 + break
1.81
1.82 except StopIteration:
1.83 pass
1.84
1.85 region.normalise()
1.86
1.87 + def add_node(self, region, node):
1.88 +
1.89 + "Add to 'region' the given 'node'."
1.90 +
1.91 + region.add(node)
1.92 + self.unqueue_region(region, node)
1.93 +
1.94 + def append_node(self, region, node):
1.95 +
1.96 + "Append to 'region' the given 'node'."
1.97 +
1.98 + region.append(node)
1.99 + self.unqueue_region(region, node)
1.100 +
1.101 def end_region(self, region):
1.102
1.103 "End the parsing of 'region', breaking out of the parsing loop."
1.104
1.105 raise StopIteration
1.106
1.107 + def queue_region(self, region, current):
1.108 +
1.109 + "Queue 'region' for appending after the 'current' region is ended."
1.110 +
1.111 + self.queued[current].append(region)
1.112 +
1.113 + def unqueue_region(self, region, ended):
1.114 +
1.115 + "Unqueue any queued region, adding it to 'region' after 'ended'."
1.116 +
1.117 + nodes = self.queued.get(ended)
1.118 +
1.119 + while nodes:
1.120 + node = nodes.pop()
1.121 + region.add(node)
1.122 + self.unqueue_region(region, node)
1.123 +
1.124 + if self.queued.has_key(ended):
1.125 + del self.queued[ended]
1.126 +
1.127 + def new_block(self, region):
1.128 +
1.129 + "Start a new block in 'region'."
1.130 +
1.131 + self.add_node(region, Block([]))
1.132 +
1.133 # vim: tabstop=4 expandtab shiftwidth=4