📄 feature.jam
字号:
# (C) Copyright David Abrahams 2001. Permission to copy, use, modify, sell and
# distribute this software is granted provided this copyright notice appears in
# all copies. This software is provided "as is" without express or implied
# warranty, and with no claim as to its suitability for any purpose.
import "class" : * ;
import errors : error lol->list ;
import sequence ;
import regex ;
import set ;
import utility ;
import modules indirect ;
import assert : * ;
local rule setup ( )
{
.all-attributes =
implicit
executed
composite
optional
symmetric
free
incidental
path
dependency
propagated
link-incompatible
subfeature
order-sensitive
;
.all-features = ;
.all-subfeatures = ; # non-subfeatures
.all-top-features = ; # non-subfeatures
.all-implicit-values = ;
}
setup ;
# prepare a fresh space to test in by moving all global variable
# settings into the given temporary module and erasing them here.
rule prepare-test ( temp-module )
{
DELETE_MODULE $(temp-module) ;
# transfer globals to temp-module
for local v in [ VARNAMES feature ]
{
if [ MATCH (\\.) : $(v) ]
{
modules.poke $(temp-module) : $(v) : $($(v)) ;
$(v) = ;
}
}
setup ;
}
# clear out all global variables and recover all variables from the
# given temporary module
rule finish-test ( temp-module )
{
# clear globals
for local v in [ VARNAMES feature ]
{
if [ MATCH (\\.) : $(v) ]
{
$(v) = ;
}
}
for local v in [ VARNAMES $(temp-module) ]
{
$(v) = [ modules.peek $(temp-module) : $(v) ] ;
}
DELETE_MODULE $(temp-module) ;
}
# Transform features by bracketing any elements which aren't already
# bracketed by "<>"
local rule grist ( features * )
{
local empty = "" ;
local r = $(empty:G=$(features)) ;
return $(r) ;
}
empty = "" ;
# declare a new feature with the given name, values, and attributes.
rule feature (
name # feature name
: values * # the allowable values - may be extended later with feature.extend
: attributes * # The feature's attributes (e.g. implicit, free, propagated...)
)
{
name = [ grist $(name) ] ;
local error ;
# if there are any unknown attributes...
if ! ( $(attributes) in $(.all-attributes) )
{
error = unknown attributes:
[ set.difference $(attributes) : $(.all-attributes) ] ;
}
else if $(name) in $(.all-features)
{
error = feature already defined: ;
}
else if implicit in $(attributes) && free in $(attributes)
{
error = free features cannot also be implicit ;
}
else if free in $(attributes) && propagated in $(attributes)
{
error = free features cannot be propagated ;
}
if $(error)
{
error $(error)
: "in" feature declaration:
: feature [ lol->list $(1) : $(2) : $(3) ] ;
}
$(name).values ?= ;
$(name).attributes = $(attributes) ;
$(name).subfeatures ?= ;
$(attributes).features += $(name) ;
.all-features += $(name) ;
if subfeature in $(attributes)
{
.all-subfeatures += $(name) ;
}
else
{
.all-top-features += $(name) ;
}
extend $(name) : $(values) ;
}
# set default value of the given feature, overriding any previous
# default.
rule set-default ( feature : value )
{
local f = [ grist $(feature) ] ;
if ! $(value) in $($(f).values)
{
errors.error "The specified default value, '$(value)' is invalid"
: "allowed values are: " $($(f).values) ;
}
$(f).default = $(value) ;
}
# return the default property values for the given features.
rule defaults ( features * )
{
local result ;
for local f in $(features)
{
local a = $($(f).attributes) ;
if ( free in $(a) ) || ( optional in $(a) )
{
}
else
{
result += $(f)$($(f).default) ;
}
}
return $(result) ;
}
# returns true iff all elements of names are valid features.
rule valid ( names + )
{
if $(names) in $(.all-features)
{
return true ;
}
}
# return the attibutes of the given feature
rule attributes ( feature )
{
if ! [ valid $(feature) ]
{
error \"$(feature)\" is not a valid feature name ;
}
return $($(feature).attributes) ;
}
# return the values of the given feature
rule values ( feature )
{
return $($(feature).values) ;
}
# returns true iff 'value-string' is a value-string of an implicit feature
rule is-implicit-value ( value-string )
{
local v = [ regex.split $(value-string) - ] ;
local failed ;
if ! $(v[1]) in $(.all-implicit-values)
{
failed = true ;
}
else
{
local feature = $($(v[1]).implicit-feature) ;
for local subvalue in $(v[2-])
{
if ! [ find-implied-subfeature $(feature) $(subvalue) : $(v[1]) ]
{
failed = true ;
}
}
}
if ! $(failed)
{
return true ;
}
}
# return the implicit feature associated with the given implicit value.
rule implied-feature ( implicit-value )
{
local components = [ regex.split $(implicit-value) "-" ] ;
local feature = $($(components[1]).implicit-feature) ;
if ! $(feature)
{
error \"$(implicit-value)\" is not a value of an implicit feature ;
feature = "" ; # keep testing happy; it expects a result.
}
return $(feature) ;
}
local rule find-implied-subfeature ( feature subvalue : value-string ? )
{
# feature should be of the form <feature-name>
if $(feature) != $(feature:G)
{
error invalid feature $(feature) ;
}
return $($(feature)$(value-string:E="")<>$(subvalue).subfeature) ;
}
# Given a feature and a value of one of its subfeatures, find the name
# of the subfeature. If value-string is supplied, looks for implied
# subfeatures that are specific to that value of feature
rule implied-subfeature (
feature # The main feature name
subvalue # The value of one of its subfeatures
: value-string ? # The value of the main feature
)
{
local subfeature = [ find-implied-subfeature $(feature) $(subvalue)
: $(value-string) ] ;
if ! $(subfeature)
{
value-string ?= "" ;
error \"$(subvalue)\" is not a known subfeature value of
$(feature)$(value-string) ;
}
return $(subfeature) ;
}
# generate an error if the feature is unknown
local rule validate-feature ( feature )
{
if ! $(feature) in $(.all-features)
{
error unknown feature \"$(feature)\" ;
}
}
# Given a feature and value, or just a value corresponding to an
# implicit feature, returns a property set consisting of all component
# subfeatures and their values. For example:
#
# expand-subfeatures <toolset>gcc-2.95.2-linux-x86
# -> <toolset>gcc <toolset-version>2.95.2 <toolset-os>linux <toolset-cpu>x86
#
# equivalent to:
# expand-subfeatures gcc-2.95.2-linux-x86
local rule expand-subfeatures-aux (
feature ? # The name of the feature, or empty if value corresponds to an implicit property
: value # The value of the feature.
: dont-validate ? # If set, no validation of value string will be done
)
{
if $(feature)
{
feature = $(feature) ;
}
if ! $(feature)
{
feature = [ implied-feature $(value) ] ;
}
else
{
validate-feature $(feature) ;
}
if ! $(dont-validate)
{
validate-value-string $(feature) $(value) ;
}
local components = [ regex.split $(value) "-" ] ;
# get the top-level feature's value
local value = $(components[1]:G=) ;
local result = $(components[1]:G=$(feature)) ;
local subvalues = $(components[2-]) ;
while $(subvalues)
{
local subvalue = $(subvalues[1]) ; # pop the head off of subvalues
subvalues = $(subvalues[2-]) ;
local subfeature = [ find-implied-subfeature $(feature) $(subvalue) : $(value) ] ;
# If no subfeature was found, reconstitute the value string and use that
if ! $(subfeature)
{
result = $(components:J=-) ;
result = $(result:G=$(feature)) ;
subvalues = ; # stop looping
}
else
{
local f = [ MATCH ^<(.*)>$ : $(feature) ] ;
result += $(subvalue:G=$(f)-$(subfeature)) ;
}
}
return $(result) ;
}
# Make all elements of properties corresponding to implicit features
# explicit, and express all subfeature values as separate properties
# in their own right. For example, the property
#
# gcc-2.95.2-linux-x86
#
# might expand to
#
# <toolset>gcc <toolset-version>2.95.2 <toolset-os>linux <toolset-cpu>x86
#
rule expand-subfeatures (
properties * # property set with elements of the form
# <feature>value-string or just value-string in the
# case of implicit features.
: dont-validate ?
)
{
local result ;
for local p in $(properties)
{
# Don't expand subfeatures in subfeatures
if ! [ MATCH "(:)" : $(p:G) ]
{
result += [ expand-subfeatures-aux $(p:G) : $(p:G=) : $(dont-validate) ] ;
}
else
{
result += $(p) ;
}
}
return $(result) ;
}
# Helper for extend, below. Handles the feature case.
local rule extend-feature ( feature : values * )
{
feature = [ grist $(feature) ] ;
validate-feature $(feature) ;
if implicit in $($(feature).attributes)
{
for local v in $(values)
{
if $($(v).implicit-feature)
{
error $(v) is already associated with the \"$($(v).implicit-feature)\" feature ;
}
$(v).implicit-feature = $(feature) ;
}
.all-implicit-values += $(values) ;
}
if ! $($(feature).values)
{
# This is the first value specified for this feature,
# take it as default value
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -