pvl.dhcp.config: nested blocks
authorTero Marttila <terom@paivola.fi>
Mon, 16 Dec 2013 10:21:37 +0200
changeset 256 63b285ceae41
parent 255 d14eda12d966
child 257 a6964f9bda8b
pvl.dhcp.config: nested blocks
pvl/dhcp/config.py
--- a/pvl/dhcp/config.py	Wed Sep 11 15:17:53 2013 +0300
+++ b/pvl/dhcp/config.py	Mon Dec 16 10:21:37 2013 +0200
@@ -11,16 +11,22 @@
         Doesn't implement the full spec, but a useful approximation.
     """
 
+    @classmethod
+    def load (cls, file) :
+        return cls().parse_file(file)
+
     def __init__ (self) :
+        self.stack = []
         self.block = None
         self.items = []
+        self.blocks = []
     
     @classmethod
     def split (cls, line) :
         """
             Split given line-data.
             
-            >>> split = DHCPLeasesParser.split
+            >>> split = DHCPConfigParser.split
             >>> split('foo bar')
             ['foo', 'bar']
             >>> split('"foo"')
@@ -48,7 +54,7 @@
         """
             Yield tokens from the given lines.
 
-            >>> lex = DHCPLeasesParser.lex
+            >>> lex = DHCPConfigParser.lex
             >>> list(lex('foo;'))
             [('item', ['foo'])]
             >>> list(item for line in ['foo {', ' bar;', '}'] for item in lex(line))
@@ -109,20 +115,18 @@
         """
             Open new block.
         """
-        
-        # XXX: stack
-        assert not self.block
+
+        self.stack.append((self.block, self.items, self.blocks))
 
         self.block = block
         self.items = []
+        self.blocks = []
 
-    def feed_block (self, item) :
+    def feed_item (self, item) :
         """
             Add item to block
         """
 
-        assert self.block
-
         self.items.append(item)
 
     def pop_block (self) :
@@ -133,30 +137,31 @@
 
         assert self.block
 
-        block, items = self.block, self.items
+        block = (self.block, self.items, self.blocks)
 
-        self.block = None
-        self.items = None
+        self.block, self.items, self.blocks = self.stack.pop(-1)
 
-        return block, items
+        self.blocks.append(block)
 
-    def parse (self, line) :
+        return block
+
+    def parse_line (self, line) :
         """
             Parse given line, yielding any complete blocks that come out.
 
             Yields (block, [ lines ]) tuples.
 
-            >>> parser = DHCPLeasesParser()
+            >>> parser = DHCPConfigParser()
             >>> list(parser.parse_lines(['foo {', ' bar;', ' quux asdf;', '}']))
-            [(['foo'], [['bar'], ['quux', 'asdf']])]
+            [(['foo'], [['bar'], ['quux', 'asdf']], [])]
 
-            >>> parser = DHCPLeasesParser()
-            >>> list(parser.parse('foo {'))
+            >>> parser = DHCPConfigParser()
+            >>> list(parser.parse_line('foo {'))
             []
             >>> list(parser.parse_lines([' bar;', ' quux asdf;']))
             []
-            >>> list(parser.parse('}'))
-            [(['foo'], [['bar'], ['quux', 'asdf']])]
+            >>> list(parser.parse_line('}'))
+            [(['foo'], [['bar'], ['quux', 'asdf']], [])]
         """
 
         for token, args in self.lex(line) :
@@ -167,10 +172,10 @@
                 block = args
 
                 if self.block :
-                    log.warn("nested blocks: %s > %s", self.block, block)
-                    continue
-            
-                log.debug("open block: %s", block)
+                    log.debug("nested block: %s > %s", self.block, block)
+                else :
+                    log.debug("open block: %s", block)
+
                 self.push_block(block)
             
             elif token == 'close' :
@@ -183,12 +188,8 @@
             elif token == 'item' :
                 item = args
 
-                if not self.block :
-                    log.warn("token outside block: %s: %s", token, args)
-                    continue
-
                 log.debug("block %s item: %s", self.block, item)
-                self.feed_block(item)
+                self.feed_item(item)
 
             else :
                 # ???
@@ -200,7 +201,21 @@
         """
 
         for line in lines :
-            for item in self.parse(line) :
+            for item in self.parse_line(line) :
                 yield item
 
+    def parse_file (self, file) :
+        """
+            Parse an entire file, returning (items, blocks) lists.
 
+            >>> DHCPConfigParser().parse_file(['foo;', 'barfoo {', 'bar;', '}'])
+            ([['foo']], [(['barfoo'], [['bar']], [])])
+        """
+
+        for line in file :
+            for item in self.parse_line(line) :
+                log.debug("%s", item)
+
+        assert not self.block
+
+        return self.items, self.blocks