Skip to content

Operators

hhas edited this page Feb 4, 2023 · 5 revisions

The standard library defines the following operators which are imported by default.

Constants

nothing
false
true
π

Arithmetic

EXPR ^ EXPR

+ EXPR
- EXPR

EXPR × EXPR
EXPR ÷ EXPR
EXPR div EXPR
EXPR mod EXPR
EXPR + EXPR
EXPR - EXPR

(^ = exponent; * is alias for ×; / is alias for ÷)

Numeric comparisons

EXPR = EXPR
EXPR ≠ EXPR
EXPR < EXPR
EXPR > EXPR
EXPR ≤ EXPR
EXPR ≥ EXPR

(<= is alias for ; >= is alias for )

Boolean logic

not EXPR
EXPR and EXPR
EXPR or EXPR
EXPR xor EXPR

String comparisons

EXPR is_same_as EXPR
EXPR is_not_same_as EXPR
EXPR is_before EXPR
EXPR is_after EXPR
EXPR is_not_before EXPR
EXPR is_not_after EXPR
EXPR begins_with EXPR
EXPR contains EXPR
EXPR ends_with EXPR
EXPR is_in EXPR

TO DO: these names may change and/or be aliased; TO DO: support comparing non-string types

String concatenation

EXPR & EXPR

Type check

EXPR is_a EXPR

Type cast

EXPR as EXPR

(The right operand must be a type command, e.g. string, editable list of: number)

Type constructors

editable EXPR
optional EXPR

(The right operand is optional. If given, it must be a type command; if omitted, anything is used.)

record EXPR

(The right operand is optional. If given, it is a record of form { label: type_command, … })

Property/element references

EXPR of EXPR

Reference forms

(These are used in aelib and behave as in AppleScript/SwiftAutomation.)

Reference forms:

EXPR at EXPR
EXPR named EXPR
EXPR id EXPR
EXPR from EXPR
EXPR whose EXPR

(at = by-index; from = by-range)

EXPR thru EXPR

(thru is used as from operator’s right operand. In future it may also be used to construct numeric ranges.)

EXPR before EXPR
EXPR after EXPR

(These are relative references. The left operand is an element type, e.g. document)

Ordinals:

first EXPR
middle EXPR
last EXPR
any EXPR
every EXPR

Insertion location:

beginning
end
before EXPR
after EXPR

Decision-making (flow control)

if TEST then ACTION

if TEST then ACTION else ALTERNATE_ACTION

while TEST repeat ACTION

TO DO: else should be a binary operator, independent of if, which can be composed with while and other commands

Assignment

set EXPR to EXPR

If the left operand is a name and set does not appear in a tell block, a new handler is defined in the current scope that returns the value of the right operand when invoked by the corresponding command:

✎ set name to “Bob”
☺︎ “Bob”
✎ name
☺︎ “Bob”

This provides variable-like behavior without needing a distinct “variable” type (name is a command with no arguments).

Note that name-scope bindings are immutable (equivalent to bind-once variables):

✎ set name to “Bob”
☺︎ “Bob”
✎ set name to “Sam”
☹︎ «handler: ‘set’ …» failed on command: … Can’t modify immutable value.

To make a binding mutable, cast the right operand to editable …:

✎ set age to 42 as editable
☺︎ editable 42
✎ age
☺︎ 42

This effectively binds an editable container that holds the initial value, which can be replaced with a new value:

✎ set age to 16
☺︎ 16
✎ age
☺︎ 16

TO DO: Left operand does not yet fully support references and multiple (list/record) binding.

Tell

Similar to AppleScript, “tell” blocks redirect commands (right operand) to the target object (left operand) instead of the current scope.

tell EXPR to ACTION

Block

As an alternative to parentheses, groups may be delimited by do and done keywords:

do ( EXPR SEP )* done

Handler

to SIGNATURE run ACTION

when SIGNATURE run ACTION

(to = command handler, describes actions to be performed; when = event handler, responds to notifications; the difference is that an event handler ignores any unmatched arguments whereas a command handler throws an “unknown argument” error, so event handlers can ignore arguments they aren't interested in)

For example:

to Hello {name as string} returning nothing run say (“Hello ’ & name).

A handler signature consists of the handler’s name, optionally followed by a parameter record, followed by returning operator, the right operand of which is a type command describing the handler’s return value, e.g.:

Hello name returning nothing

Hello {name as string} returning nothing

Hello {name: name as string, with_emphasis: emphasis as optional boolean with_default false} returning nothing

A parameter record is of form:

{label: binding as coercion}

The binding is the name under which the corresponding command argument is stored within the handler’ scope (activation record). The label and coercion are optional. If the label is omitted, the binding name is used for both. If the coercion is omitted, any value except nothing is accepted.

The returning operator can be omitted when defining a handler, in which case the handler’s return type defaults to any value (including nothing).

These signatures are equivalent (the first uses operator syntax, the second uses command syntax only):

Hello {name as string, with_emphasis: emphasis as optional boolean with_default false} returning nothing

‘returning’ {
  Hello {
    name: ‘as’ {name, string}, 
    with_emphasis: ‘as’ {emphasis, ‘optional’ {boolean, with_default: false}}
  },
  nothing
}