# APL Data-Binding Syntax

APL data binding expressions occur inside JSON strings and take the form "`${expression}`

". Any number of expressions may occur inside a string, such as `"${2}+${2} = ${2+2}"`

. Expressions are evaluated within the current data-binding context. The data-binding context is a global dictionary that supports booleans, numbers, strings, arrays, objects, null, and references to defined resources.

- Supported value types
- Truthy and Coercion
- Operators
- Array and Object access
- Function calls
- Data-binding string conversion

## Supported value types

### Identifier

An identifier is a name used to identify a data-binding variable.
Identifiers must follow the C identifier naming convention:
`[a-zA-Z_][a-zA-Z0-9_]*`

. That is, the identifier must start with an
upper or lower-case ASCII letter or underscore and may be followed by
zero or more ASCII letters, numbers, or the underscore:

```
${data}
${_myWord23}
${__AnUgly26_letter__examplE}
```

### String literals

Strings are defined using either single or double quotes. The starting and ending quote must match. Quotes, carriage returns, and line-feeds may be escaped.

```
${"Double-quoted string"}
${'Single-quoted string'}
${"Inner quote: \" or '"}
```

Expressions may be nested inside of a string.

```
${"Two plus two is ${2+2}"}
```

### Numbers

Positive, negative, and floating point numbers are supported. Scientific notation is not supported. All numbers are internally stored as doubles:

```
${1}
${-34.75}
${64000000000}
```

### Booleans

Boolean values of `true`

and `false`

are supported.

```
${true}
${false}
```

### null

The `null`

constant is supported.

```
${null}
```

### Resources

Resources defined in the data-binding context use the reserved character "@". For example:

```
${@myBlue}
${@isLandscape ? @myWideValue : @myNarrowValue}
```

APL packages define resources exposed in data-binding.

### Absolute dimensions

A dimensional suffix converts a number into an absolute viewport dimension. The valid dimensional suffixes are "dp", "px", "vh", and "vw":

```
${23 dp} // 23 display-independent pixels
${10 px} // 10 pixels
${50 vw} // 50% of the width of the viewport
${100vh} // 100% of the height of the viewport
```

Dimensional suffixes must be attached to a number, not a more complex expression. For example `${(20*20) dp}`

is not valid, but `${20*20dp}`

is valid.

## Truthy and Coercion

Data-binding expressions involve a number of different types. These types may be converted into other types. The following table gives an example of the different conversions (note that this assumes a viewport width of 512dp and a dpi of 320):

Object | Example | As Boolean | As Number | As String | As Color | As Dimension |
---|---|---|---|---|---|---|

Null | null | false | 0 | "" | transparent | 0dp |

Boolean | true | true | 1 | "true" | transparent | 0dp |

Boolean | false | false | 0 | "false" | transparent | 0dp |

Number | 23 | true | 23 | "23" | #00000017 | 23dp |

Number | 0 | false | 0 | "0" | transparent | 0dp |

String | "My dog" | true | 0 | "My dog" | transparent | 0dp |

String | "" | false | 0 | "" | transparent | 0dp |

String | "-2.3" | true | -2.3 | "-2.3" | transparent | -2.3dp |

String | "red" | true | 0 | "red" | #ff0000ff | 0dp |

String | "50vw" | true | 50 | "50vw" | transparent | 256dp |

Array | [] | true | 0 | "" | transparent | 0dp |

Map | {} | true | 0 | "" | transparent | 0dp |

Color | red | true | 0 | "#ff0000ff" | #ff0000ff | 0dp |

Dimension | 32px | true | 16 | "16dp" | transparent | 16dp |

Dimension | 0vh | false | 0 | "0dp" | transparent | 0dp |

Dimension | 23% | true | 0.23 | "23%" | transparent | 23% |

Dimension | 0% | false | 0 | "0%" | transparent | 0% |

Dimension | auto | true | 0 | "auto" | transparent | auto |

Anything else | ... | true | 0 | "" | transparent | 0dp |

### Boolean coercion

A **truthy** value is a value that is considered `true`

when evaluated in a boolean context. All values are truthy except for `false`

, `0`

, `""`

, a zero
absolute or relative dimension, and `null`

.

### Number coercion

The Boolean "true" value is converted to the number 1. String values
are converted using the C++ `std::stod`

method (note that this is
influenced by the locale). Absolute dimensions convert to the number of
dp in the absolute dimension; relative dimensions convert to the
percentage value (e.g., 32% -> 0.32). Everything else converts to 0.

### String coercion

Internal types are converted to strings using the rules in the following table:

Object | Example | Result | Description |
---|---|---|---|

Null | null | `''` |
The null value is not displayed. |

Boolean | true false | `'true'` `'false'` |
Boolean true & false are displayed as strings. |

Number | -23 | `'-23'` |
Integers have no decimal places. |

1/3 | `'0.333333'` |
Non-integers have decimal places. | |

String | "My "dog" " | `'My "dog" '` |
String values |

Array | [...] | `''` |
Arrays are not displayed. |

Map | {...} | `''` |
Maps are not displayed |

Color | red | `'#ff0000ff'` |
Colors are shown in #rrggbbaa format. |

Dimension | 23 dp | `'20dp'` |
Absolute dimensions are shown with the suffix 'dp' |

Dimension | 20 % | `'20%'` |
Percentage dimensions are shown with the suffix '%' |

Dimension | auto | `'auto'` |
The auto dimension is shown as 'auto' |

Anything else | `${Math.min}` |
`''` |
Math functions are not shown. |

The specific format of non-integer numbers is not defined, but should
follow closely the C++ standard for `sprintf(buf, "%f", value)`

. It may
change based on the locale.

### Color coercion

Color values are stored internally as 32-bit RGBA values. Numeric values will are treated as unsigned 32-bit integers and converted directly. String values are parsed according to the rules in Data Types - Color.

### Absolute dimension coercion

Numeric values are assumed to be measurements in "dp" and are converted to absolute dimensions. String values are parsed according to the rules in Data Types - Dimension. All other values are 0.

### Relative dimension coercion

Numeric values are assumed to be percentages and are converted directly. For example, 0.5 converts to 50%. Strings are parsed according to the rules in Data Types - Dimension. All other values are 0.

## Operators

APL supports different types of operators: arithmetic, logical, comparison, and ternary.

### Arithmetic operators

The standard arithmetic operations for addition, subtraction, multiplication, division, and remainder are supported:

```
${1+2} // 3
${1-2} // -1
${1*2} // 2
${1/2} // 0.5
${1%2} // 1.
```

Addition and subtraction work for pairs of numbers, absolute dimensions, and relative dimensions. When a number is combined with either an absolute or relative dimension, the number is coerced into the appropriate dimension.

The addition operator also acts as a string-concatenation operator if either the left or right operand is a string.

```
${27+''} // '27'
${1+' dog'} // '1 dog'
${'have '+3} // 'have 3'
```

Multiplication, division, and the remainder operator work for pairs of numbers. Multiplication also works if the one of the operands is a dimension (either relative or absolute) and the other is a number; the result is a dimension. Division also works if the first operand is a dimension (either relative or absolute) and the second is a number; the result is a dimension.

The remainder operator behaves as in JavaScript. That is,

```
${10 % 3} // 1
${-1 % 2} // -1
${3 % -6} // 3
${6.5 % 2} // 0.5
```

### Logical operators

The standard logical and/or/not operators are supported.

```
${true || false} // true
${true && false} // false
${!true} // false
```

The `&&`

returns the first operand if it is not truthy and the second otherwise. The `||`

operator returns the first operand if it is truthy and the second otherwise.

```
${7 && 2} // 2
${null && 3} // null
${7 || 2} // 7
${0 || -16} // -16
```

### Comparison Operators

Comparison operators return boolean values.

```
${1 < 2}
${75 <= 100}
${3 > -1}
${4 >= 4}
${myNullValue == null}
${(2>1) == true}
${1 != 2}
```

The comparison operators do not apply to arrays and objects.

### Null coalescing

The `??`

operator is the null-coalescing operator. It returns the
left-hand operand if the operand is not null; otherwise it returns the
right-hand operand. The null-coalescing operator may be chained:

```
${person.name ?? person.surname ?? 'Hey, you!'}
```

The null-coalescing operator will return the left-hand operand if it is anything but null:

```
${1==2 ?? 'Dog'} // returns false
${1==2 || 'Dog'} // returns 'Dog'
```

### Ternary Operator

The ternary conditional operator `${a ? b : c}`

evaluates the left-hand operand. If it evaluates to true or a truthy value, the middle operand is returned. Otherwise the right-hand operand is returned.

```
${person.rank > 8 ? 'General' : 'Private'}
```

## Array and Object access

### Array

Array access uses the `[]`

operator, where the operand should be an integer. Arrays also support the `.length`

operator to return the length of the array. Accessing an element outside of the array bounds returns `null`

.

```
${myArray[4]} // 5th element in the array (0-indexed)
${myArray.length} // Length of the array
${myArray[-1])} // Last element in the array
${myArray[myArray.length]} // Returns null (out of bounds)
```

Passing a negative index counts backwards through the array.

```
${a[-1] == a[a.length - 1]} // True
```

### Object

Objects support the `.`

operator and the `[]`

array access operator with string values.

```
${myObject.name} // The 'name' property of myObject
${myObject['name']} // The 'name' property of myObject
```

If the property is not defined, `null`

is returned.

Calling the `.`

or `[]`

operator on `null`

returns `null`

.

```
${myNullObject.address.zipcode} // Returns null
```

The right-side operand of the dot operator must be a valid identifier.

## Function calls

Data-binding supports a limited number of built-in functions. Functions are of the form:

```
functionName( arg1, arg2, … )
```

Functions do not have to have arguments. A function returns a single value. Some functional expressions are shown here:

```
${Math.floor(1.1)} // 1
${Math.ceil(1.2)} // 2
${Math.round(1.2)} // 1
${Math.min(1,2,3,4)} // 1
${Math.max(1,2,3,4)} // 4
${String.toUpperCase('Hello')} // HELLO
${String.toLowerCase('Hello')} // hello
${String.slice('Hello', 1, -1)} // ell
```

### Built-in functions

Some mathematical and string functions are built in to APL.

Property | Description | Example |

Math.abs(x) | Return the absolute value of x | ${Math.abs(-2.3)} == 2.3 |

Math.acos(x) | The arccosine of x | ${Math.acos(1)} == 0 |

Math.asin(x) | The arcsine of x | ${Math.asin(0)} == 0 |

Math.atan(x) | The arctangent of x | ${Math.atan(1)} == 0.7853981633974483 |

Math.ceil(x) | Return the smallest integer greater than or equal to x. | ${Math.ceil(2.3)} == 3 |

Math.clamp(x,y,z) | Return x if y<x, z if y>z, and otherwise y. | ${Math.clamp(1, 22.3, 10)} == 10 |

Math.cos(x) | The cosine of x | ${Math.cos(0)} == 1 |

Math.floor(x) | Return the largest integer less than or equal to x. | ${Math.floor(2.3)} = 2 |

Math.max(x1,x2,…) | Return the largest argument | ${Math.max(2,3)} == 3 |

Math.min(x1,x2,…) | Return the smallest argument | ${Math.min(2,3)} == 2 |

Math.PI | The value of PI | 3.141592653589793 |

Math.random() | A random number between 0 and 1 | ${Math.random()} == 0.7113654073137101 (the actual random number returned will be different) |

Math.round(x) | Return the nearest integer to x | ${Math.round(2.3)} == 2 |

Math.sign(x) | The sign of x: -1, 0, or 1 | ${Math.sign(-43.1) == -1} |

Math.sin(x) | The sine of x | ${Math.sin(Math.PI/6)} == 0.5 |

Math.sqrt(x) | The square root of x | ${Math.sqrt(9)} == 3 |

Math.tan(x) | The tangent of x | ${Math.tan(Math.PI/4)} == 0.5 |

String.slice(x,y[,z]) | Return the subset of x starting at index y and extending to but not including index z. If z is omitted, the remainder of the string is returned. If y is a negative number, select from the end of the string. | `${String.slice('berry', 2, 4)} == 'rr'` `${String.slice('berry', -2)} == 'ry'` |

String.toLowerCase(x) | Return a lower-case version of x | ${String.toLowerCase('bEn')} == "ben" |

String.toUpperCase(x) | Return an upper-case version of x. | ${String.toUpperCase('bEn')} == "BEN" |

## Data-binding string conversion

Because APL is serialized in JSON, all data-bound expressions are defined inside of a JSON string:

```
{
"MY_EXPRESSION": "${....}"
}
```

If there are no spaces between the quotation marks and the data-binding expression, then the result of the expression is the result of the data-binding evaluation. For example:

```
"${true}" -> Boolean true
"${2+4}" -> Number 6
"${0 <= 1 && 'three'}" -> String 'three'
```

When extra spaces are in the string outside of the data-binding expression or when two data-binding expressions are juxtaposed, the result is a string concatenation:

```
" ${true}" -> String ' true'
"${2+4} " -> String '6 '
"${2+1}${1+2}" -> String '33'
```