BlockIt
|
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