BlockIt
parsers.py
Go to the documentation of this file.
00001 #............................................................................
00002 # Copyright (c) 2009,2010,2011 David Car, david.car7@gmail.com
00003 #
00004 # This program is free software; you can redistribute it and/or modify it under
00005 # the terms of the GNU General Public License as published by the Free Software
00006 # Foundation; either version 2 of the License, or (at your option) any later
00007 # version.
00008 #
00009 # This program is distributed in the hope that it will be useful, but WITHOUT
00010 # ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
00011 # FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
00012 #
00013 # You should have received a copy of the GNU General Public License along with
00014 # this program; if not, write to the Free Software Foundation, Inc., 59 Temple
00015 # Place, Suite 330, Boston, MA 02111-1307 USA
00016 #..........................................................................
00017 __all__ = ['BlockParser', 'BlockParserError']
00018 
00019 from tables import SymbolTable
00020 from scanners import LineScanner
00021 import external.pyparsing as pyp
00022 
00023 class BlockParserError(Exception):
00024     def __init__(self, msg):
00025         self.msg = msg
00026     def __str__(self):
00027         return repr(self.msg)
00028 
00029 #................................................................................
00030 # Block parser
00031 #................................................................................
00032 class BlockParser(object):
00033     
00034     def __init__(self, scanner=None, ignoreChars='', contChar=None ):
00035         self._scanner = scanner
00036         self._blockDict = {}
00037         self._blockList = []
00038         self._ignore = ignoreChars
00039         self._contChar = contChar
00040         self._GRAMMAR = None
00041     
00042     def setScanner(self, scanner):
00043         '''Set the scanner to use.
00044 
00045         '''
00046         self._scanner = scanner
00047 
00048     def parse(self):
00049         raise NotImplementedError("Virtual method 'parse()' in BlockParser")
00050 
00051     def ignore(self, line):
00052         '''Ignore lines starting with comment character and null strings. 
00053 
00054         '''
00055         return any([line.startswith(x) for x in self._ignore]) or not line
00056 
00057     def _parse(self, blk):
00058         scanner = self._scanner
00059         GRAMMAR = self._GRAMMAR
00060         contChar = self._contChar
00061         ignore = self.ignore
00062 
00063         # Keep reading until the end of the block is reached or a new block is
00064         # found and a branch is made
00065         _multi_line = None
00066         while True:
00067             #.........................
00068             # Check for comment line
00069             #.........................
00070             _line = scanner.nextLine()
00071             if ignore( _line.lstrip() ):
00072                 blk.addLine( _line )
00073                 continue
00074 
00075             #......................................................
00076             # Check for continuation character and concatenate
00077             #......................................................
00078             line = ''
00079             if contChar is not None:
00080                 _cont = True
00081                 _multi_line = []
00082                 _multi_line.append( _line )
00083                 while _cont:
00084                     _loc = _line.rfind( contChar )
00085                     if _loc != -1 and ignore(_line[_loc+1:].lstrip()):
00086                         line += _line[ :_loc ]
00087                         _multi_line.append( scanner.nextLine() )
00088                         _line = _multi_line[-1].lstrip(' '+contChar)
00089                     else:
00090                         line += _line
00091                         _cont = False
00092             else:
00093                 line += _line
00094                     
00095             #....................
00096             # Check for sentinel
00097             #....................
00098             if blk.sentinel( line ): break
00099 
00100             newBlk = GRAMMAR.searchString( line )
00101             if newBlk:
00102                 newBlk = newBlk[ 0 ][ 0 ]
00103                 if _multi_line: 
00104                     newBlk.addLine( ''.join( _multi_line ) )
00105                 else:
00106                     newBlk.addLine( line )
00107 
00108                 #...........................................................
00109                 # The addChild method is called prior to parsing so that
00110                 # dependencies are not generated for blocks within
00111                 # templates, since template status is determined by the
00112                 # enclosing block/scope.  Dependencies are shared with the
00113                 # enclosing block/scope by the shareDeps() method after
00114                 # parsing of the block.  The dependencies are only shared
00115                 # with the parent and not propagated up the tree.
00116                 #...........................................................
00117                 blk.addChild( newBlk )
00118 
00119                 try:
00120                     self._parse( newBlk )
00121                 except EOFError:
00122                     msg = 'Block (%s) not closed properly'%( newBlk.name(), )
00123                     raise BlockParserError(msg) 
00124                     
00125                 newBlk.shareDeps( propagate=False )
00126                 line = ''  # empty line
00127                 
00128             if line: 
00129                 if _multi_line: 
00130                     blk.addLine( ''.join( _multi_line ) )
00131                 else: 
00132                     blk.addLine( line )
00133 
00134     def register(self, block):
00135         '''Register a block or list of blocks.
00136 
00137         '''
00138         if isinstance(block, list):
00139             for blk in block:
00140                 blk.GRAMMAR.setParseAction(blk.factory)
00141                 self._GRAMMAR = \
00142                     (self._GRAMMAR is None) and \
00143                     blk.GRAMMAR or \
00144                     (blk.GRAMMAR|self._GRAMMAR)
00145                 self._blockDict[blk.BLOCKTYPE] = block
00146             self._blockList.extend(block)
00147         else:
00148             block.GRAMMAR.setParseAction(block.factory)
00149             self._blockList.append(block)
00150             self._GRAMMAR = \
00151                 (self._GRAMMAR is None) and \
00152                 block.GRAMMAR or \
00153                 (block.GRAMMAR|self._GRAMMAR)
00154             self._blockDict[block.BLOCKTYPE] = block
 All Classes Namespaces Files Functions Variables Properties