EBNF Grammar

file

file = { declaration } , [ return ] ;

file is referencing:

If the return statement is given, importing the file becomes valid and loads the returned values.

expression

expression = assignement ;

Items referencing expression:

expression is referencing:

assignement

assignement = identifier , { "[" , expression , "]" | "." , identifier } , { ( "=" | "+=" | "-=" | "*=" | "/=" | "%=" ) , combiner } | combiner ;

Items referencing assignement:

assignement is referencing:

Assignements assign the right of the expression to the left identifier, either directly or adds/subtracts/divides/applies the modulo operator. They evaluate to their new value, which makes this valid syntax: foo = bar += 1

combiner

equalityandor
combiner = equality , { ( "and" | "or" ) , equality } ;

Items referencing combiner:

combiner is referencing:

equality

equality = comparison , { ( "==" | "!=" ) , comparison } ;

Items referencing equality:

equality is referencing:

comparison

range><>=<=
comparison = range , { ( ">" | "<" | ">=" | "<=" ) , range } ;

Items referencing comparison:

comparison is referencing:

range

range = term | term , ".." , term | term , ".." | ".." , term ;

Items referencing range:

range is referencing:

term

term = factor , { ( "+" | "-" ) , factor } ;

Items referencing term:

term is referencing:

factor

unary*/%
factor = unary , { ( "*" | "/" | "%" ) , unary } ;

Items referencing factor:

factor is referencing:

unary

unary = { "-" | "!" } , error_handling ;

Items referencing unary:

unary is referencing:

error_handling

error_handling = { "~" | "?" } , properties ;

Items referencing error_handling:

error_handling is referencing:

! transforms the given value into an error value. ? unwraps an error to it's value, or returns the error if it is an error.

properties

properties = primary , { field_access | index | call } ;

Items referencing properties:

properties is referencing:

field_access

field_access = "." , identifier ;

Items referencing field_access:

field_access is referencing:

index

index = "[" , expression , "]" ;

Items referencing index:

index is referencing:

call

call = "(" , [ arguments ] , ")" ;

Items referencing call:

call is referencing:

arguments

arguments = expression , { "," , expression } ;

Items referencing arguments:

arguments is referencing:

primary

primary = number | string | identifier | "true" | "false" | "nil" | "(" , expression , ")" | block | map | function | if | check | while | for ;

Items referencing primary:

primary is referencing:

number

number = digit , { digit | "_" } , "." , { digit | "_" }- ;

Items referencing number:

number is referencing:

string

string = '"' , { char } , '"' | "'" , { char } , "'" ;

Items referencing string:

string is referencing:

Both ' and " can be used to delimit a string. They achieve the same thing.

block

block = "{" , { statement } , "}" , [ "?" ] ;

Items referencing block:

block is referencing:

map

map = "|" , [ map_values ] , "|" ;

Items referencing map:

map is referencing:

There are multiple types of syntax to define values in a map:

  1. Identifier - value (| foo = "bar" |): Assign the string "bar" to the field foo.
  2. Same-name identifiers (| foo |): Is the same as | foo = foo |.
  3. Expression - value ([2 + 3] = foo - 2): Assigns foo - 2 to 5.

map_values

map_values = map_value , { "," , map_value } ;

Items referencing map_values:

map_values is referencing:

map_value

map_value = identifier | identifier , "=" , expression | "[" , expression , "]" , "=" , expression ;

Items referencing map_value:

map_value is referencing:

function

function = "fn" , [ "?" ] , "(" , [ parameters ] , ")" , expression ;

Items referencing function:

function is referencing:

parameters

parameters = identifier , [ "?" ] , { "," , identifier , [ "?" ] } ;

Items referencing parameters:

parameters is referencing:

if

if = "if" , [ "?" ] , "(" , expression , ")" , expression , { "else" , "if" , "(" , expression , ")" , expression } , "else" , expression ;

Items referencing if:

if is referencing:

check

check = "check" , [ "?" ] , "(" , expression , ")" , [ "as" , identifier , [ "?" ] ] , expression , [ "else" , expression ] ;

Items referencing check:

check is referencing:

while

while = "while" , [ "?" ] , "(" , expression , ")" , expression ;

Items referencing while:

while is referencing:

for

for = "for" , [ "?" ] , "(" , identifier , [ "?" ] , "in" , expression , ")" , expression ;

Items referencing for:

for is referencing:

identifier

identifier = ( lowercase_letter | uppercase_letter | "_" ) , { lowercase_letter | uppercase_letter | digit | "_" } ;

Items referencing identifier:

identifier is referencing:

lowercase_letter

abcdefghijklmnopqrstuvwxyz
lowercase_letter = "a" | "b" | "c" | "d" | "e" | "f" | "g" | "h" | "i" | "j" | "k" | "l" | "m" | "n" | "o" | "p" | "q" | "r" | "s" | "t" | "u" | "v" | "w" | "x" | "y" | "z" ;

Items referencing lowercase_letter:

uppercase_letter

ABCDEFGHIJKLMNOPQRSTUVWXYZ
uppercase_letter = "A" | "B" | "C" | "D" | "E" | "F" | "G" | "H" | "I" | "J" | "K" | "L" | "M" | "N" | "O" | "P" | "Q" | "R" | "S" | "T" | "U" | "V" | "W" | "X" | "Y" | "Z" ;

Items referencing uppercase_letter:

digit

1234567890
digit = "1" | "2" | "3" | "4" | "5" | "6" | "7" | "8" | "9" | "0" ;

Items referencing digit:

statement

statement = ( expression | "break" | "continue" | return | ev | declaration ) , ";" ;

Items referencing statement:

statement is referencing:

return

returnexpression
return = "return" , [ expression ] ;

Items referencing return:

return is referencing:

ev

ev = "->" , [ expression ] ;

Items referencing ev:

ev is referencing:

ev makes the inner-most block that contains the ev-statement evaluate to the given expression. If no ev-statement is reached within a block, the block evaluates to nil.

declaration

declaration = ( "let" | "const" ) , identifier , [ "?" ] , "=" , expression ;

Items referencing declaration:

declaration is referencing: