§4 Syntactic grammar
This chapter defines Bynk’s phrase structure: how tokens (§3) combine into declarations, types, expressions, patterns, and statements. Each production is generated from the grammar (§2.1) and embedded by name.
A production states what parses. Every constraint beyond parsing — name resolution, typing, exhaustiveness, refinement admission, the effect discipline, and all other well-formedness — is a static-semantics rule, specified normatively in §5 and not repeated here. Where a construct carries such constraints, this chapter forward-references §5 rather than restating them.
The chapters mirror the construct groupings of the friendly grammar reference; the productions are shared, the register here is the normative definition.
§4.1 Top-level & modules
Section titled “§4.1 Top-level & modules”A source file is a commons, a context, an adapter, or test declarations.
§4.1.1 source_file
Section titled “§4.1.1 source_file”source_file ::= (commons_decl | context_decl | adapter_decl | integration_decl | test_decl)+ | item_fragment+ | expr_fragmentA whole file: one or more top-level declarations, or a single fragment used by editor tooling.
§4.1.2 item_fragment
Section titled “§4.1.2 item_fragment”item_fragment ::= context_body_item | handler | store_field | key_declA tooling entry point: a single body item parsed in isolation. Not written by hand.
§4.1.3 expr_fragment
Section titled “§4.1.3 expr_fragment”expr_fragment ::= statement+ expression? | expressionA tooling entry point: statements and/or an expression parsed in isolation. Not written by hand.
§4.1.4 commons_decl
Section titled “§4.1.4 commons_decl”commons_decl ::= "commons" qualified_name ("{" commons_body_item* "}" | commons_body_item*)A commons module. The body braces are optional at file scope; with no braces
the body items run to the end of the file.
§4.1.5 context_decl
Section titled “§4.1.5 context_decl”context_decl ::= "context" qualified_name ("{" context_body_item* "}" | context_body_item*)A context. As with commons, the body braces are optional at file scope.
Well-formedness: §5.
§4.1.6 adapter_decl
Section titled “§4.1.6 adapter_decl”adapter_decl ::= "adapter" qualified_name ("{" adapter_body_item* "}" | adapter_body_item*)An adapter — the host boundary: a capability contract co-located with a named
TypeScript binding. As with commons, the body braces are optional at file
scope. An adapter’s providers are external (bodiless,
§4.3.8) and it may not declare services or agents; those
placement rules, the binding requirement, and the reserved bynk namespace are
well-formedness: §5.
§4.1.7 test_decl
Section titled “§4.1.7 test_decl”test_decl ::= "test" qualified_name ("{" test_body_item* "}" | test_body_item*)A test block naming the commons or context it targets. Well-formedness: §5.
§4.1.8 integration_decl
Section titled “§4.1.8 integration_decl”integration_decl ::= "test" "integration" string_literal ("{" wires_decl integration_body_item* "}" | wires_decl integration_body_item*)A test integration block: the keyword test integration, a name, a wires
clause, and integration body items. Well-formedness: §5.
§4.1.9 wires_decl
Section titled “§4.1.9 wires_decl”wires_decl ::= "wires" qualified_name ("," qualified_name)*The comma-separated list of contexts an integration test wires together. Well-formedness: §5.
§4.1.10 integration_body_item
Section titled “§4.1.10 integration_body_item”integration_body_item ::= uses_decl | test_caseWhat may appear in an integration test: uses declarations and test cases.
§4.1.11 commons_body_item
Section titled “§4.1.11 commons_body_item”commons_body_item ::= uses_decl | type_decl | fn_decl | capability_decl | provider_decl | service_decl | agent_decl | actor_declThe declaration forms admitted in a commons body.
§4.1.12 context_body_item
Section titled “§4.1.12 context_body_item”context_body_item ::= uses_decl | consumes_decl | exports_decl | type_decl | fn_decl | capability_decl | provider_decl | service_decl | agent_decl | actor_declThe declaration forms admitted in a context body, including consumes and
exports.
§4.1.13 adapter_body_item
Section titled “§4.1.13 adapter_body_item”adapter_body_item ::= binding_decl | uses_decl | consumes_decl | exports_decl | type_decl | fn_decl | capability_decl | provider_decl | service_decl | agent_decl | actor_declThe declaration forms admitted in an adapter body: the binding clause,
capability and type declarations, pure helpers and uses, consumes,
exports, and providers. The grammar is deliberately permissive — service and
agent parse here so the placement error can be precise; their rejection is
well-formedness: §5.
§4.1.14 test_body_item
Section titled “§4.1.14 test_body_item”test_body_item ::= uses_decl | consumes_decl | mocks_decl | test_caseThe declaration forms admitted in a test body, including mocks and test
cases.
§4.1.15 qualified_name
Section titled “§4.1.15 qualified_name”qualified_name ::= identifier ("." identifier)*A dotted sequence of identifiers, e.g. shop.orders. A dotted name is a single
flat identifier, not a hierarchy: bynk and bynk.time are independent
names that merely share a leading segment.
§4.1.16 uses_decl
Section titled “§4.1.16 uses_decl”uses_decl ::= "uses" qualified_nameuses followed by a qualified name. Well-formedness: §5.
§4.1.17 consumes_decl
Section titled “§4.1.17 consumes_decl”consumes_decl ::= "consumes" qualified_name ("as" identifier | "{" (identifier ("," identifier)*)? ","? "}")?consumes a unit, in one of three forms: the whole unit (consumes b), the
whole unit under an alias (consumes b as Alias), or a capability
selection (consumes b { Cap, … }), which flattens the named capabilities into
the consumer’s local capability namespace under their bare names. The target may
be a context or an adapter; which forms each consumer kind admits, and the
flattening and clash rules, are well-formedness: §5.
§4.1.18 exports_decl
Section titled “§4.1.18 exports_decl”exports_decl ::= "exports" ("opaque" | "transparent" | "capability") "{" (identifier ("," identifier)*)? ","? "}"exports, one of opaque / transparent / capability, and a brace-delimited
identifier list. Well-formedness: §5.
§4.1.19 binding_decl
Section titled “§4.1.19 binding_decl”binding_decl ::= "binding" string_literal ("requires" "{" (binding_requirement ("," binding_requirement)*)? ","? "}")?An adapter’s binding clause: the TypeScript module supplying its external
provider classes, as a string-literal path resolved relative to the adapter’s
source file, with an optional requires { … } map of npm dependencies.
Well-formedness: §5.
§4.1.20 binding_requirement
Section titled “§4.1.20 binding_requirement”binding_requirement ::= string_literal ":" string_literalOne "package": "range" entry in a binding’s requires map. Ranges MUST be
pinned; well-formedness: §5.
§4.2 Types & refinements
Section titled “§4.2 Types & refinements”Type declarations and the type references that appear in signatures.
§4.2.1 type_decl
Section titled “§4.2.1 type_decl”type_decl ::= "type" identifier "=" type_bodytype, a name, =, and a type body. Well-formedness: §5; the type system: §6.
§4.2.2 type_body
Section titled “§4.2.2 type_body”type_body ::= opaque_type | refined_type | record_type | sum_type | enum_typeThe right-hand side of a type: one of the five type forms.
§4.2.3 opaque_type
Section titled “§4.2.3 opaque_type”opaque_type ::= "opaque" base_type ("where" refinement)?opaque, a base type, and an optional where refinement.
§4.2.4 refined_type
Section titled “§4.2.4 refined_type”refined_type ::= base_type ("where" refinement)?A base type with an optional where refinement. Well-formedness: §5;
admission: §6.
§4.2.5 record_type
Section titled “§4.2.5 record_type”record_type ::= "{" (record_field ("," record_field)*)? ","? "}"A brace-delimited, comma-separated list of record fields, with an optional trailing comma.
§4.2.6 record_field
Section titled “§4.2.6 record_field”record_field ::= identifier ":" type_ref ("where" refinement)? ("=" expression)?A field name, :, a type, an optional inline where refinement, and an optional
= default expression. Well-formedness: §5.
§4.2.7 sum_type
Section titled “§4.2.7 sum_type”sum_type ::= sum_variant+One or more |-prefixed variants.
§4.2.8 sum_variant
Section titled “§4.2.8 sum_variant”sum_variant ::= "|" constant_name ("(" (variant_payload_field ("," variant_payload_field)*)? ","? ")")?A |, a constant name, and an optional parenthesised payload.
§4.2.9 variant_payload_field
Section titled “§4.2.9 variant_payload_field”variant_payload_field ::= identifier ":" type_refA named field in a sum-variant payload: an identifier, :, and a type.
§4.2.10 enum_type
Section titled “§4.2.10 enum_type”enum_type ::= "enum" "{" (constant_name ("," constant_name)*)? ","? "}"enum and a brace-delimited list of constant names — a sum type whose variants
all carry no payload.
§4.2.11 refinement
Section titled “§4.2.11 refinement”refinement ::= refinement_pred ("and" refinement_pred)*One or more predicates joined by and. Well-formedness: §5.
§4.2.12 refinement_pred
Section titled “§4.2.12 refinement_pred”refinement_pred ::= pred_call | predicate_nameA single predicate: a predicate call or a bare predicate name.
§4.2.13 pred_call
Section titled “§4.2.13 pred_call”pred_call ::= predicate_name "(" (pred_arg ("," pred_arg)*)? ")"A predicate name applied to parenthesised arguments, e.g. InRange(1, 100).
§4.2.14 predicate_name
Section titled “§4.2.14 predicate_name”predicate_name ::= "Matches" | "InRange" | "MinLength" | "MaxLength" | "Length" | "NonNegative" | "Positive" | "NonEmpty"The set of built-in refinement predicates. Well-formedness: §5.
§4.2.15 pred_arg
Section titled “§4.2.15 pred_arg”pred_arg ::= number_literal | float_literal | string_literalAn argument to a predicate: a number or string literal.
§4.2.16 base_type
Section titled “§4.2.16 base_type”base_type ::= "Int" | "String" | "Bool" | "Float" | "Duration" | "Instant"The primitive types Int, String, and Bool. Well-formedness: §5.
§4.2.17 type_ref
Section titled “§4.2.17 type_ref”type_ref ::= function_type_ref | base_type | unit_type | validation_error_type | generic_type_ref | identifierA type as it appears in a signature: a function type, a base type, the unit type, the validation-error type, a generic application, or a named type.
§4.2.17a function_type_ref
Section titled “§4.2.17a function_type_ref”function_type_ref ::= (base_type | unit_type | validation_error_type | generic_type_ref | identifier | "(" type_ref ("," type_ref)* ","? ")") "->" type_refA function type (v0.20a): Int -> Int, (Int, String) -> Bool, () -> Int.
The arrow is right-associative — A -> B -> C is A -> (B -> C) — and a
parenthesised list before -> is a parameter list (a single parenthesised
type without an arrow is a grouping; the empty () without an arrow stays
the unit type). A function type is effectful exactly when its return type
is Effect[_] — the structural rule of §6. Function types are confined to
non-boundary positions; well-formedness: §5.
§4.2.18 unit_type
Section titled “§4.2.18 unit_type”unit_type ::= "(" ")"The unit type ().
§4.2.19 validation_error_type
Section titled “§4.2.19 validation_error_type”validation_error_type ::= "ValidationError"ValidationError, the error type produced when refined-type validation fails.
§4.2.20 generic_type_ref
Section titled “§4.2.20 generic_type_ref”generic_type_ref ::= ("Result" | "Option" | "Effect" | "HttpResult" | "List" | "Map" | "Stream" | "Query" | "Connection") "[" type_ref ("," type_ref)* "]"A generic constructor — Result, Option, Effect, HttpResult, or
(v0.20b) List, Map — applied to bracketed type arguments.
Well-formedness: §5 (Map keys are value-keyable,
§5.10); the type system: §6.
§4.3 Functions, capabilities & providers
Section titled “§4.3 Functions, capabilities & providers”Pure functions and methods, capability interfaces, and the providers that implement them.
§4.3.1 fn_decl
Section titled “§4.3.1 fn_decl”fn_decl ::= "fn" (method_name | identifier) ("[" identifier ("," identifier)* "]")? "(" params? ")" "->" type_ref blockfn, a function name or a Type.method name, an optional [A, B]
type-parameter list (v0.20a — free functions only; a type parameter is an
unconstrained, bound-free name scoped to the signature and body), a parameter
list, ->, a return type, and a block body. Well-formedness: §5.
§4.3.2 method_name
Section titled “§4.3.2 method_name”method_name ::= identifier "." identifierA Type.method name, defining a method on a named type.
§4.3.3 params
Section titled “§4.3.3 params”params ::= (self_param | param) ("," param)* ","?A parameter list: an optional self receiver followed by named parameters, with
an optional trailing comma.
§4.3.4 self_param
Section titled “§4.3.4 self_param”self_param ::= "self"The self receiver of a method or handler.
§4.3.5 param
Section titled “§4.3.5 param”param ::= identifier ":" type_refOne parameter: an identifier, :, and a type. Well-formedness: §5.
§4.3.6 capability_decl
Section titled “§4.3.6 capability_decl”capability_decl ::= "capability" identifier "{" capability_op* "}"capability, a name, and a brace-delimited list of operation signatures.
Well-formedness: §5.
§4.3.7 capability_op
Section titled “§4.3.7 capability_op”capability_op ::= "fn" identifier "(" (param ("," param)*)? ","? ")" "->" type_refOne operation in a capability: fn, a name, parameters, ->, and a return type
— no body. Well-formedness: §5.
§4.3.8 provider_decl
Section titled “§4.3.8 provider_decl”provider_decl ::= "provides" identifier "=" identifier given_clause? ("{" provider_op* "}")?provides, the capability name, =, an implementation name, an optional given
clause, and an optional brace-delimited list of operation implementations.
The presence of the brace block distinguishes the two provider kinds: with a
block the provider is implemented in Bynk (context-only); with no block it is
external — its implementation is the named class exported by the enclosing
adapter’s binding module (§4.1.19). The absence of the
block, not an empty one, is the signal. Placement and wiring rules:
well-formedness, §5.
§4.3.9 provider_op
Section titled “§4.3.9 provider_op”provider_op ::= "fn" identifier "(" (param ("," param)*)? ","? ")" "->" type_ref blockOne operation implementation: a capability operation signature with a block body. Well-formedness: §5.
§4.3.10 given_clause
Section titled “§4.3.10 given_clause”given_clause ::= "given" qualified_name ("," qualified_name)*given and a comma-separated list of the capabilities a handler or provider may
use. Well-formedness: §5.
§4.4 Services & handlers
Section titled “§4.4 Services & handlers”A service groups the handlers that respond to calls and external triggers.
§4.4.1 service_decl
Section titled “§4.4.1 service_decl”service_decl ::= "service" identifier service_protocol? "{" handler* "}"service, a name, an optional from <protocol> header clause, and a
brace-delimited list of handlers. One protocol per service. Well-formedness: §5.
§4.4.2 service_protocol
Section titled “§4.4.2 service_protocol”service_protocol ::= "from" ("http" | "cron" | "queue" "(" string_literal ")" | "WebSocket" "(" "in" ":" type_ref "," "out" ":" type_ref ","? ")")The from <protocol> clause: from http, from cron, from queue("name")
(v0.44), or from WebSocket(in: I, out: O) (v0.103). Absent ⇒ the
contract-mediated default, which admits only on call. Well-formedness: §5.
§4.4.2a handler
Section titled “§4.4.2a handler”handler ::= call_handler | http_handler | cron_handler | queue_handler | ws_open_handler | ws_close_handlerA handler: a call, HTTP, cron, or queue entry point, matching the service’s protocol. Well-formedness: §5.
§4.4.3 call_handler
Section titled “§4.4.3 call_handler”call_handler ::= "on" "call" identifier? by_clause? "(" (param ("," param)*)? ","? ")" "->" type_ref given_clause? blockon call, an optional name, parameters, ->, a return type, an optional given
clause, and a block body.
§4.4.4 http_handler
Section titled “§4.4.4 http_handler”http_handler ::= "on" http_method "(" string_literal ")" by_clause? "(" (param ("," param)*)? ","? ")" "->" type_ref given_clause? blockon <Method>("route") — an HTTP method-builder (the verb collapses verb+route
into one config expression in the handler-config slot), then parameters, ->, a
return type, an optional given clause, and a block body. Valid only in a
from http service. Well-formedness: §5.
§4.4.5 http_method
Section titled “§4.4.5 http_method”http_method ::= "GET" | "POST" | "PUT" | "PATCH" | "DELETE"The HTTP verbs a route may handle. Well-formedness: §5.
§4.4.6 cron_handler
Section titled “§4.4.6 cron_handler”cron_handler ::= "on" "schedule" "(" string_literal ")" by_clause? "(" (param ("," param)*)? ","? ")" "->" type_ref given_clause? blockon schedule("expr"), parameters, ->, a return type, an optional given
clause, and a block body. Valid only in a from cron service. Well-formedness: §5.
§4.4.7 queue_handler
Section titled “§4.4.7 queue_handler”queue_handler ::= "on" "message" by_clause? "(" (param ("," param)*)? ","? ")" "->" type_ref given_clause? blockon message(message) — the bound queue lives on the service’s from queue("name") header. Parameters, -> Effect[QueueResult], an optional
given clause, and a block body. Well-formedness: §5.
§4.4.7a WebSocket handlers (v0.103)
Section titled “§4.4.7a WebSocket handlers (v0.103)”A from WebSocket(in: I, out: O) service declares the connection-lifecycle
handlers on open, on message, and on close. Each is a handler head — on,
the lifecycle keyword, a required by_clause naming the actor,
parameters, -> Effect[()], an optional given clause, and a block body — and
is valid only in a from WebSocket service:
on open— the upgrade handshake; the body sees an ownedconnectionbinding of typeConnection[O].on message— parameters end with the decoded inbound frame of typeI.on close— the connection ended.
Well-formedness — exactly one on open, edge authentication, held-resource
disposal: §5. (The rendered grammar productions for these handler heads land with
the tree-sitter grammar; see Reference — grammar.)
§4.4.8 by_clause (v0.45)
Section titled “§4.4.8 by_clause (v0.45)”by_clause ::= "by" (identifier ":")? identifier ("|" identifier)*by (<binder>:)? <Actor> ("|" <Actor>)* — the actor(s) a handler consumes,
positioned after the protocol config and before the parameters
(on schedule("…") by s: Scheduler () -> …). The binder is optional (v0.50):
by <name>: <Actor> captures the verified identity (read as <name>.identity);
by <Actor> declares-and-verifies the contract without capturing it (anonymous
or verify-and-discard). Omitting by entirely inherits the protocol’s default
actor; on a from http handler by is required (the binder still optional).
A |-separated list of actors (v0.52) is an ordered sum of peer actors
(by who: User | Visitor): the boundary tries each peer’s scheme in declared
order and binds the first that verifies; the body matches on the resolved
actor (the binder is required for a sum). Well-formedness: §5.
An actor is a nominal boundary contract — a closed, compiler-known
authentication scheme plus an optional sealed identity — consumed by a handler’s
by clause (§4.4.8). Actors are context-only.
§4.4.9 actor_decl (v0.45)
Section titled “§4.4.9 actor_decl (v0.45)”actor_decl ::= "actor" identifier ("{" "auth" "=" scheme scheme_config? ("," "identity" "=" type_ref)? "}" | "=" identifier "where" refinement)actor <Name> { auth = <Scheme> }, optionally , identity = <Type>. The
refinement form actor <Name> = <Base> where <predicate> (v0.53) declares an
authorisation invariant over a Bearer base; the predicate is a closed set of
claim predicates (hasClaim, claimEquals). Well-formedness: §5.
§4.4.10 scheme
Section titled “§4.4.10 scheme”scheme ::= "None" | "Internal" | "Bearer" | "Signature"The closed authentication-scheme set. None, Internal, Bearer, and
Signature (v0.51) are supported. The authenticated schemes carry a keyed-args
config — Bearer(secret = "<ENV>") and Signature(secret = "<ENV>", header = "<Header>", (timestamp = "<Header>", tolerance = <seconds>)?) — parsed by the
scheme_config production (string- or integer-valued args; the checker validates
which keys each scheme admits). Well-formedness: §5.
§4.5 Agents
Section titled “§4.5 Agents”An agent is a keyed, stateful entity whose state lives in store fields that
handlers read by name and write with :=.
§4.5.1 agent_decl
Section titled “§4.5.1 agent_decl”agent_decl ::= "agent" identifier "{" key_decl store_field* invariant_decl* handler* "}"agent, a name, and a body holding a key declaration, store fields, zero or
more invariants, and handlers — in that fixed order. Well-formedness: §5.
§4.5.2 key_decl
Section titled “§4.5.2 key_decl”key_decl ::= "key" identifier ":" type_refkey, an identifier, :, and a type — the agent’s identity.
§4.5.2a store_field
Section titled “§4.5.2a store_field”store_field ::= "store" identifier ":" store_kind store_annotation* ("=" expression)?store, a name, :, a store_kind over its type parameters,
zero or more store_annotations, and an optional =
initialiser — a persistent field of the agent. Well-formedness — required initial
value, kind validity: §5 (ADR 0108).
§4.5.2b store_kind
Section titled “§4.5.2b store_kind”store_kind ::= identifier ("[" type_ref ("," type_ref)* "]")?The closed catalogue of storage kinds: Cell, Map, Set, Cache, Log. The
catalogue is closed — there is no Queue storage kind (ADR 0122).
§4.5.2c store_annotation
Section titled “§4.5.2c store_annotation”store_annotation ::= "@" identifier ("(" (annotation_arg ("," annotation_arg)*)? ","? ")")?A @name(args) annotation between the kind and the initialiser — @ttl (on
Cache), @retain (on Log), @indexed (on Map), @bounded. Arguments are
compile-time literals. Well-formedness — kind match, known name: §5 (ADR 0111).
§4.5.3 invariant_decl (v0.80)
Section titled “§4.5.3 invariant_decl (v0.80)”invariant_decl ::= "invariant" identifier ":" expressioninvariant, a name, :, and a predicate expression — a universally-quantified
property that must hold of every committed state. Invariants form a phase between
the store fields and the handlers; one after a handler is a parse error
(bynk.parse.invariant_after_handler). The predicate references the agent’s
store fields by bare name. Well-formedness — purity, Bool type,
agent-locality: §5 (ADR 0107).
§4.6 Expressions
Section titled “§4.6 Expressions”Bynk is expression-oriented: a block’s value is its final expression. Operator
precedence is fixed by the binary_expr production (§4.6.7).
§4.6.1 expression
Section titled “§4.6.1 expression”expression ::= if_expr | match_expr | is_expr | assert_expr | binary_expr | unary_expr | primaryAny expression: control flow, a refinement check, an operator expression, or a primary.
§4.6.2 primary
Section titled “§4.6.2 primary”primary ::= lambda_expr | paren_expr | method_call | field_access | call | record_construction | record_spread | question_expr | ok_expr | err_expr | some_expr | none_expr | effect_pure_expr | mock_expr | list_literal | block | number_literal | float_literal | string_literal | boolean_literal | unit_literal | self_expr | identifierThe atomic and postfix expressions: literals, names, calls, field and method access, constructors, and parenthesised expressions.
§4.6.3 if_expr
Section titled “§4.6.3 if_expr”if_expr ::= "if" expression block "else" (if_expr | block)if, a condition, a block, else, and either a further if or a block. The
else arm is not optional. Well-formedness: §5.
§4.6.4 match_expr
Section titled “§4.6.4 match_expr”match_expr ::= "match" expression "{" match_arm* "}"match, a scrutinee, and a brace-delimited list of match arms. Well-formedness —
including exhaustiveness: §5.
§4.6.5 is_expr
Section titled “§4.6.5 is_expr”is_expr ::= expression "is" patternAn expression, is, and a pattern. Well-formedness — including the narrowing it
introduces: §5.
§4.6.6 binary_expr
Section titled “§4.6.6 binary_expr”binary_expr ::= expression "implies" expression | expression "||" expression | expression "&&" expression | expression ("==" | "!=") expression | expression ("<" | "<=" | ">" | ">=") expression | expression ("+" | "-") expression | expression ("*" | "/") expressionThe binary operators, listed from lowest precedence (implies, then ||) to
highest (*, /); the production order is the precedence order. implies
(v0.80) is logical implication, right-associative, P implies Q ≡ !P || Q.
Well-formedness: §5.
§4.6.7 unary_expr
Section titled “§4.6.7 unary_expr”unary_expr ::= ("!" | "-") expressionLogical negation ! and numeric negation -, prefixed to an expression.
§4.6.8 method_call
Section titled “§4.6.8 method_call”method_call ::= primary "." identifier ("[" type_ref ("," type_ref)* "]")? "(" (expression ("," expression)*)? ","? ")"A receiver, ., a method name, and parenthesised arguments. Well-formedness: §5.
v0.22a: the numeric base-type keywords Int and Float are admitted in
static-receiver position — Int.parse(s) / Float.parse(s) — but only
when immediately followed by .; a bare Int in expression position remains
a parse error. (List.empty() needs no such rule: List is lexically an
ordinary identifier.)
v0.22b: a method call accepts explicit type arguments —
Json.decode[Order](s) — under the same same-line-[ rule as call type
application (0039): a [ opening a new line is a list literal. In v0.22b
only the Json.decode static consumes them; type arguments on any other
method are bynk.generics.type_arg_mismatch (generic user methods remain
deferred). The bare name[T] value form stays reserved.
§4.6.9 field_access
Section titled “§4.6.9 field_access”field_access ::= primary "." identifierA receiver, ., and a field name. Well-formedness: §5.
§4.6.9a lambda_expr
Section titled “§4.6.9a lambda_expr”lambda_expr ::= "(" (lambda_param ("," lambda_param)*)? ")" "=>" (expression | block)A lambda (v0.20a): (o) => o.paid, (acc, t) => acc + t, () => 0, or with
a block body (o) => { … }. Always parenthesised; => is the value
arrow, shared with match arms — -> stays the type arrow. Well-formedness
(contextual parameter typing, the unannotated rule, bottom-up effectfulness):
§5.
§4.6.9b lambda_param
Section titled “§4.6.9b lambda_param”lambda_param ::= identifier (":" type_ref)?One lambda parameter with an optional type annotation — optional because an expected function type supplies it; required in unconstrained positions (§5).
§4.6.10 call
Section titled “§4.6.10 call”call ::= identifier ("[" type_ref ("," type_ref)* "]")? "(" (expression ("," expression)*)? ","? ")"A name, optional bracketed type arguments (v0.20a, name[T](…) — the
explicit-instantiation form; a bare name[T] without an argument list is a
reserved parse error), and parenthesised arguments — a function call, a
variant construction, an agent instantiation, or (v0.20a) the application
of a function-typed value in scope. Well-formedness: §5.
§4.6.11 record_construction
Section titled “§4.6.11 record_construction”record_construction ::= identifier "{" (field_init ("," field_init)*)? ","? "}"A type name and a brace-delimited list of field initialisers. Well-formedness: §5.
§4.6.12 field_init
Section titled “§4.6.12 field_init”field_init ::= identifier ":" expression | identifierOne field of a record construction: name: value, or the shorthand name.
§4.6.13 record_spread
Section titled “§4.6.13 record_spread”record_spread ::= identifier "{" "..." expression ("," field_init)* ","? "}" | "{" "..." expression ("," field_init)* ","? "}"A ... spread of an existing record, optionally overriding fields, with or
without a leading type name. Well-formedness: §5.
§4.6.14 question_expr
Section titled “§4.6.14 question_expr”question_expr ::= expression "?"An expression followed by ?. Well-formedness: §5.
§4.6.15 ok_expr
Section titled “§4.6.15 ok_expr”ok_expr ::= "Ok" "(" expression ")"Ok(…) — the success constructor of Result or HttpResult. Well-formedness:
§5.
§4.6.16 err_expr
Section titled “§4.6.16 err_expr”err_expr ::= "Err" "(" expression ")"Err(…) — the failure constructor of Result. Well-formedness: §5.
§4.6.17 some_expr
Section titled “§4.6.17 some_expr”some_expr ::= "Some" "(" expression ")"Some(…) — the present constructor of Option. Well-formedness: §5.
§4.6.18 none_expr
Section titled “§4.6.18 none_expr”none_expr ::= "None"None — the absent constructor of Option.
§4.6.19 effect_pure_expr
Section titled “§4.6.19 effect_pure_expr”effect_pure_expr ::= "Effect" "." "pure" "(" expression ")"Effect.pure(…) — lifts a pure value into an Effect.
§4.6.20 mock_expr
Section titled “§4.6.20 mock_expr”mock_expr ::= "Mock" "[" type_ref "]" mock_arg?Mock[T] with an optional pin argument. Well-formedness — including that it is
valid only in test bodies: §5.
§4.6.21 mock_arg
Section titled “§4.6.21 mock_arg”mock_arg ::= "(" expression ("," expression)* ","? ")" | "{" (field_init ("," field_init)*)? ","? "}"The pin to a Mock[T]: positional arguments or a brace-delimited record of field
pins.
§4.6.21a list_literal
Section titled “§4.6.21a list_literal”list_literal ::= "[" (expression ("," expression)* ","?)? "]"(v0.20b) [a, b, c], with an optional trailing comma — a leading [
in expression position. It does not collide with explicit type application
(name[T](…), §4.6.10): that [ is a postfix form on a
callee identifier and MUST sit on the same line as it — a [ opening a
new line starts a list literal. There is no Map literal ({ } is records
and blocks) and no indexing form (get(i) returns Option[T]).
Well-formedness — including empty-literal element-type inference:
§5.10.
§4.6.22 paren_expr
Section titled “§4.6.22 paren_expr”paren_expr ::= "(" expression ")"A parenthesised expression, for grouping.
§4.6.23 self_expr
Section titled “§4.6.23 self_expr”self_expr ::= "self"self — the receiver inside a method or agent handler. Well-formedness: §5.
§4.7 Patterns & matching
Section titled “§4.7 Patterns & matching”The patterns used in match arms and is checks.
§4.7.1 match_arm
Section titled “§4.7.1 match_arm”match_arm ::= pattern "=>" expression ","?A pattern, =>, a result expression, and an optional trailing comma — arm
separators are optional. Well-formedness: §5.
§4.7.2 pattern
Section titled “§4.7.2 pattern”pattern ::= wildcard_pattern | variant_patternA pattern: a wildcard or a variant pattern.
§4.7.3 variant_pattern
Section titled “§4.7.3 variant_pattern”variant_pattern ::= (identifier ".")? identifier ("(" (pattern_binding ("," pattern_binding)*)? ","? ")")?A constant name, optionally qualified, with an optional parenthesised list of bindings. Well-formedness: §5.
§4.7.4 wildcard_pattern
Section titled “§4.7.4 wildcard_pattern”wildcard_pattern ::= "_"_ — matches anything and binds nothing.
§4.7.5 pattern_binding
Section titled “§4.7.5 pattern_binding”pattern_binding ::= named_binding | positional_bindingA binding within a variant pattern: named or positional.
§4.7.6 named_binding
Section titled “§4.7.6 named_binding”named_binding ::= identifier ":" (identifier | "_")Binds a payload field by name: field: name, or field: _ to ignore it.
§4.7.7 positional_binding
Section titled “§4.7.7 positional_binding”positional_binding ::= identifier | "_"Binds a payload field by position, or _ to ignore it.
§4.8 Statements
Section titled “§4.8 Statements”A block is a sequence of statements ending in an optional value expression.
§4.8.1 block
Section titled “§4.8.1 block”block ::= "{" statement* expression? "}"A brace-delimited sequence of statements with an optional trailing expression, which is the block’s value.
§4.8.2 statement
Section titled “§4.8.2 statement”statement ::= let_stmt | effect_let_stmt | effect_send_stmt | assign_stmt | assert_exprA statement: a let, an effectful let, an asynchronous send (~>), a :=
store write, or an assertion.
§4.8.3 let_stmt
Section titled “§4.8.3 let_stmt”let_stmt ::= "let" binding_name (":" type_ref)? "=" expressionlet, a binding name, an optional type annotation, =, and an expression.
Well-formedness: §5.
§4.8.4 effect_let_stmt
Section titled “§4.8.4 effect_let_stmt”effect_let_stmt ::= "let" binding_name (":" type_ref)? "<-" expressionlet, a binding name, an optional type annotation, <-, and an effect
expression. Well-formedness: §5.
§4.8.5 effect_send_stmt
Section titled “§4.8.5 effect_send_stmt”effect_send_stmt ::= "~>" expression~> and an effect expression — an asynchronous send. Unlike an
effect_let_stmt it carries no binder: the reply is not awaited and nothing
is bound. Well-formedness — including the requirement that the reply be
Effect[()] (the error gate): §5.
§4.8.6 assign_stmt (v0.81)
Section titled “§4.8.6 assign_stmt (v0.81)”assign_stmt ::= identifier ":=" expressionAn identifier, :=, and an expression — a Cell store write. Well-formedness —
including that the target is a store Cell field and the right-hand side does not
read it: §5 (ADR 0108).
§4.8.7 assert_expr
Section titled “§4.8.7 assert_expr”assert_expr ::= "assert" expressionassert and a condition. Well-formedness: §5.
§4.8.8 binding_name
Section titled “§4.8.8 binding_name”binding_name ::= identifier | "_"The name bound by a let: an identifier, or _ to discard the value.
§4.9 Testing constructs
Section titled “§4.9 Testing constructs”Test cases and mocks. See also the top-level test_decl
(§4.1.6) and integration_decl (§4.1.7).
§4.9.1 test_case
Section titled “§4.9.1 test_case”test_case ::= "test" string_literal blocktest, a description string, and a block body. Well-formedness: §5.
§4.9.2 mocks_decl
Section titled “§4.9.2 mocks_decl”mocks_decl ::= "mocks" identifier "=" identifier "{" provider_op* "}"mocks, a capability name, =, an implementation name, and a brace-delimited
list of operation implementations. Well-formedness: §5.