Appendix A

The Full Grammar

This appendix collects the complete context-free grammar of Nex in one place, with the expression grammar given in its layered form so that operator precedence and associativity (Section 2.6) are expressed directly by the productions rather than assumed.

A.1Programs, Modules, and Declarations

program::=topitem*
topitem::=import | intern | classdec | uniondec | fundec | funsig | tydec | stmt
import::=import id (. id)* ⟨from string⟩
intern::=intern id (/ id)* ⟨as id⟩
qid::=id (/ id)*— class name, bare or qualified (Section 3.6.1)
tydec::=declare type id = ty ⟨where id : exp⟩
fundec::=function id ⟨gen⟩ ( ⟨params⟩ ) ⟨: ty⟩ ⟨note⟩ ⟨require⟩ do block ⟨ensure⟩ ⟨rescue⟩ end
funsig::=declare function id ⟨gen⟩ ( ⟨params⟩ ) ⟨: ty⟩ ⟨note⟩

A.2Classes

classdec::=⟨sealed⟩ ⟨deferred⟩ class id ⟨gen⟩ ⟨note⟩ ⟨inherit⟩ classbody ⟨invariant⟩ end
inherit::=inherit parent (, parent)*
parent::=qid ⟨tyargs⟩
classbody::=(featuresec | createsec)*
uniondec::=⟨enum⟩ union id ⟨gen⟩ ⟨note⟩ variant+ end
variant::=id ⟨( params )⟩
featuresec::=⟨private⟩ feature member+
createsec::=create constructor+
member::=field | constant | method
field::=⟨once⟩ id : ty ⟨note⟩
constant::=id ⟨: ty⟩ = exp ⟨note⟩
method::=id ⟨( ⟨params⟩ )⟩ ⟨: ty⟩ ⟨alias⟩ ⟨note⟩ ⟨require⟩ do block ⟨ensure⟩ ⟨rescue⟩ end
|id ( ⟨params⟩ ) ⟨: ty⟩ ⟨alias⟩ ⟨note⟩ ⟨deferred⟩
alias::=alias opsym
opsym::="+" | "-" | "*" | "/" | "%" | "^"
constructor::=id ⟨( ⟨params⟩ )⟩ ⟨require⟩ do block ⟨ensure⟩ ⟨rescue⟩ end
invariant::=invariant assertion+
params::=param (, param)*
param::=id (, id)* ⟨: ty⟩
require::=require assertion+
ensure::=ensure assertion+
rescue::=rescue block
assertion::=id : exp
note::=note string

A.3Types and Generics

gen::=[ genparam (, genparam)* ]
genparam::=⟨?⟩ id ⟨-> id⟩
tyargs::=[ ty (, ty)* ]
ty::=Integer | Real | Char | Boolean | String
|? ty | funty | qid ⟨tyargs⟩
funty::=Function ⟨( ⟨funtyparams⟩ ) ⟨: ty⟩⟩
funtyparams::=funtyparam (, funtyparam)*
funtyparam::=id : ty | ty

A.4Statements

block::=stmt*
stmt::=id := exp | exp . id := exp
|let id ⟨: ty⟩ := exp
|if exp then block (elseif exp then block)* ⟨else block⟩ end
|from block ⟨invariant⟩ ⟨variant⟩ until exp do block end
|repeat exp do block end
|across exp as id do block end
|case exp of caseclause+ ⟨else stmt⟩ end
|match exp of matchclause+ ⟨else block⟩ end
|select selectclause+ ⟨timeout⟩ ⟨else block⟩ end
|do block ⟨rescue⟩ end | with string do block end
|raise exp | retry | assert (assertion+ | exp) | exp
caseclause::=scon (, scon)* then stmt
matchclause::=pattern ⟨as id⟩ ⟨if exp⟩ then stmt
pattern::=_ | qid ⟨tyargs⟩ ⟨( fieldpat (, fieldpat)* )⟩
fieldpat::=_ | id | id : id | scon | pattern
selectclause::=when exp ⟨as id⟩ then block
timeout::=timeout exp then block
invariant::=invariant assertion+
variant::=variant exp

A.5Expressions (Layered)

The following layering expresses the precedence and associativity of Section 2.6: each level refers to the next more tightly binding one, with the binary operators of a level left-associative, ^ included (Section 2.6).

exp::=orexp
orexp::=andexp (or andexp)*
andexp::=eqexp (and eqexp)*
eqexp::=relexp ((= | /= | == | !=) relexp)*
relexp::=addexp ((< | <= | > | >=) addexp)*
addexp::=mulexp ((+ | -) mulexp)*
mulexp::=unexp ((* | / | % | ^) unexp)*
unexp::=- unexp | not unexp | ? postexp as id | postexp
postexp::=primary postfix*
postfix::=⟨?⟩ . id ⟨( ⟨args⟩ )⟩ | ( ⟨args⟩ )
primary::=scon | id | this | super | result | ( exp )
|createexp | whenexp | fnexp | spawnexp | convexp
|old primary | arraylit | maplit | setlit
createexp::=create qid ⟨tyargs⟩ ⟨. id ⟨( ⟨args⟩ )⟩⟩
whenexp::=when exp then exp else exp end
fnexp::=fn ⟨gen⟩ ( ⟨params⟩ ) ⟨: ty⟩ do block end
spawnexp::=spawn do block end
convexp::=convert exp to id : ty
args::=exp (, exp)*
arraylit::=[ ⟨exp (, exp)*⟩ ]
maplit::={ } | { exp : exp (, exp : exp)* }
setlit::=#{ ⟨exp (, exp)*⟩ }

A.6Lexical Grammar

id::=(letter | _) (letter | _ | digit)*
scon::=int | byte | int16 | int32 | real | char | string | true | false | nil
int::=digit+ | 0b bit+ | 0o odigit+ | 0x hdigit+
byte::=int u8
int16::=int i16
int32::=int i32
real::=⟨digit+⟩ . digit+ ⟨exp⟩
char::=# (char≠digit,ws | named | digit+)
named::=nul | space | newline | tab | return
string::=" … " | ' … '
comment::=-- … end-of-line

A digit separator _ may occur between two digits of any numeric literal. A byte, int16 or int32 is an int with a suffix, forming a single token; its range is checked (Section 2.2), and a leading - is absorbed into an int16 or int32. The reserved words of Section 2.1 are excluded from id by the longest-match rule of Section 2.5.