Glass language reference

Glass is a deterministic, small imperative language for inspecting compilation and execution.

Values and names

Expressions

Highest precedence first:

Syntax Meaning
Parentheses, calls Explicit grouping; square(12)
** Power; right-associative
Unary !, +, - Boolean negation or numeric sign
*, /, % Numeric multiply, divide, remainder
+, - Numeric add and subtract
<, <=, >, >= Numeric comparison
==, != Strict value equality, without coercion
&& Boolean and; skips the right side when false
`

-2 ** 2 is -4; 2 ** 3 ** 2 is 512. Division and remainder by zero are errors. Arithmetic requires numbers and never coerces strings or booleans.

Statements

program    → statement*
statement  → "let" name "=" expression ";"
           | name "=" expression ";"
           | "if" "(" expression ")" block ("else" (block | if))?
           | "while" "(" expression ")" block
           | "fn" name "(" parameters? ")" block
           | "return" expression? ";"
           | expression ";"
           | block
block      → "{" statement* "}"

Blocks create scopes. Each loop iteration creates a new body scope. else if is supported. Comments start with // and continue to the end of the line. Semicolons are required after declarations, assignments, expression statements, and returns.

Functions

Declare functions at the top level. Declarations are hoisted, so calls may precede them. Calls accept exactly the declared number of arguments. Arguments are evaluated left to right. Functions can recurse and mutate initialized globals. Their scopes link to lexical globals, never to the caller’s local variables.

fn factorial(n) {
  if (n <= 1) { return 1; }
  return n * factorial(n - 1);
}
print(factorial(6));

return unwinds all local scopes of the current call. A missing result or fall-through return yields 0. Nested function declarations, first-class functions, and closures are not part of Glass.

Builtins

Call Behavior
print(value) Append a value to the output log.
sin(x), cos(x) Trigonometry in radians.
radians(degrees) Convert degrees to radians.
sqrt(x), abs(x) Square root / absolute value.
floor(x), ceil(x), round(x) Standard numeric rounding.
min(a,b), max(a,b) Two numeric arguments.
hsl(h,s,l) A color string; hue wraps, saturation/lightness clamp to 0–100.
paper(color) Set background and clear existing shapes.
clear() Clear shapes, preserve background and ink.
ink(color, opacity?) Set pen color and optional opacity (clamped to 0–1; default 1).
circle(x,y,r) Filled circle, radius >= 0.
line(x1,y1,x2,y2,width) Line, width > 0.
rect(x,y,width,height) Filled rectangle with nonnegative dimensions.
frame() Increment the visual frame counter; animated execution yields here.

Drawing and output builtins return 0. Colors accept 3-, 6-, or 8-digit hex strings, black, white, transparent, or values made by hsl. Logical coordinates are 640 × 640, origin at top left. The renderer clips shapes at the canvas boundary. Drawing coordinates and sizes are bounded to ±100,000. The reference grid is independent of the program.

Debugging semantics

The compiler emits a LINE marker before executable statements and at every loop condition. Breakpoints stop before executing a matching marker. Run from a breakpoint skips that one marker once, then can stop at it on the next iteration. A line with only a comment, brace, or part of a multiline expression has no independent statement marker; set the breakpoint at the statement’s first line.

Step executes one opcode. Step line executes through to the next statement marker. A recursive call may therefore step into its function body. Function entry itself is an ENTER instruction. The current instruction’s source span drives the source and inspector highlights.

Time travel restores an exact retained snapshot, including drawings and errors. The trace displays retained checkpoints around the current position; long runs sample older checkpoints. Stepping or running after a rewind truncates future history. Reset starts the same compiled program from its initial state.

Bounds

60,000 executed instructions; 32 call frames including main; 2,000 active drawing primitives; 300 printed values; 1,600 snapshots; 24,000 source characters; 8,000 tokens; parser nesting depth 100; compiler expression depth 160. Limits produce helpful diagnostics. They do not execute host code or access external resources.

# Glass language reference

Glass is a deterministic, small imperative language for inspecting compilation and execution.

## Values and names

- IEEE-754 finite numbers, including decimals and scientific notation (`1.2e2`). Non-finite results stop the VM.
- Strict booleans `true` and `false`. A number is never silently used as a condition.
- Single- or double-quoted strings. Escapes: `\n`, `\t`, `\r`, `\\`, and escaped quotes.
- ASCII names beginning with a letter or underscore. Later characters can include digits.
- `let name = expression;` declares a variable. `name = expression;` updates the nearest lexical binding.
- A name must be declared before use in a main-program scope. Function bodies may reference top-level globals; those globals must be initialized before the function reads them.
- Redeclaring a name in the same scope is an error. Blocks can shadow outer variables. Callable names are reserved against variable declarations.

## Expressions

Highest precedence first:

| Syntax | Meaning |
| --- | --- |
| Parentheses, calls | Explicit grouping; `square(12)` |
| `**` | Power; right-associative |
| Unary `!`, `+`, `-` | Boolean negation or numeric sign |
| `*`, `/`, `%` | Numeric multiply, divide, remainder |
| `+`, `-` | Numeric add and subtract |
| `<`, `<=`, `>`, `>=` | Numeric comparison |
| `==`, `!=` | Strict value equality, without coercion |
| `&&` | Boolean and; skips the right side when false |
| `||` | Boolean or; skips the right side when true |

`-2 ** 2` is `-4`; `2 ** 3 ** 2` is `512`. Division and remainder by zero are errors. Arithmetic requires numbers and never coerces strings or booleans.

## Statements

```text
program    → statement*
statement  → "let" name "=" expression ";"
           | name "=" expression ";"
           | "if" "(" expression ")" block ("else" (block | if))?
           | "while" "(" expression ")" block
           | "fn" name "(" parameters? ")" block
           | "return" expression? ";"
           | expression ";"
           | block
block      → "{" statement* "}"
```

Blocks create scopes. Each loop iteration creates a new body scope. `else if` is supported. Comments start with `//` and continue to the end of the line. Semicolons are required after declarations, assignments, expression statements, and returns.

## Functions

Declare functions at the top level. Declarations are hoisted, so calls may precede them. Calls accept exactly the declared number of arguments. Arguments are evaluated left to right. Functions can recurse and mutate initialized globals. Their scopes link to lexical globals, never to the caller’s local variables.

```glass
fn factorial(n) {
  if (n <= 1) { return 1; }
  return n * factorial(n - 1);
}
print(factorial(6));
```

`return` unwinds all local scopes of the current call. A missing result or fall-through return yields `0`. Nested function declarations, first-class functions, and closures are not part of Glass.

## Builtins

| Call | Behavior |
| --- | --- |
| `print(value)` | Append a value to the output log. |
| `sin(x)`, `cos(x)` | Trigonometry in radians. |
| `radians(degrees)` | Convert degrees to radians. |
| `sqrt(x)`, `abs(x)` | Square root / absolute value. |
| `floor(x)`, `ceil(x)`, `round(x)` | Standard numeric rounding. |
| `min(a,b)`, `max(a,b)` | Two numeric arguments. |
| `hsl(h,s,l)` | A color string; hue wraps, saturation/lightness clamp to 0–100. |
| `paper(color)` | Set background and clear existing shapes. |
| `clear()` | Clear shapes, preserve background and ink. |
| `ink(color, opacity?)` | Set pen color and optional opacity (clamped to 0–1; default 1). |
| `circle(x,y,r)` | Filled circle, radius >= 0. |
| `line(x1,y1,x2,y2,width)` | Line, width > 0. |
| `rect(x,y,width,height)` | Filled rectangle with nonnegative dimensions. |
| `frame()` | Increment the visual frame counter; animated execution yields here. |

Drawing and output builtins return `0`. Colors accept 3-, 6-, or 8-digit hex strings, `black`, `white`, `transparent`, or values made by `hsl`. Logical coordinates are 640 × 640, origin at top left. The renderer clips shapes at the canvas boundary. Drawing coordinates and sizes are bounded to ±100,000. The reference grid is independent of the program.

## Debugging semantics

The compiler emits a `LINE` marker before executable statements and at every loop condition. Breakpoints stop **before** executing a matching marker. Run from a breakpoint skips that one marker once, then can stop at it on the next iteration. A line with only a comment, brace, or part of a multiline expression has no independent statement marker; set the breakpoint at the statement’s first line.

Step executes one opcode. Step line executes through to the next statement marker. A recursive call may therefore step into its function body. Function entry itself is an `ENTER` instruction. The current instruction’s source span drives the source and inspector highlights.

Time travel restores an exact retained snapshot, including drawings and errors. The trace displays retained checkpoints around the current position; long runs sample older checkpoints. Stepping or running after a rewind truncates future history. Reset starts the same compiled program from its initial state.

## Bounds

60,000 executed instructions; 32 call frames including main; 2,000 active drawing primitives; 300 printed values; 1,600 snapshots; 24,000 source characters; 8,000 tokens; parser nesting depth 100; compiler expression depth 160. Limits produce helpful diagnostics. They do not execute host code or access external resources.