Skip to main content

Zynx Language Grammar

This document provides the formal EBNF (ISO/IEC 14977) specification for the Zynx language.

It is primarily intended as a reference for:

  • implementors of tools that need to parse Zynx (e.g., editors, linters, or alternative frontends),
  • contributors working on the parser or language design.

For a more approachable description of syntax and behavior, see:

The sections below define the grammar of Zynx in EBNF form.

Module Structure

module          = { top_level_item } ;
top_level_item = { attribute } , [ "export" | "extern" ] , ( function_decl | struct_decl | enum_decl | error_decl | interface_decl | type_decl | var_decl , ";" | test_decl | asm_stmt | c_decl | import_stmt ) ;

(* The `export` keyword makes functions and constants public. The `extern` keyword is used to declare C functions. *)


import_stmt = ( "import" , dotted_path )
| ( "import" , "{" , identifier , { "," , identifier } , "}" , "from" , dotted_path )
, ";" ;

dotted_path = identifier , { "." , identifier } ;

c_decl = "raw" , "{" , raw_content , "}" ;
raw_content = { raw_text | raw_interp } ;
raw_interp = "$" , identifier
| "${" , expression , "}"
| "$$" ;
raw_text = ? any C text until interpolation or matching brace ? ;

Declarations

function_decl   = "fn" , identifier , [ generics ] , "(" , [ func_param_list ] , ")" , [ "->" , type ] , ( block | ";" ) ;
struct_decl = "struct" , identifier , [ generics ] , [ ":" , type_list ] , "{" ( struct_item )* "}" ;
enum_decl = "enum" , identifier , [ generics ] , "{" , [ enum_variant , { ( "," | ";" ) , enum_variant } , [ "," | ";" ] ] , "}" ;
error_decl = "error" , identifier , "{" , [ identifier , { ( "," | ";" ) , identifier } , [ "," | ";" ] ] , "}" ;
interface_decl = "interface" , identifier , [ generics ] , "{" ( interface_item )* "}" ;
type_decl = "type" , identifier , [ generics ] , "=" , [ "distinct" ] , type , ";" ;
type_list = type , { "," , type } ;
test_decl = "test" , string_literal , block ;

struct_item = field_decl | method_decl | init_decl | drop_decl ;
interface_item = field_decl | method_decl | operator_decl ;
enum_variant = identifier , [ "(" , param_list , ")" ] ;
field_decl = identifier , ":" , type , [ "=" , expression ] , [ "," | ";" ] ;
method_decl = function_decl | operator_decl ;
operator_decl = ( operator | "[]" | "()" ) , [ generics ] , "(" , [ param_list ] , ")" , [ "->" , type ] , ( block | ";" ) ;

Statements

block           = "{" ( statement )* "}" ;
statement = var_decl , ";" | expression , ";" | return_stmt , ";" | defer_stmt | if_stmt | while_stmt | for_stmt | asm_stmt | c_decl | block | "break" , ";" | "continue" , ";" ;
asm_stmt = "asm" , [ "volatile" ] , "(" , string_literal [ ":" , asm_operands ] [ ":" , asm_operands ] [ ":" , asm_clobbers ] , ")" , ";" ;
var_decl = ( "let" | "const" ) , ( identifier , [ ":" , type ] , [ "=" , expression ] | tuple_bind_pattern , "=" , expression ) ;
tuple_bind_pattern = "(" , identifier , { "," , identifier } , [ "," ] , ")" ;
return_stmt = "return" , [ expression ] ;
defer_stmt = "defer" , ( block , [ ";" ] | expression , ";" ) ;
if_stmt = "if" , expression , block , [ "else" , ( if_stmt | block ) ] ;
while_stmt = "while" , expression , block ;
for_stmt = "for" , identifier , { "," , identifier } , "in" , expression , block ;

Expressions

The following rules describe the recursive structure of Zynx expressions in terms of precedence and associativity.

expression      = assignment ;
assignment = conditional , [ assign_op , assignment ] ;
conditional = logical_or , [ "?" , expression , ":" , conditional ] ;
assign_op = "=" | "+=" | "-=" | "*=" | "/=" | "%=" | "<<=" | ">>=" | "&=" | "|=" | "^=" ;
logical_or = logical_and , { "||" , logical_and } ;
logical_and = bit_or , { "&&" , bit_or } ;
bit_or = bit_xor , { "|" , bit_xor } ;
bit_xor = bit_and , { "^" , bit_and } ;
bit_and = equality , { "&" , equality } ;
equality = comparison , { ( "==" | "!=" ) , comparison } ;
comparison = shift , { ( "<" | ">" | "<=" | ">=" ) , shift } ;
shift = additive , { ( "<<" | ">>" ) , additive } ;
additive = range , { ( "+" | "-" ) , range } ;
range = multiplicative , { ( "..." | "..<" ) , multiplicative } ;
multiplicative = cast , { ( "*" | "/" | "%" ) , cast } ;
cast = try_expr | unary ;
try_expr = "try" , expression ;
unary = catch_expr | unary_op , unary | postfix ;
catch_expr = expression , "catch" , ( [ "(" , identifier , ")" ] , ( block | expression ) ) ;
unary_op = "!" | "+" | "-" | "~" | "*" | "&" ;
postfix = primary , { call | member_access | index_access } ;
call = "(" , [ arg_list ] , ")" ;
arg_list = positional_args , [ "," , named_args ]
| named_args ;
positional_args = expression , { "," , expression } ;
named_args = named_arg , { "," , named_arg } ;
named_arg = identifier , ":" , expression ;
member_access = ( "." | "?." ) , identifier , [ generic_args ] ;
index_access = "[" , expression , "]" ;
primary = literal | identifier , [ generic_args ] | builtin_expr | "(" , expression , ")" | tuple_literal | array_literal | struct_literal | match_expr | lambda_expr ;

lambda_expr = lambda_fn_expr | lambda_short_expr ;
lambda_fn_expr = "fn" , "(" , [ param_list ] , ")" , [ "->" , type ] , block ;
lambda_short_expr = "(" , [ identifier , { "," , identifier } , [ "," ] ] , ")" , "=>" , ( block | expression ) ;

Types

type            = [ "const" ] , ( ref_type | unique_type | pointer_type | error_type | base_type ) ;
ref_type = "&" , type ;
unique_type = "Unique" , "<" , type , ">" ;
pointer_type = "*" , type ;
error_type = type , "!" ;
base_type = tuple_type | array_type | slice_type | named_type ;
tuple_type = "(" , type , { "," , type } , [ "," ] , ")" ;
array_type = type , "[" , integer_literal , "]" ;
slice_type = type , "[" , "]" ;
named_type = identifier , [ generic_args ] ;
generic_args = "<" , type , { "," , type } , ">" ;
generics = "<" , generic_param , { "," , generic_param } , ">" ;
generic_param = identifier , [ ":" , type_list ] ;