Chapter 5 Expressions

Table of Contents
Overview
Literals
Operations
If Expressions
Match Expressions
Choose Expressions

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.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 chain left-to-right. Each operator takes the current value and the next operand, producing a new value. There is no operator precedence built into the language itself. Operator precedence is built into the implementation of the individual operators. The common arithmetic operators are built into the standard library.

InputResult
3 + 47
10 - 37
6 * 742
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

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, binding the inner value to a variable.

Basic Choose

Choose expressions match on the variant of a union value and bind the inner value.

InputResult
define Option union(Some: int, None)
choose Some(5): when v: Some: v + 1 else 0
6
define Option union(Some: int, None)
choose None: when v: Some: v else -1
-1
define Option union(Some: int, None)
let x Some(10)
choose x: when v: Some: v * 2 else 0
20

Choose with Result

Choose works with any union type, including Result.

InputResult
define Result union(Ok: int, Err: String)
choose Ok(42): when v: Ok: v when e: Err: 0 else -1
42
define Result union(Ok: int, Err: String)
choose Err("error"): when v: Ok: v when e: Err: 0 else -1
0

Choose Else Branch

The else branch is evaluated when no when clause matches.

InputResult
define Option union(Some: int, None)
choose None: when v: Some: v else 99
99