Core-0normative target; implementation partial

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.
*)
Projected fromspec/editions/core-0/core-0.ebnf