BlockIt
funcs.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__ = ['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 
 All Classes Namespaces Files Functions Variables Properties