bug 1310980, part 3: fix IniParser draft
authorAxel Hecht <axel@pike.org>
Fri, 21 Oct 2016 17:57:37 +0200
changeset 144 cdfb15a3c6829bb28ce17893e255b94ad201e072
parent 143 60bb42f6bf9eb7f802ed37ffdae162b5903c63f8
child 145 1429ed19667ba4bb7447db0ec28b46468567c087
push id30
push useraxel@mozilla.com
push dateMon, 24 Oct 2016 14:52:08 +0000
bugs1310980
bug 1310980, part 3: fix IniParser MozReview-Commit-ID: ANS7yjBlyfT
compare_locales/parser.py
compare_locales/tests/test_ini.py
--- a/compare_locales/parser.py
+++ b/compare_locales/parser.py
@@ -453,29 +453,78 @@ class DefinesParser(Parser):
         self.reKey = re.compile('^(\s*)'
                                 '(#define[ \t]+(\w+)[ \t]+(.*?))([ \t]*$\n?)',
                                 re.M)
         self.reHeader = re.compile('^\s*(#(?!define\s).*\s*)*')
         self.reFooter = re.compile('\s*(#(?!define\s).*\s*)*$', re.M)
         Parser.__init__(self)
 
 
+class IniSection(Entity):
+    '''Entity-like object representing sections in ini files
+    '''
+    def __init__(self, ctx, span, pre_ws_span, def_span, val_span, post_span):
+        self.ctx = ctx
+        self.span = span
+        self.pre_ws_span = pre_ws_span
+        self.def_span = def_span
+        self.key_span = self.val_span = val_span
+        self.post_span = post_span
+        self.pp = lambda v: v
+
+    def __repr__(self):
+        return self.raw_val
+
+
 class IniParser(Parser):
     '''
     Parse files of the form:
     # initial comment
     [cat]
     whitespace*
     #comment
     string=value
     ...
     '''
     def __init__(self):
-        self.reHeader = re.compile('^((?:\s*|[;#].*)\n)*\[.+?\]\n', re.M)
-        self.reKey = re.compile('(\s*)((?:[;#].*\n\s*)*)((.+?)=(.*))(\n?)')
+        self.reComment = re.compile(
+            '((?:[ \t]*\n)*)'
+            '((?:^[;#].*?(?:\n|\Z))+)'
+            '((?:[ \t]*(?:\n|\Z))*)', re.M)
+        self.reSection = re.compile(
+            '((?:[ \t]*\n)*)'
+            '(\[(.*?)\])'
+            '((?:[ \t]*(?:\n|\Z))*)', re.M)
+        self.reKey = re.compile(
+            '((?:[ \t]*\n)*)'
+            '((.+?)=(.*))'
+            '((?:[ \t]*(?:\n|\Z))*)', re.M)
         self.reFooter = re.compile('\s*([;#].*\s*)*$')
         Parser.__init__(self)
 
+    def getEntity(self, ctx, offset):
+        contents = ctx.contents
+        m = self.reComment.match(contents, offset)
+        if m:
+            offset = m.end()
+            return (Comment(ctx, *[m.span(i) for i in xrange(4)]), offset)
+        m = self.reSection.match(contents, offset)
+        if m:
+            offset = m.end()
+            return (IniSection(ctx, *[m.span(i) for i in xrange(5)]), offset)
+        m = self.reKey.match(contents, offset)
+        if m:
+            offset = m.end()
+            return (self.createEntity(ctx, m), offset)
+        junkend = None
+        for exp in (self.reComment, self.reSection, self.reKey):
+            m = exp.search(contents, offset)
+            if m:
+                junkend = min(junkend, m.start(1)) if junkend else m.start()
+        if junkend is not None:
+            return (Junk(ctx, (offset, junkend)), junkend)
+        return (None, offset)
+
 
 __constructors = [('\\.dtd$', DTDParser()),
                   ('\\.properties$', PropertiesParser()),
                   ('\\.ini$', IniParser()),
                   ('\\.inc$', DefinesParser())]
--- a/compare_locales/tests/test_ini.py
+++ b/compare_locales/tests/test_ini.py
@@ -18,98 +18,116 @@ mpl2 = '''\
 class TestIniParser(ParserTestMixin, unittest.TestCase):
 
     filename = 'foo.ini'
 
     def testSimpleHeader(self):
         self._test('''; This file is in the UTF-8 encoding
 [Strings]
 TitleText=Some Title
-''', (('TitleText', 'Some Title'),))
-        self.assert_('UTF-8' in self.parser.header)
+''', (
+            ('Comment', 'UTF-8 encoding'),
+            ('IniSection', 'Strings'),
+            ('TitleText', 'Some Title'),))
 
     def testMPL2_Space_UTF(self):
         self._test(mpl2 + '''
 ; This file is in the UTF-8 encoding
 [Strings]
 TitleText=Some Title
-''', (('TitleText', 'Some Title'),))
-        self.assert_('MPL' in self.parser.header)
+''', (
+            ('Comment', mpl2),
+            ('Comment', 'UTF-8'),
+            ('IniSection', 'Strings'),
+            ('TitleText', 'Some Title'),))
 
     def testMPL2_Space(self):
         self._test(mpl2 + '''
 [Strings]
 TitleText=Some Title
-''', (('TitleText', 'Some Title'),))
-        self.assert_('MPL' in self.parser.header)
+''', (
+            ('Comment', mpl2),
+            ('IniSection', 'Strings'),
+            ('TitleText', 'Some Title'),))
 
     def testMPL2_MultiSpace(self):
         self._test(mpl2 + '''\
 
 ; more comments
 
 [Strings]
 TitleText=Some Title
-''', (('TitleText', 'Some Title'),))
-        self.assert_('MPL' in self.parser.header)
+''', (
+            ('Comment', mpl2),
+            ('Comment', 'more comments'),
+            ('IniSection', 'Strings'),
+            ('TitleText', 'Some Title'),))
 
     def testMPL2_JunkBeforeCategory(self):
         self._test(mpl2 + '''\
 Junk
 [Strings]
 TitleText=Some Title
-''', (('Junk', mpl2 + '''\
-Junk
-[Strings]'''), ('TitleText', 'Some Title')))
-        self.assert_('MPL' not in self.parser.header)
+''', (
+            ('Comment', mpl2),
+            ('Junk', 'Junk'),
+            ('IniSection', 'Strings'),
+            ('TitleText', 'Some Title')))
 
     def test_TrailingComment(self):
         self._test(mpl2 + '''
 [Strings]
 TitleText=Some Title
 ;Stray trailing comment
-''', (('TitleText', 'Some Title'),))
-        self.assert_('MPL' in self.parser.header)
+''', (
+            ('Comment', mpl2),
+            ('IniSection', 'Strings'),
+            ('TitleText', 'Some Title'),
+            ('Comment', 'Stray trailing')))
 
     def test_SpacedTrailingComments(self):
         self._test(mpl2 + '''
 [Strings]
 TitleText=Some Title
 
 ;Stray trailing comment
 ;Second stray comment
 
-''', (('TitleText', 'Some Title'),))
-        self.assert_('MPL' in self.parser.header)
+''', (
+            ('Comment', mpl2),
+            ('IniSection', 'Strings'),
+            ('TitleText', 'Some Title'),
+            ('Comment', 'Second stray comment')))
 
     def test_TrailingCommentsAndJunk(self):
         self._test(mpl2 + '''
 [Strings]
 TitleText=Some Title
 
 ;Stray trailing comment
 Junk
 ;Second stray comment
 
-''', (('TitleText', 'Some Title'), ('Junk', '''\
-
-;Stray trailing comment
-Junk
-;Second stray comment
-
-''')))
-        self.assert_('MPL' in self.parser.header)
+''', (
+            ('Comment', mpl2),
+            ('IniSection', 'Strings'),
+            ('TitleText', 'Some Title'),
+            ('Comment', 'Stray trailing'),
+            ('Junk', 'Junk'),
+            ('Comment', 'Second stray comment')))
 
     def test_JunkInbetweenEntries(self):
         self._test(mpl2 + '''
 [Strings]
 TitleText=Some Title
 
 Junk
 
 Good=other string
-''', (('TitleText', 'Some Title'), ('Junk', '''\
-
-Junk'''), ('Good', 'other string')))
-        self.assert_('MPL' in self.parser.header)
+''', (
+            ('Comment', mpl2),
+            ('IniSection', 'Strings'),
+            ('TitleText', 'Some Title'),
+            ('Junk', 'Junk'),
+            ('Good', 'other string')))
 
 if __name__ == '__main__':
     unittest.main()