⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 generators.jam

📁 C++的一个好库。。。现在很流行
💻 JAM
📖 第 1 页 / 共 3 页
字号:
# (probably after conversion by other generators)
rule viable-source-types-for-generator-real ( generator ) 
{        
    local source-types = [ $(generator).source-types ] ;
    if ! $(source-types)
    {
        # If generator does not specify any source types,
        # it might be special generator like builtin.lib-generator
        # which just relays to other generators. Return '*' to
        # indicate that any source type is possibly OK, since we don't
        # know for sure.
        return * ;
    }
    else
    {            
        local result ;
        for local s in $(source-types)
        {
            result += [ type.all-derived $(s) ] 
              [ generators.viable-source-types $(s) ] ;
        }
        result = [ sequence.unique $(result) ] ;        
        if * in $(result)
        {
            result = * ;
        }        
        return $(result) ;
    }        
}    

# Helper rule, caches the result of 'viable-source-types-for-genrator'.
local rule viable-source-types-for-generator ( generator )
{
    local key = .vstg.$(generator) ;
    if ! $($(key))
    {
        local v = [ viable-source-types-for-generator-real $(generator) ] ;
        if ! $(v)
        {
            v = none ;
        }
        $(key) = $(v) ;        
    }
    
    if $($(key)) != none
    {
        return $($(key)) ;
    }        
}



# Returns usage requirements + list of created targets
local rule try-one-generator-really ( project name ? : generator : 
    target-type : property-set : sources * )
{
    local targets =
      [ $(generator).run $(project) $(name)
                       : $(property-set)
                       : $(sources)
      ] ;
            
    local usage-requirements ;
    if $(targets) && [ class.is-a $(targets[1]) : property-set ]
    {
        usage-requirements = $(targets[1]) ;
        targets = $(targets[2-]) ;
    }
    else
    {
        usage-requirements = [ property-set.empty ] ;
    }
    
    generators.dout [ indent ] "  generator" [ $(generator).id ] " spawned " ;
    generators.dout [ indent ] " " $(targets) ; 
    if $(targets)
    {
        return $(usage-requirements) $(targets) ;
    }    
}

# Checks if generator invocation can be pruned, because it's guaranteed
# to fail. If so, quickly returns empty list. Otherwise, calls
# try-one-generator-really.
local rule try-one-generator ( project name ? : generator : 
    target-type : property-set : sources * )
{    
    local source-types ;
    for local s in $(sources)
    {
        source-types += [ $(s).type ] ;
    }
    local viable-source-types = 
      [ viable-source-types-for-generator $(generator) ] ;
    
    if  $(source-types) && $(viable-source-types) != * && 
      ! [ set.intersection $(source-types) : $(viable-source-types) ] 
    {
        local id = [ $(generator).id ] ;
        generators.dout [ indent ] "generator '$(id)' pruned" ;
        #generators.dout [ indent ] "source-types" '$(source-types)' ;
        #generators.dout [ indent ] "viable-source-types" '$(viable-source-types)' ;
    }          
    else {
        return [ try-one-generator-really $(project) $(name)
          : $(generator)
            : $(target-type) : $(property-set) : $(sources) ] ;
    }       
}



rule construct-types ( project name ? : target-types + :
    property-set : sources + )
{
    local result ;
    local matched-types ; 
    local usage-requirements = [ property-set.empty ] ;
    for local t in $(target-types)
    {
        local r = [ construct $(project) $(name) : $(t) : $(property-set) :
          $(sources) ] ;
        if $(r)
        {
            usage-requirements = [ $(usage-requirements).add $(r[1]) ] ;
            result += $(r[2-]) ;
            matched-types += $(t) ;
        }
    }
    # TODO: have to introduce parameter controlling if
    # several types can be matches and add appropriate
    # checks 

    # TODO: need to review the documentation for
    # 'construct' to see if it should return $(source) even
    # if nothing can be done with it. Currents docs seem to
    # imply that, contrary to the behaviour.
    if $(result)
    {
        return $(usage-requirements) $(result) ;
    }
    else
    {
        return $(usage-requirements) $(sources) ;
    }
}

# Ensures all 'targets' have types. If this is not so, exists with 
# error.
local rule ensure-type ( targets * )
{
    for local t in $(targets)
    {
        if ! [ $(t).type ]
        {
            errors.error "target" [ $(t).str ] "has no type" ;
        }        
    }    
}
    
# Returns generators which can be used to construct target of specified type
# with specified properties. Uses the following algorithm:
# - iterates over requested target-type and all it's bases (in the order returned bt
#   type.all-bases.
# - for each type find all generators that generate that type and which requirements
#   are satisfied by properties.
# - if the set of generators is not empty, returns that set.
#
# Note: this algorithm explicitly ignores generators for base classes if there's
# at least one generator for requested target-type.
local rule find-viable-generators-aux ( target-type : property-set )
{
    # Select generators that can create the required target type.
    local viable-generators = ;
    local generator-rank = ;

    import type ;
    local t = [ type.all-bases $(target-type) ] ;
    
    generators.dout  [ indent ] find-viable-generators target-type= $(target-type) 
      property-set= [ $(property-set).as-path ]
          ;
    
    # Get the lit of generators for the requested type.
    # If no generator is registered, try base type, and so on.
    local generators ;
    while $(t[1])
    {
        generators.dout  [ indent ] "trying type" $(t[1]) ;    
        if $(.generators.$(t[1]))
        {
            generators.dout [ indent ] "there are generators for this type" ;
            generators = $(.generators.$(t[1])) ;
            
            if $(t[1]) != $(target-type)
            {
                # We're here, when no generators for target-type are found,
                # but there are some generators for a base type.
                # We'll try to use them, but they will produce targets of
                # base type, not of 'target-type'. So, we clone the generators
                # and modify the list of target types.
                local generators2 ;
                for local g in $(generators)
                {
                    # generators.register adds generator to the list of generators
                    # for toolsets, which is a bit strange, but should work.
                    # That list is only used when inheriting toolset, which
                    # should have being done before generators are run.
                    generators2 += [ 
                      $(g).clone-and-change-target-type $(t[1]) : $(target-type) ] ;
                    generators.register $(generators2[-1]) ;
                }                
                generators = $(generators2) ;
            }                        
            t = ;
        }        
        t = $(t[2-]) ;            
    }
    
    
    for local g in $(generators)
    {
        generators.dout [ indent ] "trying generator" [ $(g).id ] "(" [ $(g).source-types ] -> [ $(g).target-types ] ")" ;
            
        local m = [ $(g).match-rank $(property-set) ] ;
        if $(m) 
        {
            generators.dout [ indent ] "  is viable" ;
            viable-generators += $(g) ;
        }                                    
    }
                            
    return $(viable-generators) ;
}

local rule find-viable-generators ( target-type : property-set )
{
    local key = $(target-type).$(property-set) ;
    local l = $(.fv.$(key)) ;
    if ! $(l)
    {
        l = [ find-viable-generators-aux $(target-type) : $(property-set) ] ;
        if ! $(l)
        {
            l = none ;
        }        
        .fv.$(key) = $(l) ;
    }
    
    if $(l) = none
    {
        l = ;
    }
                    
    local viable-generators ;
    for local g in $(l)
    {
        # Avoid trying the same generator twice on different levels.        
        if ! $(g) in $(.active-generators) 
        {
            viable-generators += $(g) ;
        }        
    }
    
    # Generators which override 'all'.
    local all-overrides ;
    # Generators which are overriden
    local overriden-ids ;    
    for local g in $(viable-generators)
    {
        local id = [ $(g).id ] ;
        local this-overrides = $(.override.$(id)) ;
        overriden-ids += $(this-overrides) ;
        if all in $(this-overrides)
        {
            all-overrides += $(g) ;
        }        
    }         
    if $(all-overrides)
    {
        viable-generators = $(all-overrides) ;
    }
    local result ;
    for local g in $(viable-generators)
    {
        if ! [ $(g).id ] in $(overriden-ids)
        {
            result += $(g) ;
        }        
    }
        
    return $(result) ;
}    
        
.construct-stack = ;

# Attempts to construct target by finding viable generators, running them
# and selecting the dependency graph
local rule construct-really (
   project name ? : target-type : property-set : sources * )
{
    viable-generators = [ find-viable-generators $(target-type) : $(property-set) ] ;
                        
    generators.dout [ indent ] "*** " [ sequence.length $(viable-generators) ] 
      " viable generators" ;
    
    local result ;
    for local g in $(viable-generators)
    {
        # This variable will be restored on exit from this scope.
        local .active-generators = $(g) $(.active-generators) ;
        
        local r = [ try-one-generator $(project) $(name) : $(g) : $(target-type) :
          $(property-set) : $(sources) ] ;
        
        if $(r)
        {
            if $(result)
            {
                error "Ambiguity found when searching for best transformation" ;
            }
            else
            {
                result = $(r) ;
            }            
        }
    }
    
    return $(result) ;
}       
    
        
# Attempts to create target of 'target-type' with 'properties'
# from 'sources'. The 'sources' are treated as a collection of
# *possible* ingridients -- i.e. it is not required to consume
# them all. If 'multiple' is true, the rule is allowed to return
# several targets of 'target-type'.          
#
#
# Returns a list of target. When this invocation is first instance of
# 'construct' in stack, returns only targets of requested 'target-type',
# otherwise, returns also unused sources and additionally generated
# targets.    
#
# Does not return target which are not of 'allowed-type' or of type derived from
# it. If 'allowed-type' is not specified, it's defaulted to 'target-type'.
# See lib-target-class for use case of this.
rule construct ( project name ? : target-type : property-set * : sources * 
   : allowed-type * )
{
    if (.construct-stack)
    {
        ensure-type $(sources) ;
    }
        
    .construct-stack += 1 ;

    increase-indent ;

    if $(.debug)
    {        
        generators.dout [ indent ] "*** construct" $(target-type) ;
    
        for local s in $(sources)
        {
            generators.dout [ indent ] "    from" $(s) ;
        }
        generators.dout [ indent ] "    properties:" [ $(property-set).raw ] ;        
    }
    
               
    local result = [ construct-really $(project) $(name)  
      : $(target-type) : $(property-set) : $(sources) ] ;
                    
    decrease-indent ;
        
    .construct-stack = $(.construct-stack[2-]) ;
                
    
    return $(result) ;        
}

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -