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__ = ['propagateTemplateDeps', 00018 'realizeTemplates', 00019 'buildSTL'] 00020 00021 from blockit.tables import SymbolTable 00022 from blockit.funcs import * 00023 from blockit.parsers import pyp 00024 from blockit.sets import ASet 00025 from blocks import * 00026 00027 import os 00028 00029 #................................................................................ 00030 # Global functions and stuff 00031 #................................................................................ 00032 # Built-in type list 00033 header='''!............................................................................... 00034 !. 00035 !. This code was pre-parsed by PyF95++, a block parser and code generator. 00036 !. 00037 !................................................................................''' 00038 header += os.linesep 00039 00040 #................................................................................ 00041 def buildSTL( fileTable, globalTable, destDir=None ): 00042 '''Build a Standard Template Library from all the templated modules within 00043 the fileTable. This is necessary because you can run into circular 00044 dependencies between files based on template instantiations. Therefore, 00045 you either need to create a separate file for each instantiation or you 00046 can put them within a single file and order them appropriately. The 00047 latter is the current method. 00048 00049 fileTable : symbol table containing all the files 00050 globalTable: global symbol table 00051 breakOut: boolean on whether to create multiple files or a single STL file [False] 00052 00053 ''' 00054 # import profile 00055 table = SymbolTable() 00056 table.registerAll( fileTable ) 00057 tempMods = table.filter(And(And(isModule, hasTempParent), 00058 Not(isTemplated))) 00059 00060 #................................................................................ 00061 # If the templated modules parent came from the cache, then set the 00062 # fromCache property on the modules 00063 #................................................................................ 00064 for _mod in tempMods.values(): 00065 if _mod.parent().fromCache: 00066 _mod.fromCache = True 00067 00068 tempModParents = list(set([x.parent() for x in tempMods.values()])) 00069 if not tempModParents: 00070 return None 00071 00072 #................................................................................ 00073 # Generate a depGraph between the template modules and a build order 00074 #................................................................................ 00075 changedBlocks = set() 00076 for blk in tempMods.values(): 00077 blkFile = blk.upTo( AFile ) 00078 changedBlocks.add( blk.parent() ) 00079 changedBlocks.add( blkFile ) 00080 prefix, ext = os.path.splitext( blkFile.fileName() ) 00081 srcDir = os.path.split(prefix)[0] 00082 # tmp = AFile( [ blk.name() + ext, blk.hash() ] ) 00083 # Hash is no longer used so set to zero here 00084 tmp = AFile( [ blk.name() + ext, '0' ] ) 00085 tmp.setNameLength( blk.getNameLength() ) 00086 print 'Creating new AFile: %s' % ( tmp.fileName(), ) 00087 tmp.addChild( blk.parent(), regen=False ) 00088 # profile.runctx( "tmp.addChild( blk, regen=False )", globals(), locals() ) 00089 tmp.setFileName( os.path.join( srcDir, tmp.name() ) ) 00090 tmp.fromCache = blk.fromCache 00091 # tmp.directives = blk.directives 00092 fileTable.register( tmp ) 00093 00094 for blk in changedBlocks: 00095 print 'Regenerating child deps for block: (%s)' % ( blk.name(), ) 00096 blk.regenChildDeps() 00097 00098 #................................................................................ 00099 def propagateTemplateDeps( nonTempBlocks, tempBlocks, IgnoreSymbols=ASet() ): 00100 '''Propagate template parameters from non-templated blocks that instantiate a 00101 templated type to the parent templated block, i.e. the block at the root 00102 of a nested sequence of blocks (e.g. a templated module will have all 00103 blocks under it templated). 00104 00105 nonTempBlocks : symbol table of blocks that are not templated and 00106 have template dependencies 00107 00108 tempBlocks : complete (all blocks expanded) symbol table of blocks that are 00109 templated 00110 IgnoreSymbols: a set of symbols that should not be propagated and instantiated. 00111 00112 ''' 00113 #................................................................................ 00114 global globalSymbolMap 00115 00116 joinChar = tempBlocks.joinCharacter() 00117 for k,v in nonTempBlocks.items(): 00118 dep = v.dependencies() 00119 00120 for typ in dep: 00121 #.................................................................. 00122 # Order of operations: 00123 # 1. Check if user specified external symbols in a directive 00124 # that may have a wildcard. 00125 # 2. Resolve any wildcards in the symbol. 00126 # 3. Parse if its a template spec. 00127 # 4. Add the resolved name to the global symbol map. 00128 # 5. Check if the resolved symbol is an external symbol. 00129 #.................................................................. 00130 if typ in IgnoreSymbols: continue 00131 _typ = v.resolveSymbol( typ, mangle=False ) 00132 pairs = parseTemplateSpecString( _typ ) 00133 typ = _typ 00134 if typ in IgnoreSymbols: continue 00135 00136 while len( pairs ) > 0: 00137 name, spec = pairs.pop() 00138 tmp = tempBlocks.filter(And(Or(Or(isAType, isFunction),isSubroutine), 00139 startsWith(name+joinChar))).values() 00140 00141 if len( tmp ) == 0: 00142 msg = "Missing dependency: %s<%s>%s" % ( name, spec, os.linesep ) 00143 msg += "For block %s%s" % ( v.name(), os.linesep ) 00144 continue 00145 # raise Exception( msg ) 00146 00147 blk = len( tmp ) > 1 and \ 00148 templateMRO( v, tmp, spec, v.getSig( typ ) ) or \ 00149 tmp[ 0 ] 00150 00151 spec = templateSpecToTuple( spec ) 00152 blk.addObjects( spec ) 00153 spec = ','.join( [ x for x in spec if x not in 00154 IgnoreSymbols ] ) 00155 pairs.extend( parseTemplateSpecString( spec ) ) 00156 00157 #................................................................................ 00158 def templateMRO( caller, tmp, spec, sig=None ): 00159 '''Given a list of blocks, a template spec and a optional 00160 function/subroutine signature, find the block that matches. 00161 00162 ''' 00163 # Filters for resolving ambiguous dependencies 00164 # Number of template specifications 00165 def specLength(n): return lambda v: len(v.template()) == n 00166 00167 # If parent is template 00168 zeroDepth = lambda v: isinstance(v.parent(), Template) 00169 00170 # Depth of nesting 00171 def _depth(typ, c): 00172 if not f2(typ): 00173 c += 1 00174 depth(t, c) 00175 return c 00176 00177 def depth(typ): 00178 return _depth( typ, 0 ) 00179 00180 #.................................................................... 00181 # More than one possibility, so try to resolve with mro list 00182 # 1. Check that the template length is the same. 00183 # 2. Check if the parent is the template. 00184 #.................................................................... 00185 name = tmp[0].name() 00186 mro = ( specLength( len( templateSpecToTuple( spec ) ) ), zeroDepth ) 00187 for test in mro: 00188 tmp = [ x for x in tmp if test( x ) ] 00189 if len( tmp ) == 1: return tmp[ 0 ] 00190 00191 #.................................................................... 00192 # Check the function/subroutine type signature for a match 00193 #.................................................................... 00194 if sig: 00195 for x in tmp: 00196 _args = x.argList 00197 if not ( len( _args ) == len( sig ) ): continue 00198 _syms = x.symbols 00199 _args = [ _syms[ y ] for y in _args ] 00200 if all( map( lambda x, y: x == y, _args, sig ) ): return x 00201 00202 #...................................................................... 00203 # Raise exception, no match 00204 #...................................................................... 00205 if ( len( tmp ) > 1 ): 00206 print "Ambiguous dependencies found:" 00207 for t in tmp: 00208 print "(%s) in (%s)" % ( t.name(), t.upTo( AFile ).name() ) 00209 raise Exception() 00210 elif ( len( tmp ) == 0 ): 00211 msg = "Missing dependency: %s<%s>%s" % ( name, spec, os.linesep ) 00212 msg += "For block %s%s" % ( caller.name(), os.linesep ) 00213 raise Exception( msg ) 00214 00215 #................................................................................ 00216 def realizeTemplates( table, cache, IgnoreSymbols=ASet() ): 00217 '''Find all the root templated blocks and loop through them: 00218 00219 table : global symbol table 00220 lib : FortranLibrary CacheManager object 00221 00222 Logic 00223 ----- 00224 1. Resolve their objects (i.e. any wildcards and such). 00225 00226 2. Begin main loop and propagate these objects to their children and 00227 discover any new types that are created from the templates internally. 00228 00229 3. Propagate these new types to their corresponding template blocks 00230 objects sets. 00231 00232 4. Goto to 2 and repeat until no object sets of any template have changed 00233 in any of the templated types. 00234 00235 Returns a new SymbolTable() with the instantiated templates. 00236 00237 ''' 00238 00239 tempTable = SymbolTable() 00240 realized = SymbolTable() 00241 00242 # Root template blocks 00243 rootTempBlocks = table.filter( isTemplate ) 00244 00245 # import pdb; pdb.set_trace() 00246 # All leaf templated blocks 00247 # leafTempBlocks = table.filter(And(isTemplated, isLeaf)) 00248 leafTempBlocks = table.filter( And( isTemplated, Not( isTemplate ) ) ) 00249 00250 #................................................................................ 00251 # Recursion termination: When objects sets of all root templated blocks 00252 # stops changing. 00253 #................................................................................ 00254 anyChanged = True 00255 while anyChanged: 00256 anyChanged = False 00257 00258 for sym, blk in rootTempBlocks.items(): 00259 objSet = blk.objects() 00260 if not objSet.changed(): continue 00261 _objSet = objSet.changeSet() 00262 blk.objects().reset() 00263 for params in _objSet: 00264 print 'From blk: %s'%( blk.name(), ) 00265 print 'Instantiating (%s) with parameters %s'% \ 00266 (','.join( blk.children() ), str( params ) ) 00267 _blk = blk.instantiate( params, cache ) 00268 00269 #............................................................. 00270 # Temporarily add _blk to the realized table and call 00271 # propagateTemplateDeps to push it's dependencies to the other 00272 # blocks. Then add it to the returned tempTable symbol table. 00273 #............................................................. 00274 realized.register( _blk ) 00275 propagateTemplateDeps( realized, 00276 leafTempBlocks, 00277 IgnoreSymbols ) 00278 tempTable.register( realized.pop( _blk.name() ) ) 00279 00280 anyChanged = True 00281 00282 return tempTable 00283 00284