def feature (name, values, attributes = []): """ Declares a new feature with the given name, values, and attributes. name: the feature name values: a sequence of the allowable values - may be extended later with feature.extend attributes: a sequence of the feature's attributes (e.g. implicit, free, propagated, ...) """ name = add_grist (name) __validate_feature_attributes (name, attributes) feature = { 'values': [], 'attributes': attributes, 'subfeatures': [], 'default': None } __all_features [name] = feature feature ['attributes'] = attributes for attribute in attributes: __features_with_attributes [attribute].append (name) if 'subfeature' in attributes: __all_subfeatures.append(name) else: __all_top_features.append(name) extend (name, values) # FIXME: why his is needed. if 'free' in attributes: __free_features.append (name)
def extend(name, values): """ Adds the given values to the given feature. """ assert isinstance(name, basestring) assert is_iterable_typed(values, basestring) name = add_grist(name) __validate_feature(name) feature = __all_features[name] if feature.implicit: for v in values: if v in __implicit_features: raise BaseException( "'%s' is already associated with the feature '%s'" % (v, __implicit_features[v])) __implicit_features[v] = feature if values and not feature.values and not (feature.free or feature.optional): # This is the first value specified for this feature, # take it as default value feature.set_default(values[0]) feature.add_values(values)
def feature(name, values, attributes=[]): """ Declares a new feature with the given name, values, and attributes. name: the feature name values: a sequence of the allowable values - may be extended later with feature.extend attributes: a sequence of the feature's attributes (e.g. implicit, free, propagated, ...) """ __validate_feature_attributes(name, attributes) feature = Feature(name, [], attributes) __all_features[name] = feature # Temporary measure while we have not fully moved from 'gristed strings' __all_features["<" + name + ">"] = feature for attribute in attributes: __features_with_attributes[attribute].append(name) name = add_grist(name) if 'subfeature' in attributes: __all_subfeatures.append(name) else: __all_top_features.append(feature) extend(name, values) # FIXME: why his is needed. if 'free' in attributes: __free_features.append(name) return feature
def split_top_feature(feature_plus): """ Given an ungristed string, finds the longest prefix which is a top-level feature name followed by a dash, and return a pair consisting of the parts before and after that dash. More interesting than a simple split because feature names can contain dashes. """ e = feature_plus.split('-') f = e[0] v = None while e: if add_grist(f) in __all_top_features: if len(e) > 1: after = '-'.join(e[1:]) else: after = '' v = (f, after) e = e[1:] f = f + '-' if len(e): f += e[0] return v
def feature(name, values, attributes=[]): """ Declares a new feature with the given name, values, and attributes. name: the feature name values: a sequence of the allowable values - may be extended later with feature.extend attributes: a sequence of the feature's attributes (e.g. implicit, free, propagated, ...) """ name = add_grist(name) __validate_feature_attributes(name, attributes) feature = { 'values': [], 'attributes': attributes, 'subfeatures': [], 'default': None } __all_features[name] = feature feature['attributes'] = attributes for attribute in attributes: __features_with_attributes[attribute].append(name) if 'subfeature' in attributes: __all_subfeatures.append(name) else: __all_top_features.append(name) extend(name, values) # FIXME: why his is needed. if 'free' in attributes: __free_features.append(name)
def subfeature(feature_name, value_string, subfeature, subvalues, attributes=[]): """ Declares a subfeature. feature_name: Root feature that is not a subfeature. value_string: An optional value-string specifying which feature or subfeature values this subfeature is specific to, if any. subfeature: The name of the subfeature being declared. subvalues: The allowed values of this subfeature. attributes: The attributes of the subfeature. """ feature_name = add_grist(feature_name) validate_feature(feature_name) # Add grist to the subfeature name if a value-string was supplied subfeature_name = __get_subfeature_name(subfeature, value_string) if subfeature_name in __all_features[feature_name]['subfeatures']: message = "'%s' already declared as a subfeature of '%s'" % ( subfeature, feature_name) message += " specific to '%s'" % value_string raise BaseException(message) __all_features[feature_name]['subfeatures'].append(subfeature_name) # First declare the subfeature as a feature in its own right f = ungrist(feature_name) feature(f + '-' + subfeature_name, subvalues, attributes + ['subfeature']) # Now make sure the subfeature values are known. extend_subfeature(feature_name, value_string, subfeature, subvalues)
def is_subfeature_of(parent_property, f): """ Return true iff f is an ordinary subfeature of the parent_property's feature, or if f is a subfeature of the parent_property's feature specific to the parent_property's value. """ if not valid(f) or not 'subfeature' in __all_features[f]['attributes']: return False specific_subfeature = __re_split_subfeatures.match(f) if specific_subfeature: # The feature has the form # <topfeature-topvalue:subfeature>, # e.g. <toolset-msvc:version> feature_value = split_top_feature(specific_subfeature.group(1)) if replace_grist(feature_value[1], '<' + feature_value[0] + '>') == parent_property: return True else: # The feature has the form <topfeature-subfeature>, # e.g. <toolset-version> top_sub = split_top_feature(ungrist(f)) if top_sub[1] and add_grist(top_sub[0]) == get_grist(parent_property): return True return False
def set_default (feature, value): """ Sets the default value of the given feature, overriding any previous default. feature: the name of the feature value: the default value to assign """ if isinstance(feature, list): feature = feature[0] feature = add_grist (feature) f = __all_features [feature] attributes = f['attributes'] bad_attribute = None if "free" in attributes: bad_attribute = "free" elif "optional" in attributes: bad_attribute = "optional" if bad_attribute: raise InvalidValue ("%s property %s cannot have a default" % (bad_attribute, feature)) if isinstance(value, list): value = value[0] values = f['values'] if not value in values: raise InvalidValue ("The specified default value, '%s' is invalid.\n" % value + "allowed values are: %s" % values) f ['default'] = value
def split_top_feature (feature_plus): """ Given an ungristed string, finds the longest prefix which is a top-level feature name followed by a dash, and return a pair consisting of the parts before and after that dash. More interesting than a simple split because feature names can contain dashes. """ e = feature_plus.split ('-') f = e [0] v = None while e: if add_grist (f) in __all_top_features: if len (e) > 1: after = '-'.join (e [1:]) else: after = '' v = (f, after) e = e [1:] f = f + '-' if len (e): f += e [0] return v
def subfeature (feature_name, value_string, subfeature, subvalues, attributes = []): """ Declares a subfeature. feature_name: Root feature that is not a subfeature. value_string: An optional value-string specifying which feature or subfeature values this subfeature is specific to, if any. subfeature: The name of the subfeature being declared. subvalues: The allowed values of this subfeature. attributes: The attributes of the subfeature. """ feature_name = add_grist (feature_name) validate_feature (feature_name) # Add grist to the subfeature name if a value-string was supplied subfeature_name = __get_subfeature_name (subfeature, value_string) if subfeature_name in __all_features [feature_name]['subfeatures']: message = "'%s' already declared as a subfeature of '%s'" % (subfeature, feature_name) message += " specific to '%s'" % value_string raise BaseException (message) __all_features [feature_name]['subfeatures'].append (subfeature_name) # First declare the subfeature as a feature in its own right f = ungrist (feature_name) feature (f + '-' + subfeature_name, subvalues, attributes + ['subfeature']) # Now make sure the subfeature values are known. extend_subfeature (feature_name, value_string, subfeature, subvalues)
def is_subfeature_of (parent_property, f): """ Return true iff f is an ordinary subfeature of the parent_property's feature, or if f is a subfeature of the parent_property's feature specific to the parent_property's value. """ if not valid (f) or not 'subfeature' in __all_features [f]['attributes']: return False specific_subfeature = __re_split_subfeatures.match (f) if specific_subfeature: # The feature has the form # <topfeature-topvalue:subfeature>, # e.g. <toolset-msvc:version> feature_value = split_top_feature(specific_subfeature.group(1)) if replace_grist (feature_value [1], '<' + feature_value [0] + '>') == parent_property: return True else: # The feature has the form <topfeature-subfeature>, # e.g. <toolset-version> top_sub = split_top_feature (ungrist (f)) if top_sub [1] and add_grist (top_sub [0]) == get_grist (parent_property): return True return False
def feature (name, values, attributes = []): """ Declares a new feature with the given name, values, and attributes. name: the feature name values: a sequence of the allowable values - may be extended later with feature.extend attributes: a sequence of the feature's attributes (e.g. implicit, free, propagated, ...) """ __validate_feature_attributes (name, attributes) feature = Feature(name, [], attributes) __all_features[name] = feature # Temporary measure while we have not fully moved from 'gristed strings' __all_features["<" + name + ">"] = feature for attribute in attributes: __features_with_attributes [attribute].append (name) name = add_grist(name) if 'subfeature' in attributes: __all_subfeatures.append(name) else: __all_top_features.append(feature) extend (name, values) # FIXME: why his is needed. if 'free' in attributes: __free_features.append (name) return feature
def set_default(feature, value): """ Sets the default value of the given feature, overriding any previous default. feature: the name of the feature value: the default value to assign """ if isinstance(feature, list): feature = feature[0] feature = add_grist(feature) f = __all_features[feature] attributes = f['attributes'] bad_attribute = None if "free" in attributes: bad_attribute = "free" elif "optional" in attributes: bad_attribute = "optional" if bad_attribute: raise InvalidValue("%s property %s cannot have a default" % (bad_attribute, feature)) if isinstance(value, list): value = value[0] values = f['values'] if not value in values: raise InvalidValue("The specified default value, '%s' is invalid.\n" % value + "allowed values are: %s" % values) f['default'] = value
def __find_implied_subfeature(feature, subvalue, value_string): feature = add_grist(feature) if value_string == None: value_string = '' if not __subfeature_value_to_name.has_key (feature) \ or not __subfeature_value_to_name [feature].has_key (value_string) \ or not __subfeature_value_to_name [feature][value_string].has_key (subvalue): return None return __subfeature_value_to_name[feature][value_string][subvalue]
def __find_implied_subfeature (feature, subvalue, value_string): feature = add_grist (feature) if value_string == None: value_string = '' if not __subfeature_value_to_name.has_key (feature) \ or not __subfeature_value_to_name [feature].has_key (value_string) \ or not __subfeature_value_to_name [feature][value_string].has_key (subvalue): return None return __subfeature_value_to_name[feature][value_string][subvalue]
def extend_subfeature (feature, value_string, subfeature, subvalues): feature = add_grist (feature) validate_feature (feature) if value_string: validate_value_string (feature, value_string) subfeature_name = __get_subfeature_name (subfeature, value_string) f = ungrist (feature) extend (f + '-' + subfeature_name, subvalues) ; __add_to_subfeature_value_to_name_map (feature, value_string, subfeature_name, subvalues)
def extend (name, values): """ Adds the given values to the given feature. """ name = add_grist (name) __validate_feature (name) feature = __all_features [name] if feature.implicit(): for v in values: if __implicit_features.has_key(v): raise BaseException ("'%s' is already associated with the feature '%s'" % (v, __implicit_features [v])) __implicit_features[v] = feature if len (feature.values()) == 0 and len (values) > 0: # This is the first value specified for this feature, # take it as default value feature.set_default(values[0]) feature.add_values(values)
def extend (name, values): """ Adds the given values to the given feature. """ name = add_grist (name) __validate_feature (name) feature = __all_features [name] if 'implicit' in feature ['attributes']: for v in values: if __implicit_features.has_key (v): raise BaseException ("'%s' is already associated with the feature '%s'" % (v, __implicit_features [v])) __implicit_features[v] = name if len (feature ['values']) == 0 and len (values) > 0: # This is the first value specified for this feature, # take it as default value feature ['default'] = values[0] feature['values'].extend (values)
def extend (name, values): """ Adds the given values to the given feature. """ assert isinstance(name, basestring) assert is_iterable_typed(values, basestring) name = add_grist (name) __validate_feature (name) feature = __all_features [name] if feature.implicit(): for v in values: if __implicit_features.has_key(v): raise BaseException ("'%s' is already associated with the feature '%s'" % (v, __implicit_features [v])) __implicit_features[v] = feature if values and not feature.values() and not(feature.free() or feature.optional()): # This is the first value specified for this feature, # take it as default value feature.set_default(values[0]) feature.add_values(values)