This is the full syntax specification for the Paisley language. It’s written in an ad-hoc format, not any real parser-generator syntax; the actual parser itself is hand-written. Instead, the hope here is that this file will make operator precedence & how statements are parsed more clear to the reader.
program :=
| statement*
statement :=
| if_stmt
| while_stmt
| for_stmt
| scope_stmt
| function_def
| call_stmt
| let_stmt
| uncache_stmt
| break_stmt
| continue_stmt
| return_stmt
| match_stmt
| alias_stmt
| try_stmt
| until_stmt
| error_stmt
| delete_stmt
| stop_stmt
| import_stmt
| define_stmt
| command
if_stmt :=
| `if` (argument|call_stmt) `then` program `end`
| `if` (argument|call_stmt) `then` program else_stmt
| `if` (argument|call_stmt) `then` program elif_stmt
| `if` (argument|call_stmt) else_stmt
elif_stmt :=
| `elif` program `end`
| `elif` program elif_stmt
| `elif` program else_stmt
else_stmt :=
| `else` program `end`
while_stmt :=
| `while` `do` program `end`
| `while` argument `do` program `end`
for_stmt :=
| `for` <text>+ `in` argument+ `do` program `end`
scope_stmt :=
| `do` program `end`
delete_stmt :=
| `delete` <text>+
function_def :=
| `function` <text> program `end`
call_stmt :=
| `call` <text>
let_stmt :=
| `let` <variable> `{` `}` `=` argument+
| `let` <variable> `{` expression `}` `{` `}` `=` argument+
| `let` <variable> `{` expression `}` (`=`|`+=`|`-=`|`*=`|`/=`|`%=`|`%%=`|`&=`) argument+
| `let` <variable>+ `=` argument+
| `let` <variable>+
| `let` <variable> (`+=`|`-=`|`*=`|`/=`|`%=`|`%%=`|`&=`) argument+
| `initial` <variable> `=` argument+
uncache_stmt :=
| `break` `cache` <text>
break_stmt :=
| `break` argument?
continue_stmt :=
| `continue` argument?
return_stmt :=
| `return` argument?
match_stmt :=
| `match` argument `do` match_if_stmt+ `end`
| `match` argument `do` match_if_stmt+ else_smt
match_if_stmt :=
| `if` match_argument `then` program `end`
| terse_match_statement `if` match_argument
match_argument :=
| <text>
| string
| `{` (`%`|`%%`|`>`|`<`|`>=`|`<=`|`=`|`!=`|`not`? `like`|`not`? `in`|`bitwise`? `and`|`bitwise`? `or`|`bitwise`? `xor`) expression `}`
| `{` expression `}`
| `${` inline_command `}`
terse_match_statement :=
| call_stmt
| let_stmt
| uncache_stmt
| break_stmt
| continue_stmt
| return_stmt
| delete_stmt
| stop_stmt
| error_stmt
| command
alias_stmt :=
| `using` argument `as` argument
| `using` argument
try_stmt :=
| `try` program catch_block+ `end`
until_stmt :=
| `until` text+ `do` program `end`
catch_block :=
| `catch` text+
| `catch` text+ as text
stop_stmt :=
| `stop`
import_stmt :=
| `require` text+
error_stmt :=
| `error` argument `as` text
| `error` argument
define_stmt :=
| `define` argument+
command :=
| (argument | pipeio)+
argument :=
| <text>
| string
| `{` expression `}`
| `${` inline_command `}`
pipeio :=
| `|` command
| stdio `>` (stdio | <text>)
| `<` argument
| `<<<` argument
stdio :=
| `?`
| `!`
| `?!`
inline_command :=
| call_stmt
| command
expression :=
| array
array :=
| kv_pair `,` array
| kv_pair `,`
| kv_pair
| `,`
kv_pair :=
| ternary `=>` ternary
| ternary
| `=>`
ternary :=
| list_comprehension `?` `else` ternary
| list_comprehension `else` ternary
| list_comprehension `?` `then` ternary
| list_comprehension `then` ternary
| list_comprehension `if` list_comprehension `else` ternary
| list_comprehension
list_comprehension :=
| boolean `for` <variable> `in` list_comprehension `if` list_comprehension
| boolean `for` <variable> `in` list_comprehension
| boolean
boolean :=
| concat `bitwise`? `and` boolean
| concat `bitwise`? `or` boolean
| concat `bitwise`? `xor` boolean
| concat `exists`
| concat
concat :=
| comparison+
comparison :=
| add `>` comparison
| add `<` comparison
| add `>=` comparison
| add `<=` comparison
| add `=` comparison
| add `!=` comparison
| add `in` comparison
| add `like` comparison
| add `not` `in` comparison
| add `not` `like` comparison
| add
add :=
| mult `+` add
| mult `-` add
| mult
mult :=
| slice `*` mult
| slice `/` mult
| slice `//` mult
| slice `%` mult
| slice `%%` mult
| slice
slice :=
| unary `:` `:`
| unary `:` unary `:` unary
| unary `:` unary
| unary
unary :=
| `bitwise`? `not` exponent
| `-` exponent
exponent :=
| length `^` exponent
| length
length :=
| `&` dot_and_index
| dot_and_index
dot_and_index :=
| value `.` value
| value `[` expression `]`
| value `?` `.` value
| value `?` `[` expression `]`
| value
value :=
| macro
| func_call
| <variable>
| <number>
| string
| `true` | `false` | `null`
| `(` expression `)`
| `{` expression `}`
| `${` inline_command `}`
macro :=
| <exclamation> `[` expression `]`
| <exclamation>
func_call :=
| <variable> `(` expression `)`
string :=
| `"` string_interp* `"`
| `"""` string_interp* `"""`
| `'` <text>? `'`
| `'''` <text>? `'''`
string_interp :=
| <text>
| `{` expression `}`
| `${` inline_command `}`