Zynx Language Grammar

A readable map of the current grammar shape.

This readable grammar guide follows the current 0.0.0-dev language surface. It is a guide, not a full formal grammar. Current Language Surface records the current public source boundaries.

Top-level Items

source_file = top_level_item*
top_level_item =
  attribute* ("extern" | "export" | "intrinsic")*
  (function | struct | union | enum | error | interface | type | test | import | export | statement)
  | foreign_decl
foreign_decl =
  "foreign" string ("fn" foreign_fn | ("let" | "const") declaration ";")
  | "foreign" "library" string "{" foreign_item* "}"

module declarations are not part of current source. Module identities are derived from file paths and import requests.

Declarations

function = ("async" | "unsafe")* "fn" identifier generics? "(" parameters? ")" (throws_clause? "->" type)? block
struct   = "struct" identifier generics? (":" type_list)? "{" fields? "}"
interface = "interface" identifier generics? (":" type_list)? (";" | "{" members? "}")
enum     = "enum" identifier generics? "{" variants? "}"
type     = "type" identifier generics? "=" "distinct"? type ";"

Generic declarations can contain type parameters, interface bounds, const integer parameters such as N: usize, and one final type pack such as T.... Generic argument lists can contain type arguments or integer literals for const generic parameters.

Expressions

expression =
  assignment
  | conditional
  | binary
  | unary
  | postfix
  | primary

postfix = primary (call | member_access | index_access)*
member_access = ("." | "?.") identifier generic_arguments?
condition = expression | identifier ":=" expression

See Operators for precedence and associativity.

Types

type = "const"? ("&" | "*"+)? type_atom type_pack? nullable? throws_clause?
type_atom = base_type | named_type | tuple_type | callable_type | array_type
array_type = "[" type ("," number)? "]"
nullable = "?"
throws_clause = "throws" "(" identifier ("|" identifier)* ")"

Array and slice types use bracket-first syntax: [T] for slice-shaped array values and [T, N] for fixed-size arrays.

throws(...) belongs after the nullable suffix on value types, as in T? throws(E). Function declarations and callable types put the thrown error set before the return arrow, as in fn load() throws(IOError) -> Data.

Current Boundaries

Dynamic require(...), user-defined decorators, atomics, runtime interface objects, and broad foreign ABI forms are outside normal source. See Current Language Surface for those boundaries.