Chapter 6 Expressions

Table of Contents
Overview
Literals
Operations
Comparison Operators
Boolean Operators
Bitwise Operators
If Expressions
Match Expressions
Choose Expressions
Optional Types
Variant Construction

Overview

Expressions are the core computational units of Scaly. Every expression evaluates to a value. Unlike many languages, Scaly uses postfix operators and does not define operator precedence — evaluation order is always explicit.

Literals

Expressions are the core computational units of Scaly. Every expression evaluates to a value.

Boolean Literals

The boolean literals are true and false.

InputResult
truetrue
falsefalse

Integer Literals

Integer literals are sequences of decimal digits, optionally preceded by a minus sign for negative numbers.

InputResult
4242
00
-7-7

Hexadecimal Literals

Hexadecimal literals start with 0x or 0X followed by hexadecimal digits (0-9, a-f, A-F).

InputResult
0xFF255
0x1A26
0x00

Floating-Point Literals

Floating-point literals contain a decimal point separating the integer and fractional parts.

InputResult
3.143.14
2.02.0
0.50.5

String Literals

String literals are enclosed in double quotes. They may span multiple lines, with line breaks preserved in the resulting string.

InputResult
"hello"hello
""

Character Literals

Character literals represent a single character, enclosed in backticks.

InputResult
`a`a
`Z`Z

Operations

Operations allow combining expressions.

Prefix Functions

An operation is a sequence of operands that evaluates to a single value. Each operand is an expression optionally followed by member access. An operation ends with a colon, a line break, or anything which is not an expression. Evaluation uses a context which is empty at the start of an operation. When the context is empty, operator-shaped identifiers act as prefix functions, taking the next operand as their argument.

InputResult
-7-7
-(-3)3
+ 33

Operator Chains

When the context holds a value, operators combine with operands according to standard mathematical precedence. Multiplicative operators (*, /, %, div, mod) bind tighter than additive operators (+, -). Comparison and equality operators have lower precedence than arithmetic. Operators of equal precedence associate left-to-right.

InputResult
3 + 47
10 - 37
6 * 742
84 / 242
17 % 52
3 + 4 * 211
20 - 5 - 312

Parentheses and Grouping

Parentheses create a empty context. This allows prefix forms inside an otherwise operator chain, and explicit grouping when needed.

InputResult
5 * (- 2)-10
2 * (3 + 4)14
(2 + 3) * (4 + 1)25

Identifier Shapes

Identifiers can have name shape (alphanumeric) or operator shape (symbols). The shape is purely lexical and does not determine behavior. Whether an identifier acts as a prefix function or chain operator depends on its declaration and the register state.

InputResult
10 div 33
abs (- 5)5

Let Bindings

Let bindings introduce local variables. The syntax is let followed by a name and a value expression (no equals sign). Multiple statements are separated by colons or newlines.

InputResult
let x 5
x
5
let x 5
x + 3
8
let x 5
let y 3
x + y
8
let x 2 + 3
x * 2
10

Comparison Operators

Comparison operators compare two values and return a boolean result.

Equality

The equality operator (=) tests if two values are equal. The inequality operator (not equal to) tests if two values are different.

InputResult
5 = 5true
5 = 3false
5 <> 3true
5 <> 5false

Relational Operators

Relational operators compare the ordering of values.

InputResult
3 < 5true
5 < 3false
5 > 3true
3 > 5false
5 <= 5true
5 <= 3false
5 >= 5true
3 >= 5false

Boolean Operators

Boolean operators combine boolean values.

Boolean Negation

The tilde operator negates a boolean value.

InputResult
~truefalse
~falsetrue

Boolean And/Or

The ampersand operator performs logical AND, the pipe operator performs logical OR.

InputResult
true & truetrue
true & falsefalse
false | falsefalse
true | falsetrue

Bitwise Operators

Bitwise operators manipulate integer values at the bit level.

Bit Shifts

The left shift operator shifts bits to the left, effectively multiplying by powers of two. The right shift operator shifts bits to the right, effectively dividing by powers of two.

InputResult
1 << 416
5 << 340
16 >> 24
100 >> 312

If Expressions

If expressions evaluate one of two branches based on a boolean condition. The syntax is if followed by the condition, a colon, the consequent, and optionally else with an alternative.

if true: 1 else 0        ; evaluates to 1
if false: 1 else 0       ; evaluates to 0
if 5 > 3: 10 else 20     ; evaluates to 10

If expressions can be nested:

if false: 1 else if true: 2 else 3  ; evaluates to 2

Match Expressions

Match expressions compare a value against multiple cases. The syntax is match followed by the scrutinee, a colon, one or more case branches, and optionally else.

match 2: case 1: 10 case 2: 20 else 0  ; evaluates to 20
match 5: case 1: 10 else 0              ; evaluates to 0

Multiple cases can share the same branch:

match 2: case 1 case 2: "one or two" else "other"

Choose Expressions

Choose expressions pattern match on union types, allowing different code paths based on which variant is present.

Choose on Variant Construction

Choose can match directly on constructed variants.

InputResult
define Option union(Some: int, None)
choose Option.Some(7): when v: Some: v else 0
7
define Option union(Some: int, None)
choose Option.None: when v: Some: v else 0
0

Choose with Binding

When a variant carries a value, the value can be bound to a name.

InputResult
define Result union(Ok: int, Err: int)
choose Result.Ok(42): when x: Ok: x + 1 else 0
43

Multiple When Clauses

Choose can have multiple when clauses to match different variants.

InputResult
define Result union(Ok: int, Err: int)
choose Result.Ok(10): when x: Ok: x when e: Err: e + 100
10
define Result union(Ok: int, Err: int)
choose Result.Err(5): when x: Ok: x when e: Err: e + 100
105

Optional Types

Optional types use null pointer optimization (NPO) for efficient representation.

Is Null Check

The is null expression checks if an optional value is None.

InputResult
define Option[T] union: (Some: T, None)
function check(x: int?) returns int: if x is null: 0 else 1
check(Option[int].None)
0
define Option[T] union: (Some: T, None)
function check(x: int?) returns int: if x is null: 0 else 1
check(Option[int].Some(42))
1

Optional Type Sugar

T? is syntactic sugar for Option[T].

InputResult
define Option[T] union: (Some: T, None)
function unwrap(x: int?) returns int: choose x: when v: Some: v else 0
unwrap(Option[int].Some(42))
42

Generic Option Types

Generic unions like Option[T] work with choose for pattern matching.

InputResult
define Option[T] union: (Some: T, None)
choose Option[int].Some(42): when v: Some: v else 0
42
define Option[T] union: (Some: T, None)
choose Option[int].None: when v: Some: v else -1
-1

Variant Construction

Union variants can be constructed explicitly using Type.Variant syntax.

Construct Variants

Variants are constructed with Type.Variant(value) syntax.

InputResult
define Result union: (Ok: int, Error: int)
choose Result.Ok(42): when x: Ok: x else 0
42
define Result union: (Ok: int, Error: int)
choose Result.Error(100): when e: Error: e else 0
100

Variant Is Expression

The is expression tests if a union value matches a variant.

InputResult
define Result union: (Ok: int, Error: int)
if Result.Ok(50) is Ok : 1 else 0
1
define Result union: (Ok: int, Error: int)
if Result.Error(33) is Ok : 1 else 0
0