Zornux docs
Get started Spec

Reference

Specification

Behind the friendly surface is a strict, context-free grammar and a real type system. This page summarizes the formal foundation.

Design philosophy

Zornux optimizes for structural intuition over memorization, on three principles:

  • Zero punctuation overhead. Statements read as English sentences.
  • Flexible structural bounds. Blocks close with end; whitespace is never significant.
  • Intent-aware diagnostics. Errors are explained in plain language with a suggested fix.

Lexical structure

  • Source files are UTF-8 and use the .zx extension.
  • Whitespace and newlines only separate tokens — indentation is cosmetic.
  • Comments start with # and run to end of line.
  • Identifiers start with a letter; snake_case for values and functions, PascalCase for classes and services (by convention).

Type-system rules

Zornux is strongly typed with dynamic checking. The core rules:

  1. No implicit cross-kind coercion. Number + Text is an error.
  2. + is overloaded for number addition and text concatenation — operands must match.
  3. Comparisons order like-typed values — two numbers numerically, two texts by Unicode order, dates and times chronologically; is equal to works within a type and is false across types.
  4. Truthiness is explicit. Only a Truth value may be a condition.
  5. nothing is its own type — not 0, "", or false.
  6. UntrustedText can't be used as trusted text until validated — the language-level basis of the security model.

Grammar (EBNF excerpt)

A representative slice in ISO/IEC 14977 EBNF. The parser is the authoritative grammar; this excerpt is illustrative and omits many constructs (maps, sets, records, enums, contracts, properties, switch, try/catch, and more).

ebnf
program        = { statement } ;
statement      = create_statement | show_statement | if_statement
               | repeat_statement | for_each_statement | while_statement
               | function_declaration | give_back_statement ;

create_statement     = "create" , identifier , ( "as" | "=" ) , expression ;
if_statement         = "if" , expression , { statement } ,
                       { "else" , "if" , expression , { statement } } ,
                       [ "else" , { statement } ] , "end" ;
repeat_statement     = "repeat" , expression , "times" , { statement } , "end" ;
for_each_statement   = "for" , "each" , identifier , "in" , expression ,
                       { statement } , "end" ;
function_declaration = "function" , identifier , [ "with" , parameter_list ] ,
                       { statement } , "end" ;

Expression precedence

From lowest binding to highest (verified from the parser ladder):

  1. ?? — null-coalesce (right-associative)
  2. or
  3. and
  4. comparisons — equality, relational, membership (is in), and type (is an instance of); chainable, left-associative
  5. + -
  6. * / modulo (alias %)
  7. prefix -, not
  8. ** — exponentiation (right-associative)
  9. . () [] — member, call, index (postfix)
  10. primary — literals, names, grouping ( ) [ ] { }
A subtlety

Prefix -/not bind looser than **, so -2 ** 2 is -(2 ** 2), and the right side of ** may be unary (2 ** -3).

Additive, backward-compatible surface

Each release freezes its surface and grows only additively — a program valid in an earlier release stays valid. The frozen 1.8.0 surface is 89 keywords · 339 built-ins · 127 native APIs · 503 diagnostics. New features prefer contextual words (like get/set) over new reserved words, so they rarely collide with your names.

See the full word list in the Keywords reference, and error reporting in Diagnostics.