Changeset 966


Ignore:
Timestamp:
Jun 24, 2012 9:31:10 PM (11 years ago)
Author:
jemian
Message:

refs #8, commas allowed in variable declarations as delimiter, reduce code smell in parser state engine, aggregate test macro suite

Location:
specdomain/src/specdomain
Files:
1 added
1 deleted
4 edited
12 moved

Legend:

Unmodified
Added
Removed
  • specdomain/src/specdomain/sphinxcontrib/specmacrofileparser.py

    r965 r966  
    7373                                    + non_greedy_whitespace
    7474                                    + r'(local|global|constant)'
    75                                     + r'((?:\s*@?[\w.eE+-]+\[?\]?)*)'
     75                                    + r'((?:,?\s*@?[\w.eE+-]+\[?\]?)*)'
    7676                                    + non_greedy_whitespace
    7777                                    + r'#' + non_greedy_filler
     
    7979                                    re.VERBOSE)
    8080
     81# TODO: handle "#: " indicating a description of a variable on the preceding line
    8182
    8283class SpecMacrofileParser:
     
    9293        all the extended comments and add them as nodes to the current document.
    9394       
    94         An additional step would be to parse for:
    95         * def
    96         * cdef
    97         * rdef
    98         * global    (done)
    99         * local    (done)
    100         * constant    (done)
    101         * array
    102         * ...
    103        
     95    An additional step would be to parse for:
     96    * def
     97    * cdef
     98    * rdef
     99    * global    (done)
     100    * local    (done)
     101    * constant    (done)
     102    * array
     103    * ...
    104104    '''
    105105
     
    134134        self.filename = filename
    135135        self.buf = open(filename, 'r').read()
    136    
     136
    137137    def parse_macro_file(self):
    138138        """
     
    140140        """
    141141        line_number = 0
    142         state = 'global'
    143         state_stack = []
     142        self.state = 'global'
     143        self.state_stack = []
    144144        for line in self.buf.split('\n'):
    145             if state not in self.states:
    146                 raise RuntimeError, "unexpected parser state: " + state
     145            m = None
     146            if self.state not in self.states:
     147                raise RuntimeError, "unexpected parser state: " + self.state
    147148            line_number += 1
    148             if state == 'global':
    149 
    150                 m = self._match(lgc_variable_sig_re, line)
    151                 if m is not None:           # local, global, or constant variable declaration
    152                     objtype, args = lgc_variable_sig_re.match(line).groups()
    153                     pos = args.find('#')
    154                     if pos > -1:
    155                         args = args[:pos]
    156                     m['objtype'] = objtype
    157                     m['start_line'] = m['end_line'] = line_number
    158                     del m['start'], m['end'], m['line']
    159                     if objtype == 'constant':
    160                         var, _ = args.split()
    161                         m['text'] = var
    162                         self.findings.append(dict(m))
    163                     else:
    164                         # TODO: consider not indexing "global" inside a def
    165                         # TODO: consider not indexing "local" at global level
    166                         for var in args.split():
    167                             m['text'] = var
    168                             self.findings.append(dict(m))
    169                             # TODO: to what is this local?  (remember the def it belongs to)
     149            if self.state == 'global':
     150
     151                if self._is_lgc_variable(line, line_number):
    170152                    continue
    171153
    172                 # test if one-line extended comment
    173                 m = self._match(extended_comment_block_sig_re, line)
    174                 if m is not None:
    175                     del m['start'], m['end'], m['line']
    176                     m['objtype'] = 'extended comment'
    177                     m['start_line'] = m['end_line'] = line_number
    178                     m['text'] = m['text'].strip()
    179                     self.findings.append(dict(m))
     154                if self._is_one_line_extended_comment(line, line_number):
    180155                    continue
    181                
    182                 # test if start of multiline extended comment
    183                 m = self._match(extended_comment_start_sig_re, line)
    184                 if m is not None:
    185                     text = m['line'][m['end']:]
    186                     del m['start'], m['end'], m['line']
    187                     m['objtype'] = 'extended comment'
    188                     m['start_line'] = line_number
    189                     ec = dict(m)    # container for extended comment data
    190                     ec['text'] = [text]
    191                     state_stack.append(state)
    192                     state = 'extended comment'
     156
     157                if self._is_multiline_start_extended_comment(line, line_number):
    193158                    continue
    194159
    195             elif state == 'extended comment':
    196                 # test if end of multiline extended comment
    197                 m = self._match(extended_comment_end_sig_re, line)
    198                 if m is not None:
    199                     text = m['line'][:m['start']]
    200                     ec['text'].append(text)
    201                     ec['text'] = '\n'.join(ec['text'])
    202                     ec['end_line'] = line_number
    203                     self.findings.append(dict(ec))
    204                     state = state_stack.pop()
    205                     del ec
    206                 else:
     160            elif self.state == 'extended comment':
     161
     162                if not self._is_multiline_end_extended_comment(line, line_number):
    207163                    # multiline extended comment continues
    208                     ec['text'].append(line)
     164                    self.ec['text'].append(line)
    209165                continue
     166
     167            elif self.state == 'def macro':
     168                pass
     169
     170            elif self.state == 'cdef macro':
     171                pass
     172
     173            elif self.state == 'rdef macro':
     174                pass
     175   
     176    def _is_lgc_variable(self, line, line_number):
     177        ''' local, global, or constant variable declaration '''
     178        m = self._match(lgc_variable_sig_re, line)
     179        if m is None:
     180            return False
     181        objtype, args = lgc_variable_sig_re.match(line).groups()
     182        pos = args.find('#')
     183        if pos > -1:
     184            args = args[:pos]
     185        m['objtype'] = objtype
     186        m['start_line'] = m['end_line'] = line_number
     187        del m['start'], m['end'], m['line']
     188        if objtype == 'constant':
     189            var, _ = args.split()
     190            m['text'] = var.rstrip(',')
     191            self.findings.append(dict(m))
     192        else:
     193            # TODO: consider not indexing "global" inside a def
     194            # TODO: consider not indexing "local" at global level
     195            for var in args.split():
     196                m['text'] = var.rstrip(',')
     197                self.findings.append(dict(m))
     198                # TODO: to what is this local?  (remember the def it belongs to)
     199        return True
     200   
     201    def _is_one_line_extended_comment(self, line, line_number):
     202        m = self._match(extended_comment_block_sig_re, line)
     203        if m is None:
     204            return False
     205        del m['start'], m['end'], m['line']
     206        m['objtype'] = 'extended comment'
     207        m['start_line'] = m['end_line'] = line_number
     208        m['text'] = m['text'].strip()
     209        self.findings.append(dict(m))
     210        return True
     211   
     212    def _is_multiline_start_extended_comment(self, line, line_number):
     213        m = self._match(extended_comment_start_sig_re, line)
     214        if m is None:
     215            return False
     216        text = m['line'][m['end']:]
     217        del m['start'], m['end'], m['line']
     218        m['objtype'] = 'extended comment'
     219        m['start_line'] = line_number
     220        self.ec = dict(m)    # container for extended comment data
     221        self.ec['text'] = [text]
     222        self.state_stack.append(self.state)
     223        self.state = 'extended comment'
     224        return True
     225
     226    def _is_multiline_end_extended_comment(self, line, line_number):
     227        m = self._match(extended_comment_end_sig_re, line)
     228        if m is None:
     229            return False
     230        text = m['line'][:m['start']]
     231        self.ec['text'].append(text)
     232        self.ec['text'] = '\n'.join(self.ec['text'])
     233        self.ec['end_line'] = line_number
     234        self.findings.append(dict(self.ec))
     235        self.state = self.state_stack.pop()
     236        del self.ec
     237        return True
    210238   
    211239    def _match(self, regexp, line):
     
    239267        """create the ReStructured Text from what has been found"""
    240268        s = []
     269        declarations = []
    241270        for r in self.findings:
    242271            if r['objtype'] == 'extended comment':
     
    248277                s.append( '' )
    249278                s.append(r['text'])
     279            elif r['objtype'] in ('local', 'global', 'constant'):
     280                declarations.append(r)      # remember, show this later
    250281            # TODO: other objtypes
     282        if len(declarations) > 0:
     283            col_keys = ('text', 'objtype', 'start_line', 'end_line', )
     284            widths = {}
     285            for key in col_keys:
     286                widths[key] = len( str(key) )
     287            for d in declarations:
     288                for key, w in widths.items():
     289                    widths[key] = max(w, len( str(d[key]) ) )
     290            separator = " ".join( ["="*widths[key] for key in col_keys] )
     291            format = " ".join( ["%%-%ds"%widths[key] for key in col_keys] )
     292            s.append( '' )
     293            s.append( '.. rubric:: Variable Declarations:' )
     294            s.append( '' )
     295            s.append( separator )
     296            #s.append( " ".join( [str(key) for key in col_keys]) )
     297            s.append( format % tuple([str(key) for key in col_keys]) )
     298            s.append( separator )
     299            for d in declarations:
     300                s.append( format % tuple([str(d[key]) for key in col_keys]) )
     301            s.append( separator )
    251302        return '\n'.join(s)
    252303
    253304
    254305if __name__ == '__main__':
    255     p = SpecMacrofileParser('../test/test-battery.mac')
    256     #print p.ReST()
    257     print p
    258     p = SpecMacrofileParser('../test/cdef-examples.mac')
    259     #print p.ReST()
     306    filelist = [
     307        '../macros/test-battery.mac',
     308        '../macros/cdef-examples.mac',
     309        '../macros/shutter.mac',
     310    ]
     311    for item in filelist:
     312        p = SpecMacrofileParser(item)
     313        #print p
     314        print p.ReST()
  • specdomain/src/specdomain/test/cdef-examples.mac.rst

    r964 r966  
    11.. $Id$
    22
    3 ====================================================
    4 SPEC macro source file: ``cdef-examples.mac``
    5 ====================================================
     3=============================================================
     4SPEC macro source file: ``../macros/cdef-examples.mac``
     5=============================================================
    66
    7 .. autospecmacro:: cdef-examples.mac
     7.. autospecmacro:: ../macros/cdef-examples.mac
  • specdomain/src/specdomain/test/shutter.mac.rst

    r964 r966  
    22
    33====================================================
    4 SPEC macro source file: ``shutter.mac``
     4SPEC macro source file: ``../macros/shutter.mac``
    55====================================================
    66
     
    88        No attempt to prepare it for ReST comments has been made.
    99
    10 .. autospecmacro:: shutter.mac
     10.. autospecmacro:: ../macros/shutter.mac
  • specdomain/src/specdomain/test/test-battery.mac.rst

    r964 r966  
    11.. $Id$
    22
    3 ====================================================
    4 SPEC macro source file: ``test-battery.mac``
    5 ====================================================
     3========================================================
     4SPEC macro source file: ``../macros/test-battery.mac``
     5========================================================
    66
    7 .. autospecmacro:: test-battery.mac
     7.. autospecmacro:: ../macros/test-battery.mac
Note: See TracChangeset for help on using the changeset viewer.