botwork 0.2.0

botwork is a single-binary, generic and open-source automation framework written in Rust for acceptance testing, acceptance test driven development (ATDD), and robotic process automation (RPA). The syntax is basically plain text (in any human lanuage) with parameters. Easily extendible with Rust, Python & JavaScript. An efficient, fast alternative to Robot Framework.
Documentation
WHITESPACE = _{ (" " | "\t")+ }
botwork    = _{ SOI ~ statements* ~ EOI }
reserved   =  { "true" | "false" | "and" | "or" }

// Special statements. Can cause changes to program behaviour.
IF       = _{ ("i" | "I") ~ ("f" | "F") }
IN       = _{ ("i" | "I") ~ ("n" | "N") }
ELSE     = _{ ("e" | "E") ~ ("l" | "L") ~ ("s" | "S") ~ ("e" | "E") }
FOR      = _{ ("f" | "F") ~ ("o" | "O") ~ ("r" | "R") }
BREAK    = _{ ("b" | "B") ~ ("r" | "R") ~ ("e" | "E") ~ ("a" | "A") ~ ("k" | "K") }
RETURN   = _{ ("r" | "R") ~ ("e" | "E") ~ ("t" | "T") ~ ("u" | "U") ~ ("r" | "R") ~ ("n" | "N") }
CONTINUE = _{ ("c" | "C") ~ ("o" | "O") ~ ("n" | "N") ~ ("t" | "T") ~ ("i" | "I") ~ ("n" | "N") ~ ("u" | "U") ~ ("e" | "E") }
WHILE    = _{ ("w" | "W") ~ ("h" | "H") ~ ("i" | "I") ~ ("l" | "L") ~ ("e" | "E") }
TRY      = _{ ("t" | "T") ~ ("r" | "R") ~ ("y" | "Y") }
CATCH    = _{ ("c" | "C") ~ ("a" | "A") ~ ("t" | "T") ~ ("c" | "C") ~ ("h" | "H") }

reserved_parts = _{ IF | ELSE | FOR | BREAK | RETURN | CONTINUE | WHILE | TRY | CATCH }

COMMENT       = _{ comment_block | comment_line }
comment_block = @{ "###" ~ (!"###" ~ ANY)* ~ "###" }
comment_line  = @{ "#" ~ (!NEWLINE ~ ANY)* }

part          =  { (!("|" | "{" | "}" | "\r" | "\n" | "#") ~ ANY)+ }
statements    = _{ stmt_break | stmt_continue | stmt_return | stmt_if | stmt_for | stmt_while | stmt_try | stmt_define | stmt_assign | stmt_invoke | NEWLINE }
stmt_assign   =  { param_define ~ "=" ~ (stmt_invoke | param_invoke) }
stmt_if       =  { IF ~ param_invoke ~ stmt_block ~ stmt_else? }
stmt_else     =  { ELSE ~ ( stmt_block | stmt_if) }
stmt_for      =  { FOR ~ param_define ~ IN ~ param_invoke ~ stmt_block }
stmt_while    =  { WHILE ~ param_invoke ~ stmt_block }
stmt_try      =  { TRY ~ stmt_block ~ (stmt_catch)? }
stmt_catch    =  { CATCH ~ stmt_block }
stmt_define   =  { stmt_header ~ stmt_block }
stmt_header   =  { !reserved_parts ~ part ~ (param_define | part)*}
stmt_invoke   =  { !reserved_parts ~ part ~ (param_invoke | part)* }
stmt_block    =  { "{" ~ statements* ~ "}" }
stmt_break    =  { BREAK }
stmt_continue =  { CONTINUE }
stmt_return   =  { RETURN ~ param_invoke? }
param_invoke  =  { "|" ~ expression ~ "|" }
param_define  = _{ "|" ~ ident ~ "|" }

expression        =  { infix | expression_inner }
infix             = _{ expression_inner ~ (binary_operator ~ expression_inner)+ }
expression_inner  = _{ unary | primary }
braced_expression = _{ "(" ~ expression ~ ")" }
unary             =  { unary_operator ~ primary }
primary           = _{ literal | dot_path | ident | braced_expression }
dot_path          =  { ident ~ ("." ~ (ident | integer))+ }
literal           = _{ map | array | string | float | integer | boolean }
array             =  { "[" ~ (expression ~ ("," ~ expression)*)? ~ "]" }
ident             = @{ !reserved ~ LETTER ~ (LETTER | NUMBER | "_")* }

map       =  { "{" ~ (map_pair ~ ("," ~ map_pair)*)? ~ "}" }
map_pair  =  { keyword ~ seperator ~ expression }
keyword   = @{ ident }
seperator = _{ ":" }

integer = @{ NUMBER+ }
float   = @{ NUMBER+ ~ "." ~ NUMBER+ }

string           =  { string_delimiter ~ string_content ~ string_delimiter }
string_content   = ${ (string_escape | !(string_delimiter | "\\") ~ ANY)* }
string_delimiter = _{ "\"" }
string_escape    = _{ "\\" ~ ("\"" | "\\" | "n") }

exponent              = { "^" }
multiply              = { "*" }
divide                = { "/" }
modulus               = { "%" }
plus                  = { "+" }
minus                 = { "-" }
less_than             = { "<" }
less_than_or_equal    = { "<=" }
greater_than          = { ">" }
greater_than_or_equal = { ">=" }
not_equal             = { "!=" }
equal                 = { "==" }
logical_and           = { "and" }
logical_or            = { "or" }
logical_not           = { "!" }

binary_operator = _{
    exponent
  | multiply
  | divide
  | modulus
  | plus
  | minus
  | less_than_or_equal
  | less_than
  | greater_than_or_equal
  | greater_than
  | not_equal
  | equal
  | logical_and
  | logical_or
}
unary_operator  = _{ minus | logical_not }

boolean       = _{ boolean_true | boolean_false }
boolean_true  =  { "true" }
boolean_false =  { "false" }