The pure::variants expression language pvSCL is a simple language to express constraints, restrictions and calculations. It provides logical and relational operators to build simple but also complex Boolean expressions.
The language is based on a simple object model. An object has an identity, attributes (data) and functions which can be applied to it. Some functions can be used without an explicit object context. Objects represent either simple data items such as numbers, or collections of objects; or in many cases they represent pure::variants model items such as elements or models.
Both full and partial configuration mode is fully supported when evaluating pvSCL expressions. See also Section 5.8.2, “ Partial Evaluation ” for details about model evaluation in these modes. In partial evaluation, calculations are done also with a special open value. So, the result of a constraint, restriction, or calculation can be also open.
The reference use the term
context
to denote the object to which an operator or function is applied to.
This term is not to be confused with the keywordscontext/CONTEXT
, which deliver a special object, see details below.
Expressions can be commented. A comment is started with a slash immediately followed by a star. The comment itself can span multiple lines. It is ended with a star immediately followed by a slash. Comments are ignored when an expression is evaluated.
/* comment text */
A /* The first character in the alphabet. */ OR Z /* The last character in the alphabet.*/
Expressions can resolve to a boolean value, i.e. TRUE or FALSE. An expression is said to fail if its boolean value is FALSE, and to succeed otherwise. Boolean values have type ps:boolean.
TRUE FALSE
NOT(TRUE = FALSE)
Numbers can either be decimal and hexadecimal integers, or floating point numbers. Hexadecimal integers are introduced by 0x or 0X followed by digits and / or characters between a and f. Floating point numbers contain a decimal point and / or positive or negative exponent.
Integers have type ps:integer, and floating point numbers have type ps:float.
100 10e2 150e-3 0xFF00 1.5 5.5E+3
Strings are sequences of characters and escape sequences enclosed in single quotation marks. The allowed characters are those of the Unicode character set. Strings have type ps:string.
Following escape sequences are supported.
Escape Sequence | Meaning |
---|---|
\n | New line |
\t | Horizontal tabulator |
\b | Backspace |
\r | Carriage return |
\f | Form feed |
\' | Single quotation mark |
\" | Quotation mark |
\\ | Backslash |
\0 - \777 | Octal character code |
\u0000 - \uffff | Unicode character code |
Strings can be concatenated with other strings and numbers using the plus operator. The result is a new string containing the source strings and numbers in the order they were concatenated.
'characters including escape sequences'
'Hello' '10\44' = '10$' '10\u20AC' = '10€' 'Line ' + 1 + '\n' + 'Line ' + 2
Collections are lists or sets of values of the same type. Lists may contain one and the same value twice, whereas sets only contain unique values. The type of lists either is ps:list or the value type followed by [], e.g. ps:string[] for a list of strings. The type of sets either is ps:set or the value type followed by {}, e.g. ps:integer{} for a set of integers.
Collection literals have list type. Their items are constructed from the values of any expressions, particularly nested collections, and must have the same type.
In partial evaluation, if the result of a calculation is a collection with at least one open member, instead of this incomplete collection only the open value will be returned.
{ expr, expr, ... }
{'spring', 'summer', 'autumn', 'winter'} {1, 2, 3}
The keywords SELF and CONTEXT are context dependent name references. The type of SELF and CONTEXT is ps:model if a model is referenced, ps:element for an element, ps:relation for a relation, ps:attribute for an attribute, and ps:constant for an attribute value.
Model Object | SELF | CONTEXT |
---|---|---|
Constraint | Element containing the constraint | Model containing the constraint |
Restriction on element | Element containing the restriction | Element containing the restriction |
Restriction on relation | Relation containing the restriction | Element containing the relation |
Restriction on attribute | Attribute containing the restriction | Element containing the attribute |
Restriction on attribute value | Attribute value containing the restriction | Element containing the attribute value |
Attribute value calculation | Attribute value being calculated | Element containing the attribute value |
SELF CONTEXT
SELF AND SELF->value = 5 CONTEXT IMPLIES SELF <> 0
Models, elements, and attributes can be referenced by their unique identifiers. Models can also be referenced by their names, and elements by their unique names, optionally prefixed by the name of the model containing the element. For a referenced model the result type is ps:model, for an element ps:element, and for an attribute ps:attribute.
Elements can be referenced across linked variants, i.e. variant collections, instances, and references, by means of a path name. Path names navigate to elements in another variant along the variant elements in a variant hierarchy. Variant elements are elements with type ps:variant representing the root element of a linked variant.
Path Name Element | Description |
---|---|
variant-name:name | Relative path name |
:name | Absolute path name |
parent:name | Parent variant navigation |
variant-collection-or-instance-name[3]:name | Anonymous variant navigation for variant collections and instances |
A name is resolved as follows.
If name or model-name equals "context", "CONTEXT", "self", or "SELF"
resolves to the context dependent name reference CONTEXT or SELF
If name is the name of a visible local variable, iterator or accumulator
resolves to the local variable, iterator or accumulator
If name is the unique name of an element
resolves to the element
If element-name is the unique name of an element in model model-name
resolves to the element
If name is the name of a model
resolves to the model
If it is an absolute path-name
resolve name without the leading : to an element or model
If it is a path-name with parent variant navigation
resolve name in the context of the parent variant of the current variant to an element
If it is a path-name with anonymous variant navigation
resolve name in the context of the specified variant to an element
Otherwise it is a relative name
resolve as full qualified name to an element or model
@id name model-name.element-name path-name
@isdkd Frontdoor Doors.Backdoor Residence:Frontdoor:Color->value = 'white' DoubleLock IMPLIES parent:parent:Manson House.Doors[1] AND House.Doors[1]:Type->number = '113a'
Elements can be referenced independently of their selection, i.e. existence, in the current variant.
To check the selection state of a given element, the meta-attribute pv:Selected can be called on that element. Depending on the configuration mode and selection state following values will be returned:
Selection state | Full evaluation | Partial evaluation |
---|---|---|
Selected | TRUE | TRUE |
Excluded | FALSE | FALSE |
Unselected | FALSE | open |
Applying Boolean operations on element references enforce an implicit conversion to the Boolean selection state. So an explicit call of pv:Selected on element references is not necessary in following use cases:
A constraint or restriction with a single element reference or a single expression resulting in an element reference
Condition of a conditional
Operand of operator
NOT
Left and right operand of operator
XOR
Left operand of operators
AND
and
OR
Right operand of operators
AND
and
OR
if left operand
resolves toFALSE
Left and right operand of operator
EQUALS
Left operand of operators
IMPLIES
,
REQUIRES
,
RECOMMENDS
,
CONFLICTS
and
DISCOURAGES
Right operand of operators
IMPLIES
,
REQUIRES
,
RECOMMENDS
,
CONFLICTS
and
DISCOURAGES
if left
operand resolves toFALSE
Black OR White IF Winter THEN Snow->pv:Selected ELSE Sunshine->pv:Selected ENDIF Diesel RECOMMENDS ParticleFilter NOT(High) IMPLIES Low
Attributes and meta-attributes can be accessed using the call
operator ->
. The left operand of the call operator is the context of the
call, the right operand the attribute or meta-attribute to call. It
is an error if there is no attribute or meta-attribute with the given
name for the context of a call.
If the context has model or element type, ordinary model and element attributes can be accessed. The result type is ps:attribute.
The value of an attribute is automatically accessed in all contexts a value is required, e.g. operand of a logical, relational, arithmetic, or comparison operator. Meta-attribute pv:Get can be used to access an attribute value explicitly. For an attribute with collection type a specific value can be accessed by specifying the index of the value as argument to the call (function call syntax).
In full configuration mode, an error is created, if the accessed attribute has no value. In partial configuration mode, instead an open value is returned.
The context types meta-attributes can be called on, depend on the implementation of a meta-attribute. Meta-attributes may accept an argument list (function call syntax). The result of calling a meta-attribute also depends on its implementation.
Since meta-attributes (built-in and user-defined) and attributes use the same calling syntax, the calling precedence of meta-attribute and attribute calls needs to be considered:
The built-in meta-attributes (see Section 9.7.23, “Function Library”) will override all attribute calls with the same name. However, it is generally not recommended to name attributes as same as built-in meta-attributes.
A user-defined function in the meta-attribute syntax (see Section 9.7.17, “Function Definitions”) will override attribute calls with the same name and the same number of arguments counted in the meta-attribute syntax. That is, a user-defined function with one argument (in the corresponding meta-attribute syntax called with zero arguments) will override an attribute call without arguments. Analogous, a user-defined function with two arguments (in the meta-attribute syntax called with one argument) will override an attribute call with index argument.
To access such hidden attributes, the meta-attribute pv:Attribute has to be used instead.
context-expr -> attr-name context-expr -> attr-name(index-expr) context-expr -> meta-attr-name context-expr -> meta-attr-name(expr, expr, ...)
product->version > 3 seasons->names = { 'spring', 'summer', 'autumn', 'winter' } seasons->names(1) = 'summer' AND seasons->names(2) = 'autumn' seasons->names->pv:Size = 4 seasons->names->pv:Get(3) = 'winter'
Expressions can be logically combined. For this purpose the expressions are evaluated to their boolean values. It is an error if this conversion is not possible. The logical operator is then applied to the boolean values resulting in TRUE or FALSE.
In partial evaluation, logical operations are applied using three-valued logic. So, Boolean open values are supported as operands. The result can then be also open.
Following logical operators are supported:
Operator | Meaning |
---|---|
AND | Binary operator that yields TRUE if both operands are TRUE. |
OR | Binary operator that yields TRUE if at least one operand is TRUE. If the first operand is TRUE then the second operand will not be evaluated. |
XOR | Binary operator that yields TRUE if exactly one operand is TRUE. |
NOT | Unary operator that yields TRUE if the operand is FALSE. |
Logical operators have a lower precedence than comparison operators but a higher precedence than relational operators.
expr AND expr expr OR expr expr XOR expr NOT(expr)
be OR NOT(be) cabriolet XOR sunroof
Expressions can be set in relation to each other. For this purpose the expressions are evaluated to their boolean values. It is an error if this conversion is not possible. The relational operator is then applied to the boolean values resulting in TRUE or FALSE.
In partial evaluation, relation operations are applied using three-valued logic. So, Boolean open values are supported as operands. The result can then be also open.
Following relational operators are supported:
Operator | Meaning |
---|---|
REQUIRES | Evaluates to TRUE, iff a) both operands evaluate to TRUE or b) the left operand evaluates to FALSE. In the latter case, the right operand will not be evaluated. |
IMPLIES | Same as REQUIRES. |
CONFLICTS | Evaluates to TRUE, iff a) the left operand evaluates to TRUE and the right operand evaluates to FALSE or b) the left operand evaluates to FALSE. In the latter case, the right operand will not be evaluated. |
RECOMMENDS | Like REQUIRES but always yields TRUE. |
DISCOURAGES | Like CONFLICTS but always yields TRUE. |
EQUALS | Evaluates to TRUE, iff either both operands evaluate to TRUE or both operands evaluate to FALSE. |
Relational operators have a lower precedence than conditionals, and logical and arithmetic operators.
expr IMPLIES expr expr REQUIRES expr expr CONFLICTS expr expr RECOMMENDS expr expr DISCOURAGES expr expr EQUALS expr
car REQUIRES wheels legs->number = 4 CONFLICTS human
Conditionals allow to evaluate alternative expressions depending on the boolean value of a condition. If boolean-condition-expr evaluates to TRUE, expression consequence-expr is evaluated to determine the result of the conditional expression. If the condition evaluates to FALSE, expressionalternative-expr is evaluated instead. In partial evaluation, if the condition is open, both consequence-expr and alternative-expr are evaluated. If both result values are equal, that equal value with be the result of the conditional. Otherwise the result is an open value. It is an error ifboolean-condition-expr cannot be evaluated to a Boolean value.
Conditionals can occur everywhere where expressions are allowed. This means in particular that conditionals can be nested. Conditionals have a higher precedence than relational, logical, arithmetic and compare operators.
IF condition-expr THEN consequence-expr ELSE alternative-expr ENDIF
IF summer THEN weather->temperature >= 25 ELSE IF winter THEN weather->temperature <= 5 ELSE weather->temperature > 5 AND weather->temperature < 25 ENDIF ENDIF
Expressions can be compared based on their values. For this purpose the expressions are evaluated to their values first, and then the comparison operator is applied to the values resulting in TRUE or FALSE. In partial evaluation, if one if the operands is open, the result of the comparison will be also open.
Beginning with pure::variants 5.0.0, in general values of different base types are not comparable. A comparison of such value combinations will create an error. Exceptions are a) the number types (ps:float and ps:integer are comparable) and b) versions (type ps:version), which also can be compared with strings (type ps:string).
Two numbers are compared based on their numeric values, two strings lexically, two collections item by item, two booleans by their boolean values, and model and element references by their ID.
Following comparison operators are supported:
Operator | Meaning |
---|---|
= | Yields TRUE if both operands have the same value. |
<> | Yields TRUE if the operands have different values. |
> | Yields TRUE if the left operand's value is greater than the right operand's value. |
< | Yields TRUE if the left operand's value is less than the right operand's value. |
>= | Yields TRUE if the left operand's value is greater than or equals the right operand's value. |
<= | Yields TRUE if the left operand's value is less than or equals the right operand's value. |
The types ps:boolean, ps:element, and ps:model do not have a natural order. Thus, beginning with pure::variants 5.0.0 any order comparison of such values will create an error.
Comparison operators have a lower precedence than arithmetic operators but a higher precedence than logical operators.
expr = expr expr <> expr expr > expr expr < expr expr >= expr expr <= expr
Numbers can be negated, added, subtracted, multiplied, and divided. If at least one operand of an arithmetic operation has floating point type, the result also will have floating point type. Division by zero and floating point overflows create errors.
In partial evaluation, if one of the operands is open, the result will usually also be open. Exceptions are: Multiplication of open by zero and division of zero by open results both in zero.
Arithmetic operators have a higher precedence than comparison operators and a lower precedence than conditionals. Addition and subtraction have a lower precedence than multiplication and division. That means, 2*3+3*2 is calculated as (2*3)+(3*2)=6 instead of ((2*3)+3)*2=18.
expr + expr expr - expr expr * expr expr / expr -expr
5 * 5 + 2 * 5 * 6 + 6 * 6 = 121 -(8 * 10) + (10 * 8) = 0 -0xFF / 5 = -51 -5->pv:Abs() = -5 (-5)->pv:Abs() = 5
The LET keyword declares at least one variable with name var-name and initializes it with the value of expression init-expr. The variable is visible only in the expression following keyword IN, and in theinit-expr of subsequent variable declarators.
Variable declarations can occur everywhere expressions are allowed. To avoid name conflicts it is recommended to use own namespaces for the variable names (e.g. my:var-name instead of var-name).
The result of a variable declaration is the value of the expression following keyword IN.
LET var-name = init-expr, var-name = init-expr, ... IN expr
LET doors = car->frontDoors + car->rearDoors, cabrio = (doors = 2), limousine = (doors = 4) IN cabrio OR limousine
The DEF keyword defines a function with name fct-name and the given parameter list (see syntax below). Multiple functions with the same name can be defined, if they have different numbers of parameters. Defining multiple functions with the same name and same number of arguments are not allowed (one-definition rule (ODR)). Using the same function name as for built-in functions is also not allowed. The parameters of the definition are only accessible in the function body (fct-body-expr). The result of calling such a function is the value of the fct-body-expr calculated for the given argument list.
Since pure::variants 5.0.0, such functions can also be called using meta-attribute syntax if they have at least one parameter. In this case, the context on which the function is called is assigned to the first parameter of the function. The arguments of the function call are assigned to the remaining parameters of the function.
Function definitions are only allowed at the beginning of a pvSCL expression. pvSCL expressions which contain only function definitions evaluate to TRUE. To avoid name conflicts, it is recommended to use own name spaces for the function and parameter names (e.g. my:fct-name instead of fct-name, and my:param-name instead of param-name). To avoid future name conflicts it is recommended not to use the pv name space for function names.
If not defined in a pvSCL code library, such a function is visible only in the constraint, restriction or calculation containing the function definition.
DEF fct-name(param-name,param-name,...) = fct-body-expr ; DEF fct-name(param-name,param-name,...) = fct-body-expr ; ... expr
DEF plus(x,y) = x + y; plus(plus(plus(1,2),3),4) = 10 // function syntax AND 1->plus(2)->plus(3)->plus(4) = 10 // meta-attribute syntax
A function call executes the built-in or user-defined function fct-name with the given argument list and returns the value calculated by the function. It is an error if the function does not exist.
Since pure::variants 5.0.0, functions can also be called using meta-attribute syntax if they have at least one parameter. In this case, the context on which the function is called is assigned to the first parameter of the function. The arguments of the function call are assigned to the remaining parameters of the function.
fct-name(expr1, expr2, ...) // function syntax is equivalent to expr1->fct-name(expr2, ...) // meta-attribute syntax
average(accounts,'income') > average(accounts,'outgoings') // function syntax accounts->average('income') > accounts->average('outgoings') // meta-attribute syntax
Iterators are special functions able to iterate collections. For each collection item expression expr is evaluated. The current collection item is accessible in the expression using iterator variableiter-name, which is visible there only. The value of an iterator function call depends on the implementation of that function.
fct-name(iter-name | expr)
accounts->pv:Children()-> pv:ForAll(account | account->balanced = TRUE)
Accumulators are special functions able to iterate collections. For each collection item expression expr is evaluated and its value is assigned to the accumulator variable acc-name. The initial value of accumulator variable acc-name is the value of expression acc-init-expr. The current collection item is accessible in the expression using iterator variableiter-name. Both variables, iter-name and acc-name, are visible in expression expr only.
The value of an accumulator function call is the final value of the accumulator variable.
fct-name(iter-name; acc-name = acc-init-expr | expr)
accounts->pv:Children()-> pv:Iterate(account; sum = 0 | sum + account->deposit) > 0
During evaluation of pvSCL expressions, using wrong syntax, wrong input types or invalid values will create evaluation errors and the evaluation of that expression is canceled. In partial evaluation, the usage of open values can hide such errors. An example is getting an item of a collection by using function pv:Item(n), when n is open. If n evaluates to a concrete number in future configurations, the function will return either the nth item or cancels with an index-out-of-range error. Since it cannot be known beforehand, the partial evaluation returns not only open, but also sets a potential-error flag for the evaluation of that pvSCL expression. Even if the evaluation of the complete expression results in a constant value, like in
collection->pv:Item(Feature->openattr) = 2 OR SelectedFeature
which will return either TRUE or create an error, the partial evaluation will always return open if that potential-error flag is set.
Errors, warnings, and information markers can also be created using functions pv:Fail, pv:Warn, and pv:Inform, respectively. Usually they are applied in expressions like
condition OR pv:Fail('Error: Condition is not fulfilled.')
So if condition evaluates to FALSE, the right operand of OR, pv:Fail, is executed and an error marker is created. If the condition evaluates to TRUE, the shortcut applies and pv:Fail is not executed. However, if in partial evaluation condition evaluates to open, the right operand of OR also needs to be executed. So the execution of pv:Fail actually needs to create an error marker, although it is not clear, if the condition is fulfilled or not. To avoid this, operand expressions, which needs to be only executed because a shortcut could not be applied because of an open operand, will be executed in a special mode, where pv:Fail, pv:Warn, and pv:Inform will not create any markers.
The depth of the syntax tree of the parsed pvSCL expression is limited to 512 levels by default. If a pvSCL expression exceeds this limit, a parsing error will be created and the expression will not be processed further.
An example for pvSCL expressions, which could raise this limit, are sequences of operations of a large number of operands without parentheses like
Feature_1 OR Feature_2 OR ... OR Feature_520
Usually grouping the operations by parentheses will reduce the number of syntax tree levels of these kind of pvSCL expressions. Another example are deep nested expressions like
IF Feature_1 THEN .. ELSE IF Feature_2 THEN .. ... ELSE IF Feature_520 THEN .. ELSE .. ENDIF ... ENDIF
The default limit can be overridden by setting the environment variable PV_PVSCL_MAX_AST_LEVELS to a numeric value greater than zero, interpreted as the new number of maximum levels. The value of this variable will be considered by the pure::variants Desktop Client, the pure::variants Web Client and all pure::variants integrations. It will also be considered by the pure::variants Model Server, if the variable is set during the launch of the server process.
Increasing the limit above the default limit can lead to stack overflows and crashes of the pure::variants Desktop Client, the pure::variants Web Client, the pure::variants integrations, and the pure::variants Model Server. So the changing of the limit should only be done if it is really needed and is subject to the user's own risk.
The depth of recursive operation calls of an executed pvSCL expression is limited to 512 operations by default. Usually, pvSCL expressions with recursive function calls can exceed this limit. Example:
DEF sum(x) = IF x = 0 THEN 0 ELSE sum(x-1) + x ENDIF; sum(1000)
In that example, the execution will be canceled and the error “pvSCL call depth limit of limit operations reached. It may be an endless recursion.” will be created.
In partial evaluation, the limit can also be reached because of an endless recursion created by an open termination condition. Example:
DEF sum(x) = IF x = 0 THEN 0 ELSE sum(x-1) + x ENDIF; sum(Feature->openAttr)
Because of the open condition x = 0, this results in an endless recursion of calls of the function sum with open argument x. If the operation depth limit is reached, the recursion is canceled and the result of the function will be an open value.
The default limit can be overridden by setting the environment variable or Java system property PV_PVSCL_MAX_OP_CALL_DEPTH to a numeric value greater than zero, interpreted as the new number of maximum operations. The value of this variable will be considered by the pure::variants Desktop Client, the pure::variants Web Client and all pure::variants integrations.
Increasing the limit above the default limit can lead to stack overflows and crashes of the pure::variants Desktop Client, the pure::variants Web Client and all pure::variants integrations. This can be prevented by also increasing the thread stack size of the Java VM (e.g. by setting the JVM argument -Xss). The changing of the limit should only be done if it is really needed and is subject to the user's own risk.
In partial evaluation all functions can process open values as context and as each of their arguments. Depending on the functionality the return value can be also open.
Get the absolute value of the context which must be a number.
10->pv:Abs() = 10 (-10)->pv:Abs() = 10 (-2.5)->pv:Abs() = 2.5
Return the trigonometric arc cosine of the context number. The result value has type ps:float. This function must only be called on numbers between -1 and 1.
0->pv:Acos() = 1.5707963267948966 0.2->pv:Acos() = 1.369438406004566 1->pv:Acos() = 0.0 (-1)->pv:Acos() = 3.141592653589793
Append the value of expr to the context which must be a collection. It is an error if the type of the value is not compatible to the item type of the collection. If the context collection is a set, then the item only is appended if not already contained in the set.
{}->pv:Append(1) = {1} {1,2,3}->pv:Append(2) = {1,2,3,2} {1,2,3}->pv:AsSet()->pv:Append(2) = {1,2,3}->pv:AsSet()
Append all elements of the argument collection to the context collection. It is an error if the types of both collection don't match. If the context collection is a set, then only items from the argument collection are appended if not already contained in the set.
{}->pv:AppendAll({1,2,3}) = {1,2,3} {1,2,3}->pv:AppendAll({1,3,5}) = {1,2,3,1,3,5} {1,2,3}->pv:AsSet()->pv:AppendAll({1,3,5}) = {1,2,3,5}->pv:AsSet()
Return the trigonometric arc sine of the context number. The result value has type ps:float. This function must only be called on numbers between -1 and 1.
0->pv:Asin() = 0 0.2->pv:Asin() = 0.2013579207903308 1->pv:Asin() = 1.5707963267948966 (-1)->pv:Asin() = -1.5707963267948966
Convert the context to a list. It is an error if the context does not have collection type.
{1,1,2,3}->pv:AsList() = {1,1,2,3}
Convert the context to a set. It is an error if the context does not have collection type. If the context has list type, all duplicate items of the list are removed.
{1,1,2,3}->pv:AsSet() = {1,2,3}
Return the trigonometric arc tangent of the context number. The result value has type ps:float.
0->pv:Atan() = 0 0.2->pv:Atan() = 0.19739555984988078 100->pv:Atan() = 1.5607966601082315 (-100)->pv:Atan() = -1.5607966601082315
Get the attribute with the given non-empty name. Calling this function with an empty name creates an error. Fails if the context does neither have model nor element type, or no attribute with the name exists.
self->pv:Attribute('speed') = 100
Get all attributes of the context, optionally with the non-empty (exact) type. Calling this function with an empty type creates an error. Fails if the context does neither have model nor element type, or if no attribute (with given type) exists.
self->pv:Attributes('ps:integer')
Get the characters of the context string as list.
'Text'->pv:Characters() = {'T','e','x','t'}
Get the child of the context with the given index. Fails if the context does neither have model, element, nor attribute type, or the index is invalid. The child of a model is an element, of an element an element, and of an attribute an attribute value.
self->pv:Child(0)->pv:Selected()
Get the direct children of the context which must be either a model, element, or attribute. Fails otherwise. The children of a model is a list containing the root element of the model, of an element its child elements, and of an attribute its attribute values.
alternatives->pv:Children()->pv:Size() > alternatives->pv:SubTree(false)->pv:Select(e|e->pv:Selected())->pv:Size()
Get the class of the context, as ps:string, which must be a configuration space, model, element, relation, attribute, or attribute value. Fails otherwise. The class of a configuration space is ps:configspace, of a model ps:model, of an element the element class, of a relation the relation class, of an attributeps:attribute, and of an attribute value the type of the attribute value.
context->pv:Class() = 'ps:model' IMPLIES self->pv:Class() = 'ps:element'
Iterate the context collection and evaluate the iterator expression for each element of the collection. Return a new collection with all the evaluation results. The return type is ps:list.
products->pv:Children()-> pv:Collect(p | IF p->stocked THEN 1 ELSE 0 ENDIF)-> pv:Sum() > 50
Check whether the evaluation result of expression expr is contained in the context, which must be a collection.
{1,2,3}->pv:Contains(3) = true
Check whether each value of collection is contained in the context, which must be a collection.
{1,2,3}->pv:ContainsAll({1,2}) = true
Return the trigonometric cosine of the context number. The result value has type ps:float.
0->pv:Cos() = 1 0.2->pv:Cos() = 0.9800665778412416 100->pv:Cos() = 0.8623188722876839 (-100)->pv:Cos() = 0.8623188722876839
Returns the date of the given date time value. If the date time is timezoned, the date in GMT time zone is returned. The result type is ps:date. If the given date time value is timezoned, the resulting date is also timezoned.
pv:EvaluationDateTime()->pv:Date()->pv:ToString() '2020-02-28T10:24:42'->pv:ToDateTime()->pv:Date()->pv:ToString() = '2020-02-28' '2020-02-28T10:24:42+01:00'->pv:ToDateTime()->pv:Date()->pv:ToString() = '2020-02-28Z'
Check if the context element is selected by default. Fails if the context does not have element type.
radio->pv:DefaultSelected() AND speakers->number = 2
Get the element with the given non-empty unique name or identifier. Calling the function with an empty unique name or identifier creates an error. If called on a model, only elements in that model will be considered. It is an error if the element does not exist or the function is called on anything else than a model.
Model->pv:Element('winter')->pv:Selected() = true
Returns the date and time when the current evaluation has started. The result type is ps:datetime.
pv:EvaluationDateTime()->pv:ToString()
Returns true if the current evaluation is executed in partial configuration mode. Returns false if the current evaluation is executed in full configuration mode. The result type is ps:boolean.
IF pv:EvaluationIsPartial() THEN 'fixed' ELSE 'open' ENDIF
If the given element is not excluded in a full configuration or selected in a partial configuration, a warning or error message will be created. The severity of the message will be defined by the Boolean force argument: If the force argument is missing or TRUE, an error message will be created. If the force argument is FALSE, only a warning message is created. This function will always return TRUE. If activated, the auto resolver will try to resolve warning and error messages created by this function by excluding the given element if possible.
product->price < 100 IMPLIES pv:ExclusionHint('Because of the low price, feature \'luxury\' could be excluded.', luxury, false)
Return the Euler's number e raised to the power of the context number (exponent). The result value has type ps:float.
1->pv:Exp() = 2.718281828459045 (-1.2)->pv:Exp() = 0.30119421191220214
Show an error message at the context element or the given element. Always returns TRUE. Lets the model evaluation fail.
doors->number = 2 OR doors->number = 4 OR pv:Fail('Invalid number of doors [' + doors->number + ']', doors)
Flatten the context, which has to be a collection.
LET list1 = {1,2,3,4}, list2 = {{0},list1,{5}} IN list2->pv:Flatten()->pv:ToString()
Get the largest integer value not greater than the context number (round downwards towards negative infinity). Fails if the context does not have number type. The return type is ps:integer.
3.1->pv:Floor() = 3 3.5->pv:Floor() = 3 3.9->pv:Floor() = 3 (-3.1)->pv:Floor() = -4 (-3.5)->pv:Floor() = -4 (-3.9)->pv:Floor() = -4
Iterate the context collection and evaluate the iterator expression for all items. Return FALSE if at least for one item the expression evaluates to FALSE, otherwise return TRUE.
bugs->pv:Children()-> pv:ForAll(bug | bug->state = 'fixed')
Iterate the context collection and evaluate the iterator expression for all items. Return TRUE if at least for one item the expression evaluates to TRUE, otherwise return FALSE.
bugs->pv:Children()-> pv:ForAny(bug | bug->state <> 'fixed')
Return a formatted string representation of the context number. Fails if the context does not have number type. The return type is ps:string.
The argument is a C-printf-like format specifier string. The supported strings are shown in Table 9.7, “Supported format specifiers”. The output is not localized.
Table 9.7. Supported format specifiers
Context number type | Format specifier | Meaning |
---|---|---|
ps:integer | %d | Decimal integer |
ps:integer | %x | Hexadecimal integer with lower-case letters |
ps:integer | %X | Hexadecimal integer with upper-case letters |
ps:integer | %o | Octal integer |
ps:float | %e | Scientific (exponential) notation with six digits after the decimal point. Uses a lower-case letter 'e' as the exponent symbol. |
ps:float | %.ne | Scientific (exponential) notation with n digits after the decimal point. Uses a lower-case letter 'e' as the exponent symbol. |
ps:float | %E | Same as %e, but with upper-case letter 'E' |
ps:float | %.nE | Same as %.ne, but with upper-case letter 'E' |
ps:float | %f | Decimal (non-exponential) notation with six digits after the decimal point. |
ps:float | %.nf | Decimal (non-exponential) notation with n digits after the decimal point. |
Due to limited precision of ps:float values (they are internally represented in double-precision floating-point format), each ps:float value can be represented by at most 17 significant decimal digits. So, formatting a ps:float value with more digits would pretend a higher precision in the output compared to the input. Additionally, the exact formatted output in this excessive precision range depends on the runtime libraries of the used operation system. So, the resulting string can be different across operation systems. In result, it is recommended to use the format specifiers %.ne and %.nf only with n <= 16 and n <= 17-i respectively, where i is the number of significant digits before the decimal point in non-exponential notation.
51966->pv:Format('%x') = 'cafe' 3.14159265->pv:Format('%f') = '3.141593' 3.14159265->pv:Format('%f') = '3.141593' 6.62607015e-34->pv:Format('%e') = '6.626070e-34' 6.62607015e-34->pv:Format('%.0e') = '7e-34'
Get the value of an attribute if the context is an attribute or attribute value, or return the input value. If an index is given and the context is an attribute, return the attribute value at that index, or fail if the index is invalid.
seasons->order->pv:Get(2) = 'autumn'
Returns TRUE if the attribute with the given non-empty name exists on the context model or element, FALSE otherwise. Calling this function with an empty name creates an error. Fails if the context does not have model or element type.
self->pv:HasAttribute('speed') = true
Returns TRUE if the element with the given non-empty name or identifier exists, FALSE otherwise. Calling this function with an empty name or identifier creates an error. If called on a model, only elements in that model will be considered. It is an error if the function is called on anything else than a model.
Model->pv:HasElement('seasons') = true
Returns TRUE if the model with the given non-empty name or identifier exists, FALSE otherwise. Calling this function with an empty name or identifier creates an error.
pv:HasModel('Weather') = true
Get the unique identifier of the context, as ps:string, which must be a model, element, attribute, constant, or relation, or fails otherwise.
context->pv:ID() <> ''
Return the index (starting at 0) of the first occurrence of the given non-empty sub-string or collection item within the context, or -1 if the given item was not found. Calling this function on a string with an empty string argument creates an error. It is also an error if the context does not have string or collection type. The resulting index has type ps:integer.
'Hello World'->pv:IndexOf('World') = 6 {1,2,3}->pv:IndexOf(2) = 1 {1,2,3}->pv:IndexOf(4) = -1
Show an informational message at the context element or the given element. Always returns TRUE.
sportedition AND NOT(rearspoiler) RECOMMENDS pv:Inform('Rear spoiler recommended for sport edition', rearspoiler)
Insert the given item into the context collection before the item at the given index. It is an error if the type of the item is not compatible to the item type of the context collection. Using this function with index 0 is the same as calling pv:Prepend(item) on the collection. And using this function with the size of the context collection as index is the same as calling pv:Append(item) on the collection. If the context collection is a set, then the item is only inserted at the given index if not already contained in the set.
{}->pv:Insert(0,4) = {4} {1,2,3}->pv:Insert(3,4) = {1,2,3,4} {1,2,3}->pv:Insert(0,4) = {4,1,2,3} {1,2,3}->pv:Insert(1,4) = {1,4,2,3} {1,2,3}->pv:AsSet()->pv:Insert(0,3) = {1,2,3}->pv:AsSet() {1,2,3}->pv:AsSet()->pv:Insert(0,4) = {4,1,2,3}->pv:AsSet()
Insert the given items into the context collection before the item at the given index. It is an error if the type of the argument collection is not compatible to the type of the context collection. Using this function with index 0 is the same as calling pv:PrependAll(collection) on the collection. And using this function with the size of the context collection as index is the same as calling pv:AppendAll(collection) on the collection. If the context collection is a set, then only items from the argument collection are inserted at the given index if not already contained in the set.
{}->pv:InsertAll(0,{1,2}) = {1,2} {1,2,3}->pv:InsertAll(3,{4,5}) = {1,2,3,4,5} {1,2,3}->pv:InsertAll(0,{-1,0}) = {-1,0,1,2,3} {1,2,3}->pv:InsertAll(1,{1,1,2}) = {1,1,1,2,2,3} {1,2,3}->pv:AsSet()->pv:InsertAll(3,{1,2,3,4,5}) = {1,2,3,4,5}->pv:AsSet()
Return TRUE if the context is a container, i.e. a collection like list or set.
self->pv:IsContainer() RECOMMENDS self->pv:Size() > 1
Return TRUE if the context attribute has a fixed value. Fails if the context does not have attribute type.
self->pv:IsFixed() = TRUE
Return TRUE if the context attribute is inheritable. Fails if the context does not have attribute type.
self->pv:IsInheritable() = FALSE
Returns TRUE if the type of the context object is the same as the non-empty type given as argument, or a type derived from it. Calling this function with an empty type creates an error.
The type of the context object needs to be defined in a type model. Otherwise it will always return FALSE.
seasons->pv:IsKindOf('ps:feature') = TRUE
Get the item with the given index (starting at 0) of the context collection or the character with the given index of a string. Fail if the context does not have collection or string type, or the index is invalid.
seasons->pv:Children()-> pv:Item(0)->pv:Name() = 'spring'
Iterate the context collection and return the value accumulated by evaluating the iterator expression for each element of the collection. The return type is that of the accumulated value.
pv:Inform('Current price is ' + products->pv:SubTree(false)->pv:Select(e|e->pv:Selected())-> pv:Iterate(product; price = 0 | price + product->price) + '$')
Return the index (starting at 0) of the last occurrence of the given non-empty sub-string or collection item within the context, or -1 if the given item was not found. Calling this function on a string with an empty string argument creates an error. It is also an error if the context does not have string or collection type. The resulting index has type ps:integer.
'Hello World, Hello World'->pv:IndexOf('World') = 19 {1,2,3,2}->pv:IndexOf(2) = 3 {1,2,3,2}->pv:IndexOf(4) = -1
Return the natural logarithm (base e) of the context number. The result value has type ps:float. This function must not be called on zero and negative numbers.
1->pv:Log() = 0 0.2->pv:Log() = -1.6094379124341003
Return the common logarithm (base 10) of the context number. The result value has type ps:float. This function must not be called on zero and negative numbers.
100->pv:Log10() = 2 0.2->pv:Log10() = -0.6989700043360187
If called on a number collection and no arguments, it returns the greatest number of the collection. If called on a single number and one number argument (both either ps:integer or ps:float), it returns the greater of the context number and the argument number. The return type is ps:integer or ps:float depending on the type of the context. The result for an empty collection is 0.
{1,2,3,4}->pv:Max() = 4 2->pv:Max(4) = 4
If called on a number collection and no arguments, it returns the smallest number of the collection. If called on a single number and one number argument (both either ps:integer or ps:float), it returns the smaller of the context number and the argument number. The return type is ps:integer or ps:float depending on the type of the context. The result for an empty collection is 0.
{1,2,3,4}->pv:Min() = 1 2->pv:Min(4) = 2
Return the remainder of the devision of the context integer number (dividend) with the argument integer number (divisor, modulo operation). The return type is ps:integer. If the dividend is a negative number, then the remainder also is negative. The divisor must not be zero. A negative divisor is treated as if it were positive.
5->pv:Mod(3) = 2 5->pv:Mod(-3) = 2 (-5)->pv:Mod(3) = -2 (-5)->pv:Mod(-3) = -2
Get the model, as ps:model, containing the context element, or the model with the given non-empty name or identifier if not called on an element. It is an error if the function is called on anything else than an element or configuration space, or if it is called with an empty model name or identifier.
NOT(context->pv:Model()->pv:RootElement()) IMPLIES pv:Fail('Root element of model ' + context->pv:Model()->pv:Name() + ' must be selected')
Get all models of a configuration space as ps:model[] collection. Optionally accepts a non-empty model type as argument to get only the models of a specific type. The parameter type is of ps:string type. See Table 5.1, “Mapping between input and concrete model types” for the list of applicable type names. Calling the function with an empty model type string creates an error. If applied on an object, call fails if the object is not of configuration space type ('ps:configspace').
pv:Models('ps:fm')->pv:Size() > 1 /* applicable everywhere, number of feature models more than 1 */ context->pv:Parent()->pv:Models()->pv:Size() > 1 /* this form only in constraints*/ /* context of constraint is a model, parent is config space */
Get the name of the context, as ps:string, which must be a model, element, or attribute, or fail otherwise.
self->pv:SelectionState() = 'ps:nonselectable' IMPLIES pv:Warn('Feature ' + self->pv:Name() + ' is now non-selectable!')
Get the parent of the context, or fail if the context is not a model, element, relation, attribute, or attribute value. The parent of a model is the corresponding configuration space, of an element its parent element, or the corresponding model if it is the root element, of a relation the element on which the relation is defined, of an attribute the element on which the attribute is defined, and of an attribute value the attribute containing the value.
summer->pv:Parent()->pv:Name() = 'seasons'
Return the value of the context number (base) raised to the power of the argument number (exponent). If both, the base and the exponent, are integers, then the result value has type ps:integer. Otherwise the result value has type ps:float. If the base is negative, then the exponent has to be an integer.
2->pv:Pow(8) = 256 3.14->pv:Pow(2) = 9.8596
Prepend the value of expr to the context which must be a collection. It is an error if the type of the value is not compatible to the item type of the collection.
{}->pv:Prepend(1) = {1} {1,2,3}->pv:Prepend(2) = {2,1,2,3} {1,2,3}->pv:AsSet()->pv:Prepend(2) = {1,2,3}->pv:AsSet()
Prepend the values of collection to the context, which must be a collection. It is an error if the types of collections are not compatible.
{}->pv:PrependAll({1,2,3}) = {1,2,3} {1,2,3}->pv:PrependAll({1,3,5}) = {1,3,5,1,2,3} {1,2,3}->pv:AsSet()->pv:PrependAll({1,3,5}) = {5,1,2,3}->pv:AsSet()
Get the current version of pure::variants as ps:version. The result contains the complete version string, e.g. '4.0.7.685'. To check against specific versions, comparison operators can be used.
pv:PVVersion() >= '4.0.7.*' /* at least version 4.0.7 */ pv:PVVersion() = '4.0.*' /* any service release of the 4.0 branch */ pv:PVVersion() < '4.*' /* any release before version 4.x */
Get the relations of class ps:dependencies defined on the context element, as ps:relation[]. Optionally accepts a non-empty relation type as argument to get only relations of the given type. Calling this function with an empty relation type creates an error. Fails if the context does not have element type.
specialedition->pv:Relations('my:extras')-> pv:ForAll(r | re->pv:Targets()->pv:Size() <> 0)
If called with an item as the single argument, then a new collection is returned containing all the items from the context collection except of the given item. If called with an index range instead, then the resulting collection contains all the items from the context collection except the items with index begin up to index end-1.
{'a','b','c','b','a'}->pv:Remove('b') = {'a','c','a'} {'a','b','c','b','a'}->pv:Remove(0,2) = {'c','b','a'} {'a','b','c','b','a'}->pv:Remove(3,5) = {'a','b','c'}
If the context, which must be a collection, contains an element from the given collection, this element is removed from the context.
{1,2,3,2,1}->pv:RemoveAll({1,3}) = {2,2}
If an element of the given collection is not contained in the context, which has to be a collection, it will be removed from the context.
{1,2,3,2,1}->pv:RetainAll({2,3}) = {2,3,2}
Get the root element of the context model, as ps:element. Fails if the context does not have model type.
context->pv:RootElement()->pv:Selected() = TRUE
Get the integer value nearest to the context number. Positive context numbers are rounded up towards positive infinity if the fractional part is equal to or greater than 0.5, and rounded downwards towards negative infinity otherwise. Negative context numbers are rounded downwards towards negative infinity if the fractional part is equal to or greater than 0.5, and rounded up towards positive infinity otherwise. Fails if the context does not have number type. The return type is ps:integer.
3.1->pv:Round() = 3 3.5->pv:Round() = 4 3.9->pv:Round() = 4 (-3.1)->pv:Round() = -3 (-3.5)->pv:Round() = -4 (-3.9)->pv:Round() = -4
Iterate the context collection and add all the collection items to the result list for which the iterator expression evaluates to TRUE. The return type is the type of the context collection.
customers-> pv:Select(customer | customer->balanced = FALSE)-> pv:ForAll(customer | pv:Inform('Send customer ' + customer->id + ' a reminder'))
Return TRUE if the context element or attribute exists in the variant, FALSE otherwise. Fails if the context does not have element or attribute type.
self EQUALS self->pv:Selected()
If the given element is not selected in a full configuration or excluded in a partial configuration, a warning or error message will be created. The severity of the message will be defined by the Boolean force argument: If the force argument is missing or TRUE, an error message will be created. If the force argument is FALSE, only a warning message is created. This function will always return TRUE. If activated, the auto resolver will try to resolve warning and error messages created by this function by selecting the given element if possible.
product->price > 1000 IMPLIES pv:SelectionHint('Because of the high price, feature \'luxury\' could be selected.', luxury, false)
Get the selection state of the context element, as ps:string. Fails if the context does not have element type. The selection state is one ofps:selected, ps:excluded, ps:unselected, or ps:nonselectable.
airbags->pv:SelectionState() = 'ps:excluded' REQUIRES speed->max < 30
Get the selector of the context element, as ps:string. Fails if the context does not have element type. The selector is ps:user for user selections, ps:auto for all other selections, or none for elements that neither are explicitly or automatically selected nor excluded.
self IMPLIES self->pv:Selector() = 'ps:user' OR pv:Inform('Feature ' + self->pv:Name() + ' was added automatically')
Generate the finite sequence of all integers, beginning with integer begin and increased by integer increment each, which are less than (so excluding) integer end. If the function signatures without begin and increment are called, the values 0 and 1 are used, respectively. The resulting type is integer[] An increment of 0 (zero) is not allowed and creates an error. This function can be used as input of collection iteration functions to iterate across more than one collection at a time.
pv:Sequence(3) = {0, 1, 2} pv:Sequence(1,5) = {1, 2, 3, 4} pv:Sequence(0,10,2) = {0, 2, 4, 8} LET list1 = {'A','B','C'}, list2 = {'1','2','3'} IN pv:Sequence(list1->pv:Size())-> pv:Collect(i | list1->pv:Item(i) + list2->pv:Item(i)) = {'A1','B2','B3'}
Return the trigonometric sine of the context number. The result value has type ps:float.
0->pv:Sin() = 0 0.2->pv:Sin() = 0.19866933079506122 100->pv:Sin() = -0.5063656411097588 (-100)->pv:Sin() = 0.5063656411097588
Get the number of attribute values for attribute types, collection items for collection types, or characters for string types as ps:integer. For any other context type, 1 is returned.
seasons->pv:Children()->pv:Size() = 4 AND seasons->pv:SubTree(false)->pv:Select(e|e->pv:Selected())->pv:Size() = 1
Sort the items of the context collection in ascending order. Numbers are sorted by value and precede strings. Strings are sorted alphabetically where upper-case characters precede lower-case characters. Collections are sorted by their elements.
{1,3,2}->pv:Sort() = {1,2,3} {'c','C','b'}->pv:Sort() = {'C','b','c'} {1.6,-1.0,0.3}->pv:Sort() = {-1.0,0.3,1.6} { {3,1}, {1,3}, {2,1}, {1,2} }->pv:Sort() = { {1,2}, {1,3}, {2,1}, {3,1} } { {{3,1},{1,3}}, {{2,1},{1,2}} }->pv:Sort() = { {{2,1},{1,2}}, {{3,1},{1,3}} }
Return the square root of the context number. The result value has type ps:float. This function must not be called on negative numbers.
9->pv:Sqrt() = 3 1.2->pv:Sqrt() = 1.0954451150103321
Splits the context string around occurrences of the string delimiter in the context string and returns the result value as list of string (ps:string[]). It is an error if the context or delimiter does not have string type and if the delimiter is an empty string.
'Hello World'->pv:StringSplit(' ') = {'Hello','World'}
Replace the first occurrence of the string search in the context string with the string replace and return the result. It is an error if context, search, or replace does not have string type and if the search string is an empty string.
'Hello World, Hello World'->pv:StringReplace('World','All') = 'Hello All, Hello World'
Replace all occurrences of the string search in the context string with the string replace and return the result. It is an error if context, search, or replace does not have string type and if the search string is an empty string.
'Hello World, Hello World'->pv:StringReplace('World','All') = 'Hello All, Hello All'
Return a new collection that is a sub-collection of the context collection. The sub-collection begins at the specified begin index and extends to the end-1 index or end of the context collection. It is an error if the context does not have collection type.
{1,2,3,4,5}->pv:SubList(0) = {1,2,3,4,5} {1,2,3,4,5}->pv:SubList(2) = {3,4,5} {1,2,3,4,5}->pv:SubList(5) = {} {1,2,3,4,5}->pv:SubList(1,4) = {2,3,4} {1,2,3,4,5}->pv:SubList(0,0) = {} {1,2,3,4,5}->pv:SubList(0,1) = {1}
Return a new string, as ps:string, that is a sub-string of the context string. The sub-string begins at the specifiedbegin index and extends to theend-1 index or end of the context string. It is an error if the context does not have string type.
'Hello World'->pv:SubString(6) = 'World' 'smiles'->pv:SubString(1,5) = 'mile'
Get all elements of a model, or just a sub-tree. If the context is a model, then all elements of that model are returned. If the context is an element and the function is called without an argument or with true as argument, then the sub-tree with this element as root is returned. If called on an element with argument false, then the context element will not be part of the result.
model->pv:SubTree->pv:ForAll(e|not(e->pv:Selected)) element->pv:SubTree(false)->pv:Select(e|e->pv:Selected)->pv:Size > 0
Return the sum of all numbers in the context collection, or fail if the context is not a number collection. The return type is ps:integer or ps:float depending on the type of the collection. The sum of an empty collection is 0.
{1,2,3,4}->pv:Sum() = 10
Return the trigonometric tangent of the context number. The result value has type ps:float.
0->pv:Tan() = 0 0.2->pv:Tan() = 0.2027100355086725 100->pv:Tan() = -0.5872139151569291 (-100)->pv:Tan() = 0.5872139151569291
Get the relation target with the given index of the context relation, as ps:element. Fails if the context does not have relation type.
self->pv:Target(0) XOR self->pv:Target(1)
Get the relation targets of the context relation, as ps:element[]. Fails if the context does not have relation type.
self->pv:Type() = 'ps:discourages' AND self->pv:Targets()->pv:ForAll(element | pv:Warn('You better deselect element ' + element->pv:Name())))
Returns the time of the given date time value. The result type is ps:time. If the given date time value is timezoned, the resulting time is also timezoned.
pv:EvaluationDateTime()->pv:Time()->ToString() '2020-02-28T10:24:42'->pv:ToDateTime()->pv:Time()->pv:ToString() = '10:24:42.000' '2020-02-28T10:24:42+01:00'->pv:ToDateTime()->pv:Time()->pv:ToString() = '09:24:42.000Z'
Converts the context string containing a date in XML Schema date format with or without time zone into a date value of type ps:date.
The supported format is: '-'?[0-9]{4,}'-'[0-1][0-9]'-'[0-3][0-9]('Z'|('+'|'-')[0-2][0-9]':'[0-9][0-9])?
It has to be an existing date in the Gregorian calendar and the time zone, if given, has to be in range +14:00 to -14:00.
During conversion the eventually existing time zone is normalized to so-called recoverable time zone, which has the range +12:00 to -11:59.
It fails, if the date format is invalid, or the given date does not exist.
'2020-02-28->pv:ToDate()->pv:ToString() = '2020-02-28' '2020-02-28Z'->pv:ToDate()->pv:ToString() = '2020-02-28Z' '2020-02-28+01:00'->pv:ToDate()->pv:ToString() = '2020-02-27Z' '-0050-07-13'->pv:ToDate()->pv:ToString() = '-0050-07-13'
Converts the context string containing a date and time in XML Schema dateTime format with or without time zone into a date time value of type ps:datetime.
The supported format is: '-'?[0-9]{4,}'-'[0-1][0-9]'-'[0-3][0-9]'T'[0-2][0-9]':'[0-5][0-9]':'[0-5][0-9]('.'[0-9]+)?('Z'|('+'|'-')[0-2][0-9]':'[0-9][0-9])?
It has to be an existing date in the Gregorian calendar and the time zone, if given, has to be in range +14:00 to -14:00.
During conversion the time is rounded to millisecond precision and, if a time zone is given, the time is normalized to GMT.
It fails, if the date time format is invalid, or the given date or time does not exist.
'2020-02-28T12:34:56'->pv:ToDateTime()->pv:ToString() = '2020-02-28T12:34:56.000' '2020-02-28T12:34:56.25Z'->pv:ToDateTime()->pv:ToString() = '2020-02-28T12:34:56.250Z' '2020-02-28T00:02:42.123+01:00'->pv:ToDateTime()->pv:ToString() = '2020-02-27T23:02:42.123Z'
Convert the context number or string to a floating point number. If the context number is an integer, which exceeds the range of valid float number, an overflow error is created. If the context number is already a float, it will be returned as it is. If the context is a string, it will be parsed as a float value. Valid float strings have to follow the grammar:
[+-]? (([0-9]+ ('.' [0-9]*)?) | ('.' [0-9]+)) ([eE] [+-]? [0-9]+)?
If the string is not a valid float string, an error will be created. The return type is ps:float.
1->pv:ToFloat() = 1.0 '-2.3e42'->pv:ToFloat() = -2.3e42
Convert the context number or string to an integer number. If the context number is a float, it will be truncated (i.e., round towards zero). If the context number is already an integer, it will be returned as it is. If the context is a string, it will be parsed as an integer value with radix radix (or radix 10 if omitted). The value of radix has to be in the range [2, 36], where for radices 2 to 10, numerical digits '0' to '9', and for the radices 11 to 36 additionally the letter digits 'A' to 'Z' (or 'a' to 'z') are used. If the string is not a valid integer string, an error will be created. The return type is ps:integer.
1.9->pv:ToInteger() = 1 '-123'->pv:ToInteger() = -123 'CAFE'->pv:ToInteger(16) = 51966
Convert all characters of the context string to lower case. Fails if the context does not have string type. The return type is ps:string.
'Hello'->pv:ToLowerCase() = 'hello'
Return a string representation of the context object. The return type is ps:string.
If a delimiter is given, then the context object needs to be a collection. Instead of just converting the collection to a string, the collection items are listed each separated from the other using the given delimiter. If additionally a last delimiter is given, then this delimiter is inserted between the last item in the collection and its predecessor.
6->pv:ToString() = '6' {1,2,3}->pv:ToString = '{1,2,3}' {1,2,3}->pv:ToString('+') = '1+2+3' {1,2,3}->pv:ToString(', ',', and ') = '1, 2, and 3' {{100,-100},{30,75},{10}}->pv:ToString(', ',', and ') = '{100,-100}, {30,75}, and {10}'
Converts the context string containing a time in XML Schema time format with or without time zone into a time value of type ps:time.
The supported format is: [0-2][0-9]':'[0-5][0-9]':'[0-5][0-9]('.'[0-9]+)?('Z'|('+'|'-')[0-2][0-9]':'[0-9][0-9])?
The time zone, if given, has to be in range +14:00 to -14:00.
During conversion the time is rounded to millisecond precision and, if a time zone is given, the time is normalized to GMT.
It fails, if the time format is invalid, or the given time does not exist.
'12:34:56'->pv:ToTime()->pv:ToString() = '12:34:56.000' '12:34:56.25Z'->pv:ToTime()->pv:ToString() = '12:34:56.250Z' '00:02:42.123+01:00'->pv:ToTime()->pv:ToString() = '23:02:42.123Z'
Convert all characters of the context string to upper case. Fails if the context does not have string type. The return type is ps:string.
'Hello'->pv:ToUpperCase() = 'HELLO'
Convert the context number into an integer by truncating the fractional digits. Fails if the context does not have number type. The return type is ps:integer.
3->pv:Truncate() = 3 1.9->pv:Truncate() = 1 (-2.6)->pv:Truncate() = -2
Get the type of the context as ps:string.
'hello'->pv:Type() = 'ps:string' 42->pv:Type() = 'ps:integer' FeatureA->pv:Type() = 'ps:feature'
Get the name of the currently evaluated variant as ps:string.
pv:VariantName() = pv:Models('ps:vdm')->pv:Item(0)->pv:Name()
Get the variation type of the context element or attribute, as ps:string. Fails if the context does not have element or attribute type. The variation type of attributes always isps:mandatory, and of elements ps:mandatory, ps:optional, ps:or, or ps:alternative.
summer->pv:VariationType() = 'ps:alternative'
Get the visible name of the context, as ps:string, which must be an element, or fail otherwise. Optionally the non-empty language identifier can be specified. Calling the function with an empty language identifier creates an error.
If no language is given, the visible name with no specified language will be returned. If no such visible name exists, any other visible name will be returned. If no visible name is defined for the element, an empty string will be returned. If a language is specified, the visible name in the given language will be returned if available. If no such visible name exists the function falls back to the version without given language.
self->pv:SelectionState() = 'ps:nonselectable' IMPLIES pv:Warn('Feature ' + self->pv:VName() + ' is now non-selectable!')
For complex restrictions and calculations it may be useful to provide additional functions, e.g. to simplify the expressions or to share code. For the expression language pvSCL a code library can be defined in each model. This is done by entering the code into thepvSCL Code Library properties page of a model (seeFigure 9.1, “pvSCL Code Library Model Property Page”).
Each feature or family model in a Configuration Space can define code libraries. Code defined in one model is also available in all other models of the same configuration space. Defining the same function in more than one model, will redefine the function. Since there is no explicit model loading order the used version of the function may differ.