# Semantics

This document defines the currently implemented user-visible structural meaning of Masterbelt programs after syntax is parsed.

The semantic model is intentionally minimal at this stage. Future semantic additions must extend this document before or together with implementation changes.

## Source Files

A source file evaluates to ordered declarations and statements.

Line comments and block comments have no semantic value. They remain available to syntax tooling but do not appear in the semantic program structure.

## Analysis

Analysis parses a source file, resolves names, and type checks the resolved file.

Analysis returns diagnostics from each implemented phase in phase order: syntax parsing, name resolution, then type checking.

At this stage, analysis may continue after an earlier phase reports diagnostics when that phase produced a partial result. Later diagnostics are still reported, but callers must treat any error diagnostic as making the source unacceptable for operations that require a trustworthy checked program.

## Documentation Comments

Documentation comments attach to the declaration or statement that immediately follows them in the syntax tree.

Multiple documentation comments attached to the same declaration or statement preserve source order.

Documentation comments inside grouped const declarations attach to the const item that immediately follows them.

The text of a documentation comment is the source text after the leading `///`.

When a documentation comment line ends with carriage-return line feed, the carriage return is not part of the documentation text.

## Visibility Modifiers

A `pub` declaration is visible outside its source file. Without `pub`, a declaration is private to its file.

## Const Declarations

A const declaration binds one or more immutable names to initializer expressions.

The optional type annotation records the declared type for the const item. If no type annotation is written, the item type is inferred from the initializer expression.

Grouped const declarations apply the outer visibility to every item in the group. Documentation comments inside the group are item documentation and preserve source order.

## Type Declarations

A type declaration introduces a new name for a type expression. The declared type may carry zero or more type parameters; the body may be any nested type expression — product, union, generic, or any combination — and the declared name resolves through to that body at every use site.

The declared name and the target type expression are both stored in the resolved declaration. A `pub` type declaration is visible outside its file.

A type declaration does not introduce a value binding and does not evaluate to a runtime value.

## Failable Handling

Masterbelt is a DSL whose primary surface users are planners, not engineers. Exception-style control flow is therefore not part of the surface language: a `failable` call from a `failable` body looks and types like an ordinary call, and the failure path is plumbed transparently by the implementation.

A `failable` function may produce one of two outcomes per call: the declared success type `R`, or an `Error` value. The surface program never expresses the union directly:

- A `failable` function's declared return type is exactly its success type `R`. Call expressions of a `failable` function are typed `R`. The `Error` outcome is not visible at the type level.
- A `fail expression` statement completes the surrounding `failable` function with the Error outcome. When the expression is a `string`, the runtime constructs `Error { message: <string> }`; when it is an `Error` value, that value is used directly.
- A `return value` statement completes the function with the success outcome, carrying `value` (which must be assignable to `R`).
- When a `failable` call inside a `failable` body produces an `Error`, the surrounding function completes with that same `Error` automatically. No surface syntax marks this propagation, and no surface syntax can intercept it.

Every effect — `failable`, `asyncable`, `cancellable` — is inherited silently at call sites: a function that calls a callable carrying any effect behaves as if it carried the same effect, whether or not its own declaration mentions it. The surface program never has to express the obligation; each codegen target observes the call graph and lifts the obligation into the rendered signature (see [types.md](types.md#effect-inheritance)).

A `match` statement does not receive an `Error` arm for a `failable` call subject, because the call's surface type is `R`. The built-in `Error` product type remains available only as the argument to `fail`.

The evaluator and every codegen target observe these semantics through their native error-passing idioms (see [codegen/golang.md](../codegen/golang.md#failable-handling), [codegen/typescript.md](../codegen/typescript.md#failable-handling), and [codegen/csharp.md](../codegen/csharp.md#failable-handling)). Those idioms are an implementation concern; they must not leak into the surface program.

## For Statements

A `for` statement evaluates its subject expression exactly once. The result is a sequence of elements decided by the subject's type:

- A `list<T>` value yields its elements in stored order.
- A `map<K, V>` value yields its entries in insertion order. Each entry contributes two values, a key and a value, in that order.
- A `range(start, end)` call yields the integers `start, start + 1, ..., end - 1` in ascending order. When `start >= end`, no element is yielded.
- A `master.toList()` call yields the master's records in import order. Records dropped by the master's filter section are not yielded.

For each element, the bindings declared by the `for` clause are bound to the element's components in the order described above, then the function block is evaluated under a fresh scope. After the block completes, the next element is drawn; iteration ends when the subject is exhausted.

Bindings written as `_` discard the corresponding component. The body cannot observe a `_`-bound value.

A `break` statement terminates the iteration immediately and resumes after the `for` statement. A `continue` statement skips the remainder of the current iteration; the next element is drawn as usual. A `return` inside the body terminates the surrounding function the same way a top-level `return` would.

Mutation of the subject collection from within the body is unspecified behavior. Targets may evaluate the iteration over a live or snapshot view; programs must not rely on either choice.

## Match Statements

A `match` statement evaluates its subject expression exactly once, then selects at most one arm by walking the arms in source order:

1. The subject is tested against the arm's pattern.
2. When the pattern matches, the arm's guard expression (if any) is evaluated.
3. When the guard evaluates to `true` (or no guard is written), the arm's function block is evaluated. No subsequent arm is considered.
4. When the pattern does not match, or the guard evaluates to `false`, evaluation continues with the next arm.

Pattern matching is value-based: a type pattern observes the subject's runtime type; an enum pattern, literal pattern, or product pattern compares the subject to a value or structural shape. Bindings introduced by a matched pattern (`as name`, the short product-field form, or a nested binding) take effect before the guard expression is evaluated and remain in scope for the entire arm body.

A guard expression is an ordinary boolean expression; it may have side effects. The guard is evaluated at most once per arm and only when its arm's pattern matches.

The set of arms is exhaustive over the subject's static type: type checking guarantees that at least one arm matches every value of the subject's type, except when a guard restricts the matched set (see [types.md](types.md#match-statements)). When every arm's guard evaluates to `false` and no later unguarded arm covers the value, evaluation falls through the `match` statement without executing any arm body.

## Validation Blocks

A master's `validation` section declares named rules that run over the master's post-filter records during [`masterbelt export`](../tooling/cli.md), after import and filtering and before any artifact is written. A validation rule never drops a record; it inspects the data and emits diagnostics. The complete surface form, scoping, and severity model are defined in [masterdata/validation.md](../masterdata/validation.md).

A validation rule body is a statement block that "passes" when it runs to completion. It must not contain a `return`: a validation block has no value and the checker rejects `return` inside it. The block reports failures through `assert` instead.

An `all` rule binds the master's post-filter relation to `table` (and to its alias `self`). A `for row in table` statement iterates the relation's post-filter records the same way [For Statements](#for-statements) iterate a relation; because `table` is a relation, an `all` rule may also apply the master's scopes to it.

### Assert Statements

An `assert` statement evaluates its condition expression, which must be a boolean. `assert` is the validation primitive and is valid only inside a validation rule body.

A failing `assert` (a condition that evaluates to `false`) records one diagnostic and evaluation continues with the next statement. Unlike `fail` or `return`, an `assert` does not abort the surrounding block, so one rule can report several failures from several `assert` statements in a single pass.

## Scope Sections

A master's `scope` section declares a named, parameterisable relation query that surfaces as a method on the master's relation. A scope body builds and returns a `Relation<M>` without scanning records; it is effect-free and runs no terminal. The surface form, the `self` receiver, the relation query DSL, scope chaining, visibility, and the `indexed` modifier are defined in [masterdata/schema.md](../masterdata/schema.md#scope-section) and [masterdata/query.md](../masterdata/query.md#source-level-relation-queries); the type rules are defined in [types.md](types.md#scope-bodies); the evaluation model is defined in [evaluation.md](evaluation.md#scope-evaluation).

## Expression Statements

An expression statement evaluates its expression.

At this stage, expression statements do not bind names and do not produce declarations.

## Literals

Literal expressions evaluate to their literal values.

### Null Literal

`null` evaluates to the null value.

### Bool Literals

`true` evaluates to the boolean true value.

`false` evaluates to the boolean false value.

### Integer Literals

Integer literals evaluate to integer values.

Digit separators are ignored when determining the value.

The representable range and type assignment of integer literal values are defined by the type system.

Radix prefixes determine the base:

- `0b` and `0B` use base 2.
- `0o` and `0O` use base 8.
- `0x` and `0X` use base 16.
- Integer literals without a radix prefix use base 10, including zero-padded decimal literals.

### String Literals

String literals evaluate to string values.

Escape sequences are decoded when determining the string value.

## Collection Literals

A list literal evaluates to an ordered sequence of element values.

A map literal evaluates to a mapping from key values to value values. When two map entries have equal keys, the entry that appears later in the source replaces the earlier one. This rule applies to both literal and computed keys.

An empty collection literal evaluates to an empty list or an empty map depending on the resolved type as determined by [Collection Literal Types](types.md#collection-literal-types).
