Decodal

Grammar

This page is the canonical grammar reference for Decodal syntax. Parser implementations such as the Rust parser, Tree-sitter grammar, and Lezer grammar should follow this grammar and may add implementation-specific precedence annotations where needed.

Lexical grammar

source_character = ? any Unicode scalar value ? ;
newline          = "\n" | "\r\n" | "\r" ;
space            = " " | "\t" | newline ;
comment          = "#" , { ? any character except newline ? } ;

digit            = "0" … "9" ;
letter           = "A" … "Z" | "a" … "z" ;
identifier       = letter , { letter | digit | "_" } ;

integer          = digit , { digit } ;
float            = digit , { digit } , "." , digit , { digit } ;

string           = '"' , { string_character | escape } , '"' ;
string_character = ? any character except '"', "\\", or newline ? ;
escape           = "\\" , source_character ;

regex            = "/" , regex_character , { regex_character } , "/" ;
regex_character  = escape | ? any character except "/", "\\", or newline ? ;

Whitespace and comments separate tokens and are otherwise ignored by the parser.

Syntactic grammar

module          = { statement } ;
statement       = field_definition , [ ";" ]
                | expression , [ ";" ] ;

expression      = default_expression ;

default_expression = patch_expression , [ "default" , default_expression ] ;
patch_expression   = compose_expression , { "//" , compose_expression } ;
compose_expression = logical_or_expression , { "&" , logical_or_expression } ;

logical_or_expression  = logical_and_expression , { "||" , logical_and_expression } ;
logical_and_expression = comparison_expression , { "&&" , comparison_expression } ;
comparison_expression  = concat_expression , [ comparison_operator , concat_expression ] ;
concat_expression      = additive_expression , { "++" , additive_expression } ;
additive_expression    = multiplicative_expression , { ( "+" | "-" ) , multiplicative_expression } ;
multiplicative_expression = unary_expression , { ( "*" | "/" ) , unary_expression } ;

unary_expression   = [ "!" | "-" ] , postfix_expression ;
postfix_expression = primary_expression , { call_suffix | path_suffix } ;
call_suffix        = "(" , [ argument_list ] , ")" ;
path_suffix        = "." , identifier ;

primary_expression = literal
                   | identifier
                   | comparison_constraint
                   | object
                   | array
                   | let_expression
                   | function_expression
                   | match_expression
                   | import_expression
                   | "(" , expression , ")" ;

literal            = string | integer | float | "true" | "false" | regex ;
comparison_operator = "==" | "!=" | "<" | "<=" | ">" | ">=" ;
comparison_constraint = ( "<" | "<=" | ">" | ">=" ) , expression ;

object             = "{" , [ field_definition , { ";" , field_definition } , [ ";" ] ] , "}" ;
field_definition   = field_path , "=" , expression ;
field_path         = identifier , { "." , identifier } ;

array              = "[" , [ expression , { "," , expression } , [ "," ] ] , "]" ;

let_expression     = "let" , { field_definition , ";" } , "in" , expression ;
function_expression = "(" , [ parameter_list ] , ")" , "=>" , expression ;
parameter_list     = parameter , { "," , parameter } , [ "," ] ;
parameter          = identifier , [ ":" , expression ] ;

match_expression   = "match" , expression , "{" , [ match_arm , { ";" , match_arm } , [ ";" ] ] , "}" ;
match_arm          = pattern , ":" , expression ;
pattern            = "_" | expression ;

import_expression  = "import" , string ;
argument_list      = expression , { "," , expression } , [ "," ] ;

Precedence

Precedence is highest first.

  1. function call and field path reference
  2. unary ! and -
  3. * and /
  4. + and -
  5. ++
  6. ==, !=, <, <=, >, >=
  7. &&
  8. ||
  9. &
  10. //
  11. default

Binary operators are left-associative except default, which is right-associative.

Tooling mapping

Syntax tooling should derive token categories from this grammar rather than making a tool-specific grammar canonical. Tree-sitter and Lezer grammars are implementation artifacts that follow this page.