Declarations
Compilation unit
Section titled “Compilation unit”SourceFile = NamespaceDecl { Using } { Declaration } .NamespaceDecl = "namespace" QualifiedName .QualifiedName = identifier { "." identifier } .Using = "using" string_lit | "using" "static" string_lit | "using" identifier "=" string_lit .Declaration = [ "pub" ] ( DataDecl | RefDataDecl | ChoiceDecl | RefChoiceDecl | EnumDecl | InterfaceDecl | DelegateFuncDecl | StaticFuncDecl | FuncDecl | ConstDecl | DeriveDecl ) .Every source file begins with exactly one NamespaceDecl. Name resolution and the semantics of Using
are specified in Names & resolution. A declaration is internal unless
prefixed with pub.
Type = QualifiedName [ TypeArgs ] [ "?" ] // named type, optional generic args, optional nullable | "*" Type // pointer | "readonly" "*" Type // read-only by-ref (parameter position) | "(" TypeList ")" // tuple | FuncPtrType .FuncPtrType = "&" "(" [ TypeList "->" ] Type ")" . // &(int, int -> int) , &(-> bool)TypeArgs = "<" TypeList ">" .TypeList = Type { "," Type } .A type name in declaration position shall be PascalCase (ES2160). *T is a
pointer; *RefData is ill-formed (ES2003). T? denotes
an optional (see Types → nullable).
DataDecl = [ "readonly" ] "data" TypeName [ Generics ] ( "{" [ FieldList ] "}" | "(" [ ParamList ] ")" ) .FieldList = Field { ( "," | newline ) Field } .Field = [ "let" | "var" | "pub" ] identifier ":" Type [ "=" Expr ] | [ "pub" ] [ "*" ] TypeName . // embedded (anonymous) fieldGenerics = "<" identifier { "," identifier } ">" .A data introduces a value type: assignment copies it, and two values are equal iff their fields are
equal. The representation (CLR struct or class) is implementation-defined and unobservable
(Allocation). The following are ill-formed:
- a field whose type contains the enclosing type by value — ES2002; break the
cycle with
*T. - an
initblock — ES3012; construct with a composite literal or factory.
readonly data makes every field immutable and emits [IsReadOnly]. The positional form
data T(params) adds positional construction. An embedded field promotes the embedded type’s members to
the enclosing type. Generic type parameters are reified.
ref data
Section titled “ref data”RefDataDecl = [ "open" | "abstract" ] "ref" "data" TypeName [ Generics ] [ ":" BaseList ] "{" { Member } "}" .BaseList = TypeName { "," TypeName } . // base class, if any, is firstMember = Field | Init | Method | EventDecl | ConstDecl | ReturnsClause .Init = "init" "(" [ ParamList ] ")" [ ":" "base" "(" [ ArgList ] ")" ] Block .Method = [ "virtual" | "abstract" | ":" ] "func" identifier "(" [ ParamList ] ")" [ ReturnType ] ( Block | "=" Expr | ε ) .ReturnsClause = "returns" Type . // class-level default returnA ref data is a CLR class (identity, reference equality). It is sealed by default — emitted as a
sealed class, with no modifier to write; open makes it inheritable, abstract makes it
non-instantiable and inheritable. open is the only shape that is both instantiable and inheritable;
E#‘s OO stance is that a class is either abstract or sealed, so open is slated to become an
explicit .esproj opt-in, disabled by default. Field defaults run before the init
body. Inheritance — the member forms, the : func role inference, : base(...), and the ES2120–2128
diagnostics — is specified in the guide page Inheritance. EventDecl is specified
in Delegates & events.
choice / ref choice
Section titled “choice / ref choice”ChoiceDecl = "choice" TypeName [ Generics ] "{" { Case } "}" .RefChoiceDecl = "ref" "choice" TypeName [ Generics ] "{" { Case } "}" .Case = identifier [ "(" ParamList ")" ] .A choice is a tagged union — a value is exactly one case, each with zero or more payload fields. A value
choice emits as a tag enum plus a struct (always a struct). A ref choice emits an abstract base with
one sealed subclass per case; the per-case CLR type is Outer_case. Generic choice is reified. Cases are
constructed by factory (T.case(args)) or dot-case shorthand (.case(args)) and consumed by
match.
EnumDecl = "enum" TypeName "{" { EnumCase } "}" .EnumCase = identifier [ "=" int_lit ] .Emits as a CLR System.Enum with int32 underlying type. A case without an explicit value takes the
previous value + 1 (the first defaults to 0). Cases are constructed with a trailing () (Dir.north()).
interface
Section titled “interface”InterfaceDecl = "interface" TypeName [ Generics ] "{" { InterfaceMember } "}" .InterfaceMember = "func" identifier "(" [ ParamList ] ")" [ ReturnType ] | EventDecl .Emits as a CLR interface. Conformance is nominal: a type conforms only if it names the interface
after :, and the match is exact (name, parameter types, return type). A type that would satisfy an
undeclared interface raises ES2153. Where only the pointer method set
conforms, the __Ptr_T wrapper implements the interface (see Pointers).
Functions, static func, delegate func
Section titled “Functions, static func, delegate func”FuncDecl = "func" identifier [ Generics ] "(" [ ParamList ] ")" [ ReturnType ] ( Block | "=" Expr ) .ReturnType = ( "->" | "returns" ) Type .ParamList = Param { "," Param } .Param = [ "out" ] [ "readonly" ] identifier ":" Type | identifier ":" "*" Type .StaticFuncDecl = "static" "func" TypeName "{" { StaticMember } "}" .StaticMember = ConstDecl | "let" identifier [ ":" Type ] "=" Expr | "var" identifier [ ":" Type ] "=" Expr | FuncDecl | ReturnsClause .DelegateFuncDecl = "delegate" "func" TypeName "(" [ ParamList ] ")" [ ReturnType ] .A free function’s name shall be camelCase (ES2161); a method (first parameter
a data receiver) and a static func member may be PascalCase. A function whose first parameter is an
E#-declared data value is promoted to a method on that type and shall be called as recv.f(...); calling
it free is ES2142. Promotion, by-ref/out parameters, function pointers, and
the returns default-return clause are specified in Functions and
Pointers & by-ref. A static func body shall contain only fields, const, and
functions; a bare statement is ES1010. A delegate func mints a nominal
delegate type (Delegates & events).
const and derive
Section titled “const and derive”ConstDecl = "const" identifier [ ":" Type ] "=" Expr .DeriveDecl = "derive" identifier { "," identifier } . // precedes a data declarationA const initializer shall fold to a compile-time literal; otherwise ES1011
(use let). const is valid at namespace, static func, ref data, and function-body scope. derive
generates members at compile time: equality emits Equals / GetHashCode / == / !=; debug emits
ToString().