WHITESPACE = _{ " " | "\t" | "\n" | "\r" }
COMMENT = _{ ("/*" ~ (!"*/" ~ ANY)* ~ "*/") | ("//" ~ (!"\n" ~ ANY)*) }
program = { SOI ~ item* ~ EOI }
item = { type_alias | function | module }
statement = { assignment | expression }
expression = { block_expression | single_expression }
block_expression = { "{" ~ (statement ~ ";")* ~ expression? ~ "}" }
identifier = @{ ASCII_ALPHA ~ (ASCII_ALPHANUMERIC | "_")* }
jet = @{ "jet::" ~ (ASCII_ALPHANUMERIC | "_")+ }
witness_name = @{ ASCII_ALPHA ~ (ASCII_ALPHANUMERIC | "_")* }
builtin_type = @{ ("Either" | "Option" | "bool" | "List" | unsigned_type) ~ !ASCII_ALPHANUMERIC }
builtin_function = @{ ("unwrap_left" | "unwrap_right" | "for_while" | "is_none" | "unwrap" | "assert" | "panic" | "match" | "into" | "fold" | "dbg") ~ !ASCII_ALPHANUMERIC }
function_name = { !builtin_function ~ identifier }
typed_identifier = { identifier ~ ":" ~ ty }
function_params = { "(" ~ (typed_identifier ~ ("," ~ typed_identifier)*)? ~ ")" }
function_return = { "->" ~ ty }
fn_keyword = @{ "fn" ~ !ASCII_ALPHANUMERIC }
function = { fn_keyword ~ function_name ~ function_params ~ function_return? ~ block_expression }
variable_pattern = { identifier }
ignore_pattern = @{ "_" }
tuple_pattern = { "(" ~ ((pattern ~ ",")+ ~ pattern?)? ~ ")" }
array_pattern = { "[" ~ (pattern ~ ("," ~ pattern)* ~ ","?)? ~ "]" }
pattern = { ignore_pattern | tuple_pattern | array_pattern | variable_pattern }
let_keyword = @{ "let" ~ !ASCII_ALPHANUMERIC }
assignment = { let_keyword ~ pattern ~ ":" ~ ty ~ "=" ~ expression }
left_pattern = { "Left(" ~ identifier ~ ":" ~ ty ~ ")" }
right_pattern = { "Right(" ~ identifier ~ ":" ~ ty ~ ")" }
none_pattern = @{ "None" }
some_pattern = { "Some(" ~ identifier ~ ":" ~ ty ~ ")" }
false_pattern = @{ "false" }
true_pattern = @{ "true" }
match_pattern = { left_pattern | right_pattern | none_pattern | some_pattern | false_pattern | true_pattern }
sum_type = { "Either<" ~ ty ~ "," ~ ty ~ ">" }
option_type = { "Option<" ~ ty ~ ">" }
boolean_type = @{ "bool" }
unsigned_type = @{ "u128" | "u256" | "u16" | "u32" | "u64" | "u1" | "u2" | "u4" | "u8" }
tuple_type = { "(" ~ ((ty ~ ",")+ ~ ty?)? ~ ")" }
array_size = @{ ASCII_DIGIT+ }
array_type = { "[" ~ ty ~ ";" ~ array_size ~ "]" }
list_bound = @{ ASCII_DIGIT+ }
list_type = { "List<" ~ ty ~ "," ~ list_bound ~ ">" }
ty = { alias_name | builtin_alias | sum_type | option_type | boolean_type | unsigned_type | tuple_type | array_type | list_type }
builtin_alias = @{ "Ctx8" | "Pubkey" | "Message64" | "Message" | "Signature" | "Scalar" | "Fe" | "Gej" | "Ge" | "Point" | "Height" | "Time" | "Distance" | "Duration" | "Lock" | "Outpoint" | "Confidential1" | "ExplicitAsset" | "Asset1" | "ExplicitAmount" | "Amount1" | "ExplicitNonce" | "Nonce" | "TokenAmount1" }
alias_name = { !builtin_type ~ !builtin_alias ~ identifier }
type_keyword = @{ "type" ~ !ASCII_ALPHANUMERIC }
type_alias = { type_keyword ~ alias_name ~ "=" ~ ty ~ ";" }
left_expr = { "Left(" ~ expression ~ ")" }
right_expr = { "Right(" ~ expression ~ ")" }
none_expr = @{ "None" }
some_expr = { "Some(" ~ expression ~ ")" }
false_expr = @{ "false" }
true_expr = @{ "true" }
unwrap_left = { "unwrap_left::<" ~ ty ~ ">" }
unwrap_right = { "unwrap_right::<" ~ ty ~ ">" }
is_none = { "is_none::<" ~ ty ~ ">" }
unwrap = @{ "unwrap" }
assert = @{ "assert!" }
panic = @{ "panic!" }
type_cast = { "<" ~ ty ~ ">::into" }
debug = @{ "dbg!" }
fold = { "fold::<" ~ function_name ~ "," ~ list_bound ~ ">" }
for_while = { "for_while::<" ~ function_name ~ ">" }
call_name = { jet | unwrap_left | unwrap_right | is_none | unwrap | assert | panic | type_cast | debug | fold | for_while | function_name }
call_args = { "(" ~ (expression ~ ("," ~ expression)*)? ~ ")" }
call_expr = { call_name ~ call_args }
dec_literal = @{ (ASCII_DIGIT | "_")+ }
bin_literal = @{ "0b" ~ (ASCII_BIN_DIGIT | "_")+ }
hex_literal = @{ "0x" ~ (ASCII_HEX_DIGIT | "_")+ }
witness_expr = ${ "witness::" ~ witness_name }
param_expr = ${ "param::" ~ witness_name }
variable_expr = { identifier }
match_arm = { match_pattern ~ "=>" ~ (single_expression ~ "," | block_expression ~ ","?) }
match_keyword = @{ "match" ~ !ASCII_ALPHANUMERIC }
match_expr = { match_keyword ~ expression ~ "{" ~ match_arm ~ match_arm ~ "}" }
tuple_expr = { "(" ~ ((expression ~ ",")+ ~ expression?)? ~ ")" }
array_expr = { "[" ~ (expression ~ ("," ~ expression)* ~ ","?)? ~ "]" }
list_expr = { "list![" ~ (expression ~ ("," ~ expression)* ~ ","?)? ~ "]" }
single_expression = { left_expr | right_expr | none_expr | some_expr | false_expr | true_expr | call_expr | match_expr | tuple_expr | array_expr | list_expr | bin_literal | hex_literal | dec_literal | witness_expr | param_expr | variable_expr | "(" ~ expression ~ ")" }
mod_keyword = @{ "mod" ~ !ASCII_ALPHANUMERIC }
const_keyword = @{ "const" ~ !ASCII_ALPHANUMERIC }
module_name = @{ "witness" | "param" }
module_assign = { const_keyword ~ witness_name ~ ":" ~ ty ~ "=" ~ expression }
module = { mod_keyword ~ module_name ~ "{" ~ (module_assign ~ ";")* ~ "}" }