[UP]
The UI language
 ui:a
 ui:alist-value and ui:alist-item
 ui:application
 ui:button
 ui:checkbox
 ui:cond
 ui:context
 ui:default
 ui:dialog
 ui:dyn-enum-value and ui:dyn-enum-item
 ui:dynamic
 ui:encode
 ui:enum-value and ui:enum-item
 ui:enumerate
 ui:enumeration and ui:enum
 ui:false
 ui:file
 ui:form
 ui:if
 ui:ifexpr
 ui:iflang
 ui:ifvar
 ui:imagebutton
 ui:iter-*
 ui:iterate
 ui:page
 ui:param
 ui:popup
 ui:radio
 ui:richbutton
 ui:select
 ui:server-popup
 ui:special
 ui:string-value
 ui:template
 ui:text and ui:password
 ui:textarea
 ui:translate
 ui:true
 ui:use
 ui:variable
 t:*, q:*, and p:*
 l:*
 $param
 $[expr]
 Dot notation (v1.v2)
   
Bracket expressions $[...]

Bracket expressions allow the UI developer to access dialog variables from page or template definitions (i.e. everywhere the dollar character is recognized as meta symbol). For example, $[v] would expand to the current value of the dialog variable v. Of course, this works only if this variable is a string variable, as it would be unclear what to do with a non-string value (e.g. an enumeration).

So far, so simple. In recent versions of WDialog, the brackets cannot only contain variable names but whole expressions that are computed when the bracket is expanded. For instance, the expression $[card(v)] expands to the number of words in the string v. There are a number of functions that can be applied to variables (see below). The syntax of function calls always includes parantheses, so x is a variable, and x() is a function call. Functions may have several arguments, separated by commas, e.g. f(x1,x2,x3).

Of course, the card function is not only reasonable for strings. We can also define the cardinality of enumerator values, and of associative lists. Because of this it is allowed to write $[card(v)] when v is an enumerator or alist. In general, the intermediate values during evaluation may be of any type that can be stored in a dialog variable; however the final value must be a string as the result is inserted into the XML tree[1]. Typing is dynamic, and although the functions usually only accept certain types as arguments it is not tried to verify that by a type checker.

It is not only possible to access variables, but also template parameters. The dollar character must prefix the parameter name, e.g. $[$p]. Braces are allowed, and even output encodings can be specified: $[${p}] and $[${p/html}] are legal expressions. The parameters are evaluated to strings (as if they would occur in attribute context). A number of UI control elements are expanded allowing one to mix template-level and dialog-level evaluation strategies. For example, the template t2 expands to the size of the expanded template t1:

<ui:template name="t1">
  This is a text
</ui:template>

<ui:template name="t2" from-caller="which">
  <ui:default param="which"><ui:use template="t1"/></ui:default>
  $[card($which)]
</ui:template>

The expanded text is 4, the number of words in t1.

We have mentioned variables, functions, parameters. Is it possible to include constant values into bracket expressions? Yes, but the current implementation is quite limited. Numbers can be used literally, e.g. $[add(n,2)]. It is also possible to construct strings of words using the words form, e.g. $[words(a,b,c)] is the string "a b c". The words must be syntactically names. It is not (yet) possible to include arbitrary string constants or any non-string constants. These may be added later.

Another important syntactic note: Bracket expressions must not contain white space! They are not even recognized by the parser if they do.

There are also some boolean functions. The value 0 is considered as the false value, and numbers other than 0 are considered as true values.

Now the list of functions that are defined by default:

  • id(expr): Just returns expr (identity)

  • length(str): Returns the number of characters of the string str

  • card(expr): If expr is a string, this function returns the number of words. If expr is an enumerator or associative list, this function returns the number of elements. This definition of cardinality is just the same as that of ui:iterate.

  • size(expr): Deprecated! If expr is a string, this function returns the number of characters. If expr is an enumerator or associative list, this function returns the number of elements.

  • add(num1,...,numN): Adds all the numbers passed as arguments and returns the sum.

  • sub(num1,...,numN): Subtracts the second and all following arguments from the first argument, and returns the difference.

  • mul(num1,...,numN): Multiplies all the numbers passed as arugments and returns the product.

  • div(num1,...,numN): Divides the first number through the second number and all following numbers (in turn), and returns the quotient.

  • modulo(num1,...,numN): Divides the first number through the second number and takes the modulus, and continues with the following numbers in turn, and returns the final modulus.

  • assoc(alist,str): Looks up the str argument in the associative list alist, and returns the value that corresponds to the str key. Of course, str must be a string. It is an error if str does not occur in alist.

  • nth(alist,num): Returns the numth value of the associative list alist, i.e. num is the ordinal number of the value to return. The first value has the ordinal number 0. It is an error if num is greater or equal than the number of elements of alist.

  • contains(container,str): Returns 1 if the first argument contains the second argument, and 0 otherwise. The second argument must be a string value. The function is defined as follows: If the container is a string, it is split up into a list of words, and it is tested whether str occurs in the list of words. If the container is a declared enumerator, it is tested whether the value includes str as item. If the container is a dynamic enumerator, it is tested whether the value includes str as internal item. If the container is an associative list, it is tested whether the value includes str as index.

  • mentions(container,str): Returns 1 if the first argument contains the second argument, and 0 otherwise. The second argument must be a string value. The function is defined as follows: If the container is a dynamic enumerator, it is tested whether the value includes str as external item. If the container is an associative list, it is tested whether the value includes str as mapped value.

  • translate(dynenum,str): Returns the external value that corresponds to the internal value str in the dynamic enumerator dynenum. It is an error if str does not occur as internal value in dynenum.

  • translate(enum(name),str): Returns the external value that corresponds to the internal value str in the declared enumerator type name (i.e. the name in a ui:enumeration declaration). It is an error if str does not occur as internal value in the enumeration. See below for explanations of the enum form.

  • rev-translate(dynenum,str): Returns the (first) internal value that corresponds to the external value str in the dynamic enumerator dynenum. It is an error if str does not occur as external value in dynenum.

  • rev-translate(enum(name),str): Returns the (first) internal value that corresponds to the external value str in the declared enumerator type enum (i.e. the name in a ui:enumeration declaration). It is an error if str does not occur as external value in the enumeration. See below for explanations of the enum form.

  • eq(str1,str2): Returns 1 if both strings are equal, and 0 otherwise

  • ne(str1,str2): Returns 1 if the strings are not equal, and 0 otherwise

  • match(str1,str2): Returns 1 if the string str1 matches the regular expression str2, and 0 otherwise

  • nomatch(str1,str2): Returns 1 if the string str1 does not match the regular expression str2, and 0 otherwise

  • substring(str,num1): Returns the substring of str starting at character position num1 until the end of the string.

  • substring(str,num1,num2): Returns the substring of str starting at character position num1 with length num2 (the length can be negative).

  • concat(str1,...,strN): Concatenates the strings str1 to strN.

  • int-eq(num1,num2): Returns 1 if both numbers are equal, and 0 otherwise

  • int-ne(num1,num2): Returns 1 if the numbers are not equal, and 0 otherwise

  • int-lt(num1,num2): Returns 1 if num1 < num2, and 0 otherwise

  • int-le(num1,num2): Returns 1 if num1 <= num2, and 0 otherwise

  • int-gt(num1,num2): Returns 1 if num1 > num2, and 0 otherwise

  • int-ge(num1,num2): Returns 1 if num1 >= num2, and 0 otherwise

  • int-min(num,...): Returns the minimum of all passed numbers

  • int-max(num,...): Returns the maximum of all passed numbers

  • int-abs(num): Returns the absolute value

  • int-sign(num): Returns the sign of the number

  • card-eq(container,num), card-ne(container,num), card-lt(container,num), card-le(container,num), card-gt(container,num), card-ge(container,num): These functions compare the cardinality of container with the number. The cardinality is defined as for the card function.

  • height(str): Returns the number of lines the string str consists of. A line is separated from the next one by either LF, CR, or CRLF bytes. The number of lines is the number of these line separators plus 1.

  • width(str): Returns the number of characters the longest line in string str consists of. The line separators are not counted for the width.

  • dialog_exists(dlg): Returns 1 if the dialog exists, 0 otherwise

  • and(bool,...): Returns 1 if all arguments are non-zero integers, and 0 otherwise. This function is evaluated lazily.

  • or(bool,...): Returns 1 if there is a non-zero integers as argument, and 0 otherwise. This function is evaluated lazily.

  • not(bool): Returns 1 if the argument is 0, and 0 if the argument is non-zero.

  • true(): Returns 1

  • false(): Returns 0

  • if(bool,true_arg,false_arg): If bool is a non-zero number, the value of true_arg is returned. If 0, the value of false_arg is returned. This function is evaluated lazily.

  • var(str): Returns the contents of the dialog variable called str. (This function can be used to access variables indirectly.)

  • dialog(): Returns the name of the current dialog.

  • self(): Returns the current dialog.

  • page(): Returns the name of the current page.

  • language(): Returns the current language, or the empty string if none is selected.

  • self-base-url(): Return the URL pointing to the current script (omitting any URL parameters)

  • session-id(): Returns the session ID without checksum

  • create-anchor-event(str): Add the anchor event source called str, and return the HTML-level identifier.

  • create-xanchor-event(str1,str2): Add the anchor event source called str1 for index str2, and return the HTML-level identifier.

Furthermore, there are the following special forms, i.e. syntactic elements evaluated in a special way:

  • type(var): Returns the name of the type of the variable var. The argument is not expanded before evaluation of the form, but taken literally, e.g. type(x) returns the type of the variable x, and not the type of the variable whose name is stored in the variable x. The return value is a string:

    • "string" is the type name of string variables

    • "dialog" is the type name of dialog variables

    • "dynamic-enumerator" is the type name of dynamic enumerator variables

    • The name of the enumeration is the type name of enumerator variables

    The type name is what the ui:variable element declares with the type argument.

    It does not matter whether the variable is associative or not.

  • is-associative(var): Returns whether the type of the variable var is associative or not. Like the type form, the argument is taken literally. The return value is either the string "yes" or "no".

  • default(var): Returns the default value used to initialize the variable var when the dialog object is created. Like the type form, the argument is taken literally. The return value is a value of appropriate type.

  • enum(name): Returns the declaration of the enumeration enum as a dynamically enumerated value. The argument is taken literally.

  • words(name,...): Returns the string containing the names literally (i.e. the concatenated names separated by spaces). The arguments are taken literally.

Numbers are represented as decimal strings.

As strings can contain multi-byte characters, the question arises whether the string functions take the number of bytes or the number of characters as "position" or "length". Of course, characters are counted, so the user does not have to take care of the character encoding.


[1]
It may be possible to also allow XML tree types here, but such types do not occur in the rest of the UI language. This is an interesting idea for a future extension of the language, though.