Paisley Syntax

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 `}`

Back