iXML Language Reference
This document provides a comprehensive reference for the iXML language syntax and usage.
iXML envelope
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE ixml SYSTEM "https://developers.zeyos.com/schema/ixml.dtd">
<ixml
xmlns="https://developers.zeyos.com/schema/ixml"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="https://developers.zeyos.com/schema/ixml https://developers.zeyos.com/schema/ixml.xsd">
<!-- Code -->
</ixml>
Variables
The name of a variable is a placeholder for its value, the data it holds. Referencing its value is called variable substitution. Variables that are referenced inside an expression are expanded to their respective values. For that purpose variables are represented by a dollar sign ('$') followed by the name of the variable. The next punctuation character implicitly ends the variable name even though it may explicitly be concluded by a trailing dollar sign ('$'). A dollar sign ('$') is passed unchanged if not followed by an alphanumeric character or underscore. Two adjacent dollar signs ('$$') are substituted with one single dollar sign ('$') as an escape syntax. The variable name is case-sensitive and consists of alphanumeric characters and underscores only. Variables typically have a single local scope and are therefore only visible within the immediate context, unless they have been specifically declared as global variables in which case they are given global scope and are then independent of the context within which they are defined. Closures may be used to establish a referencing environment for free function variables. Those variables are explicitly bound to corresponding variables from the immediate context within which a function is defined, thereby directly referencing non-local variables from the parent scope outside of the inherent context of that function. The order of visibility precedence from highest to lowest is: special local variables (e.g. 'this', 'return', 'arguments'), free function variables, regular local variables (parameters), global variables. Primitive non-composite variables are always assigned by value while complex variables are always assigned by reference. Assignment by reference may cause circular references. Complex data structures with circular references are considered bad practice as they generally entail memory management drawbacks and possibly raise maximum stack depth exceptions when operated on. Using a variable before assigning a value to it may cause problems. It is nevertheless possible to perform operations on an uninitialized variable as it then defaults to the neutral literal of the accordant input type.
<set var="name">iXML</set>
<output>My name is $name!</output>
<!-- My name is iXML! -->
A special shortcut syntax may be used for referencing array items directly by specifing the corresponding key, either enclosed in square brackets ('[]') or appended with a dot ('.').
<set var="names[bg]">Bill Gates</set>
<set var="names[sj]">Steve Jobs</set>
<output>$names[bg] and $names[sj] are competitors!</output>
<!-- Bill Gates and Steve Jobs are competitors! -->
Within square brackets (array notation) a key is not interpreted as a literal but as an expression, resulting in further variable substitution. Although empty brackets will simply be interpreted as empty key literals in case of substitution or when used for getting or unsetting in general, they will implicitly generate a consecutive numeric key when used for setting.
<set var="names[bg]">Bill Gates</set>
<set var="names[sj]">Steve Jobs</set>
<set var="key1">bg</set>
<set var="key2">sj</set>
<output>$names[$key1] and $names[$key2] are competitors!</output>
<!-- Bill Gates and Steve Jobs are competitors! -->
A key that is appended with a dot (object notation) is always interpreted as a literal. Although keys in general may consist of any characters whatsoever, they may consist of alphanumeric characters and underscores only when accessed with the object notation (dot syntax). This specific restriction does not apply to the array notation (square bracket syntax).
<set var="names.bg">Bill Gates</set>
<set var="names.sj">Steve Jobs</set>
<output>$names.bg and $names.sj are competitors!</output>
<!-- Bill Gates and Steve Jobs are competitors! -->
Several keys may also be strung together to form a key chain of arbitrary length, which allows multidimensional arrays to be accessed directly, whereby the array notation (square bracket syntax) and the object notation (dot syntax) may be mixed.
<set var="names.microsoft[bg]">Bill Gates</set>
<set var="names[apple].sj">Steve Jobs</set>
<output>$names[microsoft].bg and $names.apple[sj] are competitors!</output>
<!-- Bill Gates and Steve Jobs are competitors! -->
References of array items may also be deeply nested within the array notation (square bracket syntax) or other substitution mechanisms.
<set var="names.bg">Bill Gates</set>
<set var="names[sj]">Steve Jobs</set>
<set var="keys[bill_gates]">bg</set>
<set var="keys.steve_jobs">sj</set>
<output>$names[$keys.bill_gates] and $names[$keys[steve_jobs]] are competitors!</output>
<!-- Bill Gates and Steve Jobs are competitors! -->
A special shortcut syntax may be used for substitution of embedded functional expressions pertaining to a variable that references a function (parenthesis syntax). Functional expressions that are embedded inside another expression are replaced by their result. For that purpose functional expressions are represented by a leading variable reference followed by a single argument put into parentheses ('()').
<function var="lcase">
<tolower var="return">$return</tolower>
</function>
<set var="name">iXML</set>
<output>My name is $lcase($name)!</output>
<!-- My name is ixml! -->
Functional expressions in parenthesis syntax may also be deeply nested within other substitution mechanisms.
The data type of a variable is determined by the context in which the variable is used and defaults to the neutral literal of the accordant input type.
iXML recognizes the following data types for variables:
| Type | Neutral Literal | Description |
|---|---|---|
| null | NULL | NULL |
| bool | FALSE | Boolean (true or false) |
| int | 0 | Integer number |
| float | 0.0 | Floating point number |
| string | '' | String (arbitrary byte sequence) |
| array | - | Array (collection of items in an ordered map that associates keys to values) |
| function | - | Function (closed subroutine) |
| macro | - | Macro (open subroutine) |
| class | - | Class (array prototype) |
An undeclared variable is undefined and therefore has neither type nor value. The NULL value however indicates a variable that is defined but does not hold any data. It can be thought of as uninitialized, invalid or empty. NULL is not equivalent to the ASCII NUL byte ('\0') and, although comparable, it is semantically different from an empty string.
The extended classification includes the following additional pseudo-types that generalize semantically related intrinsic data types:
| Pseudo-Type | Intrinsic Types | Description |
|---|---|---|
| number | int/float | Integer or floating point number |
| numeric | int/float/string | Number or string representation thereof |
| scalar | bool/int/float/string | All primitive non-composite types other than NULL |
| subroutine | function/macro | Subroutine |
| complex | array/function/macro/class | All complex types |
| Value | Types | TYPEOF | IF='' | IF!='' | IF='0' | CAST(bool) | CAST(int) | CAST(float) | CAST(string) |
|---|---|---|---|---|---|---|---|---|---|
<undefined> | - | 'undefined' | true | false | false | false | 0 | 0 | '' |
| NULL | null | 'null' | true | false | false | false | 0 | 0 | '' |
| TRUE | bool/scalar | 'bool' | false | true | false | true | 1 | 1 | '1' |
| FALSE | bool/scalar | 'bool' | true | false | false | false | 0 | 0 | '' |
| 0 | int/number/numeric/scalar | 'int' | false | true | true | false | 0 | 0 | '0' |
| 123 | int/number/numeric/scalar | 'int' | false | true | false | true | 123 | 123 | '123' |
| 0.0 | float/number/numeric/scalar | 'float' | false | true | true | false | 0 | 0 | '0' |
| 123.123 | float/number/numeric/scalar | 'float' | false | true | false | true | 123 | 123.123 | '123.123' |
| '0' | string/numeric/scalar | 'string' | false | true | true | false | 0 | 0 | '0' |
| '123' | string/numeric/scalar | 'string' | false | true | false | true | 123 | 123 | '123' |
| '' | string/scalar | 'string' | true | false | false | false | 0 | 0 | '' |
| 'abc' | string/scalar | 'string' | false | true | false | true | 0 | 0 | 'abc' |
<array> | array/complex | 'array' | false | true | false | true | 0 | 0 | '[array#123]' |
<function> | function/subroutine/complex | 'function' | false | true | false | true | 0 | 0 | '[function#123]' |
<macro> | macro/subroutine/complex | 'macro' | false | true | false | true | 0 | 0 | '[macro#123]' |
<class> | class/complex | 'class' | false | true | false | true | 0 | 0 | '[class#123]' |
Arithmetic expressions
An arithmetic expression is a placeholder for its result. Whenever a number is explicitly expected, the corresponding expression is automatically evaluated arithmetically. Its result is then implicitly cast to the appropriate input type. All C-like arithmetic and bitwise operators as well as their respective precedences are applicable to arithmetic expressions. Integer numbers can be specified in decimal (base 10), hexadecimal (base 16, '0x...'), octal (base 8, '0...') or binary (base 2, '0b...') notation while floating point numbers can be specified in decimal (base 10) or scientific E notation.
<math:abs var="number">(0x12 - 19.5) * $number</math:abs>
A special shortcut syntax may be used for substitution of embedded arithmetic expressions that are independent of the superordinate data type (parenthesis syntax). Arithmetic expressions that are embedded inside another expression are replaced by their result. For that purpose arithmetic expressions are represented by a leading dollar sign ('$') and put into parentheses ('()').
<set var="birthyear">1950</set>
<output>This person is `$(2012 - $birthyear)` years old!</output>
<!-- This person is 62 years old! -->
Arithmetic expressions in parenthesis syntax may also be deeply nested within other substitution mechanisms.
<array var="names">
<item>Bill Gates</item>
<item>Steve Jobs</item>
</array>
<output>$names[0] and $names[`$(0 + 1)`] are competitors!</output>
<!-- Bill Gates and Steve Jobs are competitors! -->
Result propagation
Any CDATA value of a statement may be replaced with the result of an embedded statement, unless it is explicitly precluded. An incompatible result type is thereby implicitly cast to the appropriate input type.
<set var="number">`$(15 + (7.5 * 2 - 3)`)</set>
<output>$number</output>
<!-- 27 -->
<output>
<set>`$(15 + (7.5 * 2 - 3)`)</set>
</output>
<!-- 27 -->
At the same time the result may still be stored in a result variable if specified.
<output>
<set var="number">`$(15 + (7.5 * 2 - 3)`)</set>
</output>
<output>,$number</output>
<!-- 27,27 -->
If code is embedded, the last scalar result is then used for propagation.
<output>
<set var="number">10</set>
<set>`$($number + 100)`</set>
<set>`$($number + 5)`</set>
</output>
<!-- 15 -->
The embedded code may also be deeply nested. Results of IF, IS and SWITCH are then propagated to the topmost statement.
<set var="born">1945</set>
<output>
<if value1="$born" func="<" value2="1950">
<set>This person is very old!</set>
<else>
<set>`$(2012 - $born)`</set>
</else>
</if>
</output>
<!-- This person is very old! -->
Any CDATA values that are used alongside embedded code are discarded.
<output>
<set>`$(15 + (7.5 * 2 - 3)`)</set>
471
</output>
<!-- 27 -->
Result propagation is also applicable to user-defined functions.
<function var="getName">
<set var="return">iXML</set>
</function>
<output>
<call func="getName"/>
</output>
<!-- iXML -->