← Documentation / DOC-03 · GRAMMAR · v1.0 · EBNF

Grammar
Reference

The formal surface syntax of New Code v1.0 in EBNF. Two layers: a top-level indentation-aware declaration layer and a brace/paren-based expression layer. When the implementation and spec disagree, this file wins.

Overview

The grammar is split into two layers, matching the implementation in newcode/parser.py and newcode/expr.py:

LAYER 1 · TOP-LEVEL Indentation-aware module · import · extern fn · process · let intent / forbid / ensure clauses captures body as raw text after ≔ LAYER 2 · EXPRESSION Brace/paren-based, free-form let-in · lambda · block if/then/else · case · fold records · lists · python { } invoked on every let RHS and body — two grammar layers · parser.py handles declarations · expr.py handles expressions

Everything a human writes in New Code is a score. The conductor writes the score; the compiler plays it. Everything the compiler writes in New Code is also a score — the syntax is shared, the semantics are the same.

EBNF Conventions

NotationMeaning
A ::= BA is defined as B
A | BOne of A or B
A?Optional A
A*Zero or more of A
A+One or more of A
( A B )Grouping
"lit"A literal token
UPPERCASETerminal symbols
lowercaseNon-terminal symbols

Lexical Structure

Source and whitespace

source    ::= ( line NEWLINE )*
NEWLINE   ::= "\r\n" | "\n"
whitespace ::= " " | "\t"
comment   ::= "※" any*

Identifiers

IDENT        ::= ( LETTER | "_" ) ( LETTER | DIGIT | "_" )*
DOTTED_IDENT ::= IDENT ( "." IDENT )*
LETTER       ::= "A".."Z" | "a".."z"
DIGIT        ::= "0".."9"

Numeric literals

NUMBER    ::= SIGN? ( FLOAT | INT ) EXPONENT?
SIGN      ::= "+" | "-"
INT       ::= DIGIT+
FLOAT     ::= DIGIT+ "." DIGIT* | "." DIGIT+
EXPONENT  ::= ("e" | "E") SIGN? DIGIT+

String literals

STRING       ::= "\"" STRING_CHAR* "\""
               | "'"  STRING_CHAR* "'"
INTENT_STR   ::= "「" any* "」"

INTENT_STR is the bracketed string form used in intent, forbid, and ensure clauses. Regular strings use ASCII quotes; intent strings use the Japanese corner brackets.

Top-Level Declarations

Module

module_decl ::= "module" DOTTED_IDENT NEWLINE
                intent_clause?
                forbid_clause?
                ensure_clause?
                module_body

module_body ::= ( import_decl
               | extern_decl
               | fn_decl
               | process_decl
               | let_decl
               | export_decl )*

Import

import_decl ::= "import" DOTTED_IDENT ( "as" IDENT )?
              | "import" DOTTED_IDENT ".{" name_list "}"

Extern Python block

extern_decl ::= "extern" "python" "{" python_source "}"

Function declaration

fn_decl ::= "fn" IDENT params_list "→" type_expr NEWLINE
            intent_clause
            forbid_clause
            ensure_clause
            requires_clause*
            guard_clause*
            bind_expr

params_list ::= "(" ( param ( "," param )* )? ")"
param       ::= IDENT ":" type_expr

Process declaration

process_decl ::= "process" IDENT ":" type_expr NEWLINE
                 intent_clause
                 emits_clause
                 consumes_clause*
                 bind_expr

Let binding

let_decl ::= "let" IDENT ( ":" type_expr )? "=" expr

Body binding

bind_expr ::= "≔" expr
            | ":=" expr
            | "≔" "??"       (* a hole — compiler fills from intent *)

Intent Clauses

intent_clause   ::= "intent:"  ":" INTENT_STR NEWLINE
forbid_clause   ::= "forbid:"  ":" INTENT_STR NEWLINE
ensure_clause   ::= "ensure:"  ":" INTENT_STR NEWLINE
requires_clause ::= "requires" ":" expr NEWLINE
emits_clause    ::= "emits"    ":" type_expr "at" NUMBER ("Hz" | "kHz")? NEWLINE
consumes_clause ::= "consumes" ":" IDENT "<" IDENT ">" NEWLINE
guard_clause    ::= "guard"    ":" expr NEWLINE

Clause indentation: All clauses in a function declaration must be indented at least one level beyond the fn keyword. The body () must be at the same indentation level as the clauses.

Expression Layer

The expression layer is parsed by newcode/expr.py and is invoked on every let RHS, every explicit body, and every REPL expression.

Let-in

let_expr ::= "let" IDENT ( ":" type_expr )? "=" expr "in" expr
           | "let" IDENT ( ":" type_expr )? "=" expr NEWLINE expr

Lambda

lambda_expr ::= "\" IDENT+ "->" expr
              | "λ" IDENT+ "↦" expr

Block

block_expr ::= "{" statement* expr "}"
statement  ::= let_decl NEWLINE

Conditional

if_expr ::= "if" expr "then" expr "else" expr

Both branches must yield a value of the same type. if without else is a parse error.

Case expression

case_expr ::= "case" expr "of" NEWLINE
              ( pattern "when" expr? "↦" expr NEWLINE )+

Fold

fold_expr ::= expr "fold" "with" expr "from" expr
            | expr "fold-min" "by" IDENT

Record and list literals

record_expr ::= "{" ( IDENT ":" expr ( "," IDENT ":" expr )* )? "}"
list_expr   ::= "[" ( expr ( "," expr )* )? "]"

Python escape

python_expr ::= "python" "{" python_source "}"

Binary and unary expressions

expr ::= expr "⊕" expr
       | expr "⊚" expr
       | expr "⇝" expr
       | expr "‖" expr
       | expr "▶" expr
       | expr "∥" expr
       | expr "↺" "by" NUMBER TIME_UNIT
       | expr "▷◁" expr
       | "⟪" expr "," expr "⟫"
       | "⌊" expr "⌉"
       | "⌊" expr "⌉_amp"
       | "⌊" expr "⌉_freq"
       | "⌊" expr "⌉_rms"
       | expr "⁻"
       | expr "?"
       | "◈" "(" expr "," expr ")"
       | expr "(" arg_list? ")"    (* function application *)
       | atom

Waveform literal

wave_literal ::= "⟨" expr "," expr "," expr "," shape_expr "⟩"
shape_expr   ::= IDENT
               | "pulse" "(" expr ")"
               | "noise" "(" expr ")"
               | "{" IDENT "↦" expr "}"   (* shape literal *)

Literals

KindFormExample
Waveform⟨ f, A, φ, σ ⟩⟨ 440, 1.0, 0, sine ⟩
ScalarDecimal, optional exponent3.14 · 6.022e23
Shape{ t ↦ expr }{ t ↦ tanh(sin(2π·t)) }
String (intent)「...」「identify the nearest signature」
String (general)"..." or '...'"libsndfile"
Booleantrue / false / True / Falsetrue
List[ expr, ... ][concert_a, silence]
Record{ key: expr, ... }{ f: 440, A: 1.0 }

Type Expressions

type_expr ::= "𝕎"
            | "𝕎*"
            | "ℝ"
            | "shape"
            | "proc" "<" type_expr ">"
            | "stream" "<" type_expr ">"
            | "fault" "<" IDENT ">"
            | "⌊" type_expr "⌉"
            | "⟨" type_expr "▷◁" type_expr "⟩"
            | "[" type_expr "]"
            | "(" type_expr "," type_expr ")"
            | "{" ( IDENT ":" type_expr )+ "}"
            | "fn" "(" type_expr_list ")" "→" type_expr
            | type_expr "|" type_expr
            | IDENT

Patterns

pattern ::= "⟨" pat_component "," pat_component "," pat_component "," pat_component "⟩"
          | "fault" "<" IDENT ">" "(" pattern "," pattern ")"
          | "⌊" pattern "⌉"
          | "⟨" pattern "▷◁" pattern "⟩"
          | "[" pattern ( "," pattern )* "]"
          | IDENT                    (* variable binding *)
          | "_"                      (* wildcard *)
          | NUMBER
          | STRING

pat_component ::= IDENT             (* bind component to name *)
                | "_"               (* ignore component *)
                | shape_expr        (* match on specific shape *)
                | NUMBER            (* match on literal value *)

Reserved Words

Top-level declaration keywords

fn   let   process   module   import   extern   export

Clause keywords

intent   forbid   ensure   requires   emits   consumes   guard

Expression-layer keywords

let   in   if   then   else   and   or   not
match   with   do   end
case   of   when   fold
true   false   True   False

Type keywords

fn   proc   stream   fault   shape   record   collapse

Built-in shape names

sine   sq   square   tri   triangle   saw   sawtooth   pulse   noise

Reserved symbols

SymbolRole
𝕎 ℝType glyphs
⊕ ⊚ ⁻ ⇝ ⟪·,·⟫ ▷◁ ◈ ‖ ⌊·⌉Operators
▶ ∥ ↺Process combinators
⟨ ⟩Waveform literal delimiters
Maps-to (lambda and shape literals)
≔ :=Definition / body bind
??Hole placeholder
Line comment
《 》Block comment delimiters
「 」Intent string delimiters

Unicode note: All reserved symbols are fixed Unicode code points. The parser does not accept ASCII substitutes for most symbols except := for , \ for λ, and -> for in lambda expressions.