Grammar
Grammar
This is the complete syntax of qdx. Square brackets mean optional, braces mean repeated zero or more times, a bar separates alternatives, and text in quotes is written as shown.
Text
Source files are bytes. Spaces, tabs and line ends separate tokens and otherwise mean nothing, with one exception: a bytes literal cannot contain a line end.
letter = "a" ... "z" | "A" ... "Z" | "_" ;
digit = "0" ... "9" ;
name = letter { letter | digit } ;
integer = digit { digit } ;
bytes = '"' { any byte except '"', "\" and line end | escape } '"' ;
escape = "\n" | "\t" | "\\" | '\"' | "\x" hex hex ;
hex = digit | "A" ... "F" ;A name may not be one of the reserved words. An integer may not be followed directly by a letter. Where two symbols could be read as one, the longer is taken, so <= is one symbol.
Declarations
program = { function | record | union } ;
function = "fn" name "(" [ typed-names ] ")" "->" type block ;
record = "record" name "{" [ typed-names ] "}" ;
union = "union" name "{" case { "," case } "}" ;
case = name "(" [ typed-names ] ")" ;
typed-names = name ":" type { "," name ":" type } ;
type = "int" | "bool" | "bytes" | "never" | name ;Blocks
block = "{" { statement } expression "}" ;
statement = "let" name [ ":" type ] "=" expression ";"
| expression ";" ;Expressions
expression = or ;
or = and { "or" and } ;
and = not { "and" not } ;
not = "not" not | comparison ;
comparison = additive [ compare additive ] ;
compare = "==" | "!=" | "<" | "<=" | ">" | ">=" ;
additive = multiplicative { ( "+" | "-" ) multiplicative } ;
multiplicative = unary { ( "*" | "/" | "%" ) unary } ;
unary = "-" unary | access ;
access = primary { "." name } ;
primary = integer | bytes | "true" | "false" | name
| call | make | if | match | block
| "(" expression ")" ;
call = name "(" [ expression { "," expression } ] ")" ;
make = name "(" name ":" expression { "," name ":" expression } ")" ;
if = "if" expression block "else" ( if | block ) ;
match = "match" expression "{" arm { "," arm } "}" ;
arm = name "(" [ name { "," name } ] ")" "=>" expression ;Notes
- Lists never end with a comma.
callandmakelook alike when there is nothing between the parentheses.point()makes a record or union case ifpointis one, and calls a function otherwise.- A
nameused as a type must be a declared record or union. Type names are known across all files before any file is read, so a type can be used before its declaration. - The condition of an
ifand the value of amatchare followed by{. Because making a record uses parentheses and not braces, there is no ambiguity.