The complete generated Core-0 source and interface grammar.
Core-0 grammar
(* ZergLang Core-0 generated lexical and surface grammar.
This file governs generated .zl implementations and generated .zli machine
interfaces. The authoritative .zl.md and optional .zli.md are unconstrained
free English and therefore intentionally have no EBNF. Semantic restrictions
that cannot be expressed here are in the modular Core-0 specification.
Braces and semicolons below
are literal tokens.
Notation:
X , Y sequence
X | Y alternative
[ X ] zero or one
{ X } zero or more
X - Y character-set subtraction
*)
(* ------------------------------------------------------------------------- *)
(* Lexical grammar *)
(* ------------------------------------------------------------------------- *)
source-character = ? any Unicode scalar value except U+0000 ? ;
line-terminator = U+000A | U+000D , [ U+000A ] ;
space = U+0020 | U+0009 | line-terminator ;
line-comment = "//" , { source-character - line-terminator } ,
[ line-terminator ] ;
block-comment = "/*" , { block-comment-unit } , "*/" ;
block-comment-unit
= source-character - "*"
| "*" , (source-character - "/") ;
trivia = space | line-comment | block-comment ;
(* Block comments do not nest. Trivia may occur between any two tokens, but
never within a token. A UTF-8 BOM is permitted only before the first token
and is otherwise rejected. *)
ascii-lower = "a" | "b" | "c" | "d" | "e" | "f" | "g" | "h"
| "i" | "j" | "k" | "l" | "m" | "n" | "o" | "p"
| "q" | "r" | "s" | "t" | "u" | "v" | "w" | "x"
| "y" | "z" ;
ascii-upper = "A" | "B" | "C" | "D" | "E" | "F" | "G" | "H"
| "I" | "J" | "K" | "L" | "M" | "N" | "O" | "P"
| "Q" | "R" | "S" | "T" | "U" | "V" | "W" | "X"
| "Y" | "Z" ;
ascii-letter = ascii-lower | ascii-upper | "_" ;
decimal-digit = "0" | "1" | "2" | "3" | "4"
| "5" | "6" | "7" | "8" | "9" ;
binary-digit = "0" | "1" ;
hex-digit = decimal-digit | "a" | "b" | "c" | "d" | "e" | "f"
| "A" | "B" | "C" | "D" | "E" | "F" ;
identifier-token = ascii-letter , { ascii-letter | decimal-digit } ;
keyword = "module" | "import" | "public" | "private"
| "open" | "abstract" | "override"
| "value" | "class" | "extends"
| "error" | "enum" | "let" | "var" | "move"
| "init" | "drop" | "message" | "operator"
| "algorithm" | "workflow" | "compute" | "state" | "optimize"
| "requires" | "ensures" | "effects" | "result"
| "self" | "type" | "Self" | "base"
| "if" | "else" | "while" | "match"
| "break" | "continue" | "return" | "defer" | "try"
| "true" | "false" | "unsafe" ;
identifier = identifier-token - keyword ;
digit-sequence = decimal-digit , { [ "_" ] , decimal-digit } ;
binary-sequence = binary-digit , { [ "_" ] , binary-digit } ;
hex-sequence = hex-digit , { [ "_" ] , hex-digit } ;
integer-suffix = "i8" | "i16" | "i32" | "i64"
| "u8" | "u16" | "u32" | "u64" | "index" ;
integer-literal = ( "0x" , hex-sequence
| "0b" , binary-sequence
| digit-sequence ) ,
[ integer-suffix ] ;
exponent-part = ( "e" | "E" ) , [ "+" | "-" ] , digit-sequence ;
float-suffix = "f32" | "f64" ;
float-literal = ( digit-sequence , "." , digit-sequence ,
[ exponent-part ]
| digit-sequence , exponent-part ) ,
[ float-suffix ] ;
simple-escape = "\\" , ( "\\" | "\"" | "n" | "r" | "t" | "0" ) ;
byte-escape = "\\x" , hex-digit , hex-digit ;
unicode-escape = "\\u{" , hex-digit , { hex-digit } , "}" ;
string-character = (source-character - ( "\"" | "\\" | line-terminator ))
| simple-escape | byte-escape | unicode-escape ;
string-literal = "\"" , { string-character } , "\"" ;
byte-string-literal
= "b\"" , { string-character } , "\"" ;
boolean-literal = "true" | "false" ;
literal = float-literal | integer-literal | string-literal
| byte-string-literal | boolean-literal ;
(* The lexer uses longest-token matching for ::, ->, =>, <=, >=, ==, !=, <<,
>>, &&, and ||. While parsing a type-argument list, a >> token is consumed as
two successive > delimiters. This is the only token split performed by the
parser. *)
(* ------------------------------------------------------------------------- *)
(* Files and declarations *)
(* ------------------------------------------------------------------------- *)
implementation-unit
= module-declaration , { import-declaration } ,
{ implementation-top-level-declaration } , end-of-file ;
generated-interface-unit
= module-declaration , { import-declaration } ,
{ generated-interface-top-level-declaration } , end-of-file ;
end-of-file = ? end of input ? ;
module-declaration
= "module" , module-path , ";" ;
import-declaration
= "import" , import-path , ";" ;
module-path = identifier , { "." , identifier } ;
import-path = identifier , "." , identifier ,
{ "." , identifier } ;
implementation-top-level-declaration
= value-declaration
| class-declaration
| error-declaration
| enum-declaration ;
generated-interface-top-level-declaration
= generated-interface-value-declaration
| generated-interface-class-declaration
| generated-interface-error-declaration
| generated-interface-enum-declaration ;
visibility = "public" | "module" | "private" ;
value-declaration
= visibility , "value" , identifier , [ generic-parameters ] ,
{ requirement-clause } ,
"{" , { value-member } , "}" ;
class-declaration
= visibility , [ "open" ] , [ "abstract" ] ,
"class" , identifier ,
[ generic-parameters ] , [ extends-clause ] ,
{ requirement-clause } ,
"{" , { class-member } , "}" ;
generated-interface-value-declaration
= "public" , "value" , identifier , [ generic-parameters ] ,
{ requirement-clause } ,
"{" , { generated-interface-value-member } , "}" ;
generated-interface-class-declaration
= "public" , [ "open" ] , [ "abstract" ] ,
"class" , identifier ,
[ generic-parameters ] , [ extends-clause ] ,
{ requirement-clause } ,
"{" , { generated-interface-class-member } , "}" ;
generic-parameters
= "<" , identifier , { "," , identifier } , ">" ;
generic-arguments
= "<" , type , { "," , type } , ">" ;
explicit-generic-arguments
= "::" , generic-arguments ;
extends-clause = "extends" , type ;
value-member = field-declaration
| initializer-declaration
| drop-declaration
| value-message-declaration ;
class-member = field-declaration
| initializer-declaration
| drop-declaration
| message-declaration ;
generated-interface-value-member
= generated-interface-field-declaration
| generated-interface-initializer-declaration
| generated-interface-value-message-declaration ;
generated-interface-class-member
= generated-interface-field-declaration
| generated-interface-initializer-declaration
| generated-interface-message-declaration ;
field-declaration
= visibility , field-mutability , identifier , ":" , type ,
";" ;
generated-interface-field-declaration
= "public" , field-mutability , identifier , ":" , type ,
";" ;
field-mutability = "let" | "var" ;
initializer-declaration
= visibility , "init" , [ generic-parameters ] ,
"(" , [ value-parameter-list ] , ")" ,
[ base-initializer ] , "->" , type , effect-clause , block ;
generated-interface-initializer-declaration
= "public" , "init" , [ generic-parameters ] ,
"(" , [ value-parameter-list ] , ")" ,
"->" , type , effect-clause , ";" ;
base-initializer = "base" , type , "." , "init" ,
"(" , [ argument-list ] , ")" ;
drop-declaration
= "private" , "drop" , "(" , "self" , ":" ,
"Mut" , "<" , "Self" , ">" , ")" ,
"->" , "Unit" , effect-clause , block ;
message-declaration
= visibility , [ "open" ] , [ "abstract" ] , [ "override" ] ,
domain , "message" , message-selector , [ generic-parameters ] ,
"(" , receiver-parameter ,
[ "," , value-parameter-list ] , ")" ,
"->" , type , { requirement-clause } ,
[ precondition-clause ] , [ postcondition-clause ] , effect-clause ,
message-implementation ;
value-message-declaration
= visibility , domain , "message" , message-selector ,
[ generic-parameters ] ,
"(" , receiver-parameter ,
[ "," , value-parameter-list ] , ")" ,
"->" , type , { requirement-clause } ,
[ precondition-clause ] , [ postcondition-clause ] , effect-clause ,
block ;
generated-interface-message-declaration
= "public" , [ "open" ] , [ "abstract" ] , [ "override" ] ,
domain , "message" , message-selector , [ generic-parameters ] ,
"(" , receiver-parameter ,
[ "," , value-parameter-list ] , ")" ,
"->" , type , { requirement-clause } ,
[ precondition-clause ] , [ postcondition-clause ] , effect-clause ,
";" ;
generated-interface-value-message-declaration
= "public" , domain , "message" , message-selector ,
[ generic-parameters ] ,
"(" , receiver-parameter ,
[ "," , value-parameter-list ] , ")" ,
"->" , type , { requirement-clause } ,
[ precondition-clause ] , [ postcondition-clause ] , effect-clause ,
";" ;
message-selector = identifier | "operator" , overloadable-operator ;
overloadable-operator
= "+" | "-" | "*" | "/" | "%"
| "<<" | ">>" | "&" | "|" | "^"
| "==" | "!=" | "<" | "<=" | ">" | ">=" | "!" ;
message-implementation
= block | ";" ;
receiver-parameter
= "self" , ":" , type
| "type" , ":" , "Class" , "<" , type , ">" ;
value-parameter-list
= value-parameter , { "," , value-parameter } ;
value-parameter = identifier , ":" , type ;
requirement-clause
= "requires" , identifier ,
"{" , { requirement-message } , "}" ;
requirement-message
= "algorithm" , "message" , message-selector ,
"(" , receiver-parameter ,
[ "," , value-parameter-list ] , ")" ,
"->" , type , effect-clause , ";" ;
precondition-clause
= "requires" , "{" , { contract-expression , ";" } , "}" ;
postcondition-clause
= "ensures" , "{" , { contract-expression , ";" } , "}" ;
contract-expression
= expression ;
effect-clause = "effects" , "{" , [ effect-list ] , "}" ;
effect-list = effect-name , { "," , effect-name } ;
effect-name = identifier | "unsafe" ;
domain = "algorithm" | deferred-domain ;
deferred-domain = "workflow" | "compute" | "state" | "optimize" ;
error-declaration
= visibility , "error" , identifier , [ generic-parameters ] ,
"{" , { variant-declaration } , "}" ;
enum-declaration
= visibility , "enum" , identifier , [ generic-parameters ] ,
"{" , { variant-declaration } , "}" ;
generated-interface-error-declaration
= "public" , "error" , identifier , [ generic-parameters ] ,
"{" , { variant-declaration } , "}" ;
generated-interface-enum-declaration
= "public" , "enum" , identifier , [ generic-parameters ] ,
"{" , { variant-declaration } , "}" ;
variant-declaration
= identifier ,
[ "(" , value-parameter-list , ")" ] , ";" ;
(* ------------------------------------------------------------------------- *)
(* Types *)
(* ------------------------------------------------------------------------- *)
type = "Self" | identifier , [ generic-arguments ] ;
(* Imported declarations are referred to by their imported final component.
Dotted source names are module paths, not an alternate fully-qualified type
spelling. Intrinsic types use the same identifier/generic grammar. *)
(* ------------------------------------------------------------------------- *)
(* Statements and blocks *)
(* ------------------------------------------------------------------------- *)
block = "{" , { statement } , "}" ;
statement = local-declaration , ";"
| expression , ";"
| return-statement
| if-statement
| while-statement
| match-statement
| break-statement
| continue-statement
| defer-statement
| unsafe-statement ;
local-declaration
= local-mutability , identifier , [ ":" , type ] ,
"=" , expression ;
local-mutability = "let" | "var" ;
return-statement = "return" , [ expression ] , ";" ;
break-statement = "break" , ";" ;
continue-statement
= "continue" , ";" ;
if-statement = "if" , "(" , expression , ")" , block ,
[ "else" , (if-statement | block) ] ;
while-statement = "while" , "(" , expression , ")" , block ;
match-statement = "match" , "(" , expression , ")" ,
"{" , { match-arm } , "}" ;
match-arm = pattern , "=>" , block ;
defer-statement = "defer" , block ;
unsafe-statement = "unsafe" , block ;
pattern = "_"
| [ "-" ] , integer-literal
| string-literal
| byte-string-literal
| boolean-literal
| "let" , identifier
| variant-pattern ;
variant-pattern = identifier , [ "." , identifier ] ,
[ "(" , [ pattern-list ] , ")" ] ;
pattern-list = pattern , { "," , pattern } ;
(* ------------------------------------------------------------------------- *)
(* Expressions, from lowest to highest precedence *)
(* ------------------------------------------------------------------------- *)
expression = assignment-expression ;
assignment-expression
= logical-or-expression ,
[ "=" , assignment-expression ] ;
logical-or-expression
= logical-and-expression ,
{ "||" , logical-and-expression } ;
logical-and-expression
= bitwise-or-expression ,
{ "&&" , bitwise-or-expression } ;
bitwise-or-expression
= bitwise-xor-expression ,
{ "|" , bitwise-xor-expression } ;
bitwise-xor-expression
= bitwise-and-expression ,
{ "^" , bitwise-and-expression } ;
bitwise-and-expression
= equality-expression ,
{ "&" , equality-expression } ;
equality-expression
= comparison-expression ,
{ equality-operator , comparison-expression } ;
equality-operator
= "==" | "!=" ;
comparison-expression
= shift-expression ,
{ comparison-operator , shift-expression } ;
comparison-operator
= "<" | "<=" | ">" | ">=" ;
shift-expression = additive-expression ,
{ shift-operator , additive-expression } ;
shift-operator = "<<" | ">>" ;
additive-expression
= multiplicative-expression ,
{ additive-operator , multiplicative-expression } ;
additive-operator
= "+" | "-" ;
multiplicative-expression
= unary-expression ,
{ multiplicative-operator , unary-expression } ;
multiplicative-operator
= "*" | "/" | "%" ;
unary-expression = postfix-expression
| unary-operator , unary-expression
| "try" , unary-expression
| "move" , "(" , expression , ")" ;
unary-operator = "!" | "-" ;
postfix-expression
= primary-expression , { postfix-part } ;
postfix-part = "." , identifier
| "." , identifier , [ explicit-generic-arguments ] ,
"(" , [ argument-list ] , ")" ;
primary-expression
= literal
| "self"
| "type"
| "base"
| "result"
| name-expression
| parenthesized-expression
| array-literal
| self-initializer ;
name-expression = identifier , [ explicit-generic-arguments ] ;
parenthesized-expression
= "(" , expression , ")" ;
argument-list = expression , { "," , expression } ;
array-literal = "[" , [ argument-list ] , "]" ;
self-initializer = "Self" , "{" , [ field-initializer-list ] , "}" ;
field-initializer-list
= field-initializer , { "," , field-initializer } , [ "," ] ;
field-initializer
= identifier , ":" , expression ;
(* ------------------------------------------------------------------------- *)
(* Context restrictions *)
(* ------------------------------------------------------------------------- *)
(* 1. In a .zl file, a class message ending in ';' must say open abstract, and
its class must also say open abstract. A message with a block must not say
abstract. Value messages always have blocks and cannot say open,
abstract, or override.
2. A .zli is canonical compiler output. All declarations it contains are
public, and all message/initializer entries end in ';'. Source parsers do
not accept a handwritten .zli as the implementation of a module.
3. A class and each class message are sealed unless they say open. An
abstract class/message must say open. An override is sealed unless it says
open override. A value is always sealed and has no extends clause.
4. Only algorithm is executable in Core-0. A parsed deferred-domain message
is rejected with ZL-DOMAIN-0001.
5. An instance message's first parameter is self: Ref<Self>, self: Mut<Self>,
or self: Self. A declared class-object message uses type: Class<Self>.
A closed intrinsic-catalog value-construction selector may use the same
type: Class<Self> descriptor receiver without acquiring class semantics.
A generic requirement may instead name type: Class<T> for its required
type parameter T.
6. A class initializer's first value parameter is an explicitly named
allocator: Ref<Allocator<A>>, where A denotes one initializer type
parameter (the source identifier need not literally be A). Its result is
Result<Self, InitError<A, E>> for one declared domain-error type E. A
value initializer returns Result<Self, E>. A class initializer has
exactly one base-initializer when its class has an explicit base, and none
otherwise; that base initializer receives the same allocator and does not
allocate again.
7. A postfix part without '(...)' is field access. The resolved field must
be visible from the access site, and the receiver must provide the borrow
needed to read or mutate it. A private field is therefore accessible only
through self inside its declaring value or class. Every postfix part with
'(...)' is a message send.
8. The left side of '=' must be an assignable place rooted in a var local or
an authorized self field. Assignment is right-associative; all other
binary operators are left-associative.
9. A match must be exhaustive. Binding patterns are written 'let name'; a
bare identifier in a pattern denotes a resolved enum/error variant. A
Result pattern obtains its exact T and E from the scrutinee only and is
written Ok(...), Err(...), Result.Ok(...), or Result.Err(...), without
generic arguments.
10. Trailing commas are permitted only in Self field initializer lists.
11. A requirement-clause is distinguished from a precondition-clause by the
identifier immediately following 'requires'. Requirement clauses precede
message preconditions. Preconditions precede postconditions, which
precede effects. 'result' is legal only in a postcondition of a message
whose result type is not Unit. Contract expressions are additionally
restricted by C0-CONTRACT; the expression grammar alone does not imply
that an effectful or allocating expression is legal there.
12. Operator declarations use only overloadable-operator. Unary ! has arity
one; - may have arity one or two; every other operator has arity two.
Expression &&, ||, and assignment are not overloadable selectors.
13. A postfix call `Type.Variant(...)` whose primary name resolves to a
closed enum/error descriptor and whose selector resolves to one of its
declared variants is variant construction, not message lookup. Its
arguments match the declared variant payload positionally and exactly;
a fieldless variant requires an explicit empty `()`.
14. Intrinsic Result construction always supplies both generic arguments as
`Result::<T, E>.Ok(...)` or `Result::<T, E>.Err(...)`; construction does
not infer either argument. Prefix `try` is valid only under the exact
operand and enclosing-result rule in C0-ERR-004.
*)