📄 property.jam
字号:
# Copyright (C) Vladimir Prus 2002. 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 utility : ungrist ;
import sequence : unique ;
import errors : error ;
import feature ;
import regex ;
import sequence ;
import set ;
import path ;
import assert ;
import indirect ;
# Refines 'properties' by overriding any non-free properties
# for which a different value is specified in 'requirements'.
# Conditional requirements are just added without modification.
# Returns the resulting list of properties.
rule refine ( properties * : requirements * )
{
local result ;
local error ;
# All the elements of requirements should be present in the result
# Record them so that we can handle 'properties'.
for local r in $(requirements)
{
# Don't consider conditional requirements.
if ! [ MATCH (:) : $(r:G=) ]
{
# Note: cannot use local here, so take an ugly name
__require__$(r:G) = $(r:G=) ;
}
}
for local p in $(properties)
{
# No processing for free properties
if [ MATCH (:) : $(p:G=) ]
{
# Skip conditional properties
result += $(p) ;
}
else if free in [ feature.attributes $(p:G) ]
{
result += $(p) ;
}
else
{
local required-value = $(__require__$(p:G)) ;
if $(required-value)
{
local value = $(p:G=) ;
if $(value) != $(required-value)
{
result += $(p:G)$(required-value) ;
}
else
{
result += $(p) ;
}
}
else
{
result += $(p) ;
}
}
}
# Unset our ugly map.
for local r in $(requirements)
{
__require__$(r:G) = ;
}
if $(error)
{
return $(error) ;
}
else
{
return [ unique $(result) $(requirements) ] ;
}
}
# Removes all conditional properties which conditions are not met
# For those with met conditions, removes the condition. Properies
# in conditions are looked up in 'context'
rule evaluate-conditionals-in-context ( properties * : context * )
{
local base ;
local conditionals ;
for local p in $(properties)
{
if [ MATCH (:<) : $(p) ]
{
conditionals += $(p) ;
}
else
{
base += $(p) ;
}
}
local result = $(base) ;
for local p in $(conditionals)
{
# Separate condition and property
local s = [ MATCH (.*):(<.*) : $(p) ] ;
# Split condition into individual properties
local c = [ regex.split $(s[1]) "," ] ;
# Evaluate condition
if $(c) in $(context)
{
result += $(s[2]) ;
}
}
return $(result) ;
}
rule expand-subfeatures-in-conditions ( properties * )
{
local result ;
for local p in $(properties)
{
local s = [ MATCH (.*):(<.*) : $(p) ] ;
if ! $(s)
{
result += $(p) ;
}
else
{
local condition = $(s[1]) ;
# Condition might include several elements
condition = [ regex.split $(condition) "," ] ;
local value = $(s[2]) ;
local e ;
for local c in $(condition)
{
if [ MATCH "^(<toolset>|<toolset->)" : $(c:G) ] ||
[ MATCH "^(<os>)" : $(c:G) ]
{
# It common that condition includes a toolset which
# was never defined, or mentiones subfeatures which
# were never defined. In that case, validation will
# only produce an spirious error, so don't validate.
e += [ feature.expand-subfeatures $(c) : true ] ;
}
else
{
e += [ feature.expand-subfeatures $(c) ] ;
}
}
if $(e) = $(condition)
{
result += $(p) ;
}
else
{
local individual-subfeatures = [ set.difference $(e) : $(condition) ] ;
result += $(individual-subfeatures:J=,):$(value) ;
}
}
}
return $(result) ;
}
# Helper for as-path, below. Orders properties with the implicit ones
# first, and within the two sections in alphabetical order of feature
# name.
local rule path-order ( x y )
{
if $(y:G) && ! $(x:G)
{
return true ;
}
else if $(x:G) && ! $(y:G)
{
return ;
}
else
{
if ! $(x:G)
{
x = [ feature.expand-subfeatures $(x) ] ;
y = [ feature.expand-subfeatures $(y) ] ;
}
if $(x[1]) < $(y[1])
{
return true ;
}
}
}
# Returns a path which represents the given expanded property set.
rule as-path ( properties * )
{
local entry = .result.$(properties:J=-) ;
if ! $($(entry))
{
# trim redundancy
properties = [ feature.minimize $(properties) ] ;
# sort according to path-order
properties = [ sequence.insertion-sort $(properties) : path-order ] ;
local components ;
for local p in $(properties)
{
if $(p:G)
{
local f = [ ungrist $(p:G) ] ;
components += $(f)-$(p:G=) ;
}
else
{
components += $(p) ;
}
}
$(entry) = $(components:J=/) ;
}
return $($(entry)) ;
}
# Exit with error if property is not valid.
local rule validate1 ( property )
{
local msg ;
if $(property:G)
{
local feature = $(property:G) ;
local value = $(property:G=) ;
if ! [ feature.valid $(feature) ]
{
feature = [ ungrist $(property:G) ] ; # Ungrist for better error messages
msg = "unknown feature '$(feature)'" ;
}
else if $(value) && ! free in [ feature.attributes $(feature) ]
{
feature.validate-value-string $(feature) $(value) ;
}
else if ! $(value)
{
feature = [ ungrist $(property:G) ] ; # Ungrist for better error messages
msg = "No value specified for feature '$(feature)'" ;
}
}
else
{
local feature = [ feature.implied-feature $(property) ] ;
feature.validate-value-string $(feature) $(property) ;
}
if $(msg)
{
error "Invalid property "'$(property:J=" ")'": "$(msg:J=" "). ;
}
}
rule validate ( properties * )
{
for local p in $(properties)
{
validate1 $(p) ;
}
}
rule validate-property-sets ( property-sets * )
{
for local s in $(property-sets)
{
validate [ feature.split $(s) ] ;
}
}
# Makes a property set from 'specification', converting implicit values into
# full properties.
rule make ( specification * )
{
local result ;
for local e in $(specification)
{
if $(e:G)
{
result += $(e) ;
}
else if [ feature.is-implicit-value $(e) ]
{
local feature = [ feature.implied-feature $(e) ] ;
result += $(feature)$(e) ;
}
else
{
error "'$(e)' is not a valid for property specification" ;
}
}
return $(result) ;
}
# Returns a property sets which include all the elements in 'properties' that
# do not have attributes listed in 'attributes'.
rule remove ( attributes + : properties * )
{
local result ;
for local e in $(properties)
{
if ! [ set.intersection $(attributes) : [ feature.attributes $(e:G) ] ]
{
result += $(e) ;
}
}
return $(result) ;
}
# Returns a property set which include all properties in 'properties' that have
# any of 'attributes'.
rule take ( attributes + : properties * )
{
local result ;
for local e in $(properties)
{
if [ set.intersection $(attributes) : [ feature.attributes $(e:G) ] ]
{
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -