simfony 0.1.0

Rust-like language that compiles to Simplicity bytecode.
Documentation
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 ~ ";")* ~ "}" }