faml 0.1.14

Minimalist and powerful dynamic markup language
Documentation
WHITESPACE = _{ " " | "\t" }
NEWLINE    = _{ "\n" | "\r\n" }
COMMENT    = _{ ("//" ~ (!NEWLINE ~ ANY)*) | ("/*" ~ (!"*/" ~ ANY)* ~ "*/") }

boolean_literal       = @{ "true" | "false" }
number_literal        = @{ "-"? ~ ASCII_DIGIT+ ~ ("." ~ ASCII_DIGIT+)? }
string_literal        = @{ "\"" ~ ("\\\"" | (!"\"" ~ ANY))* ~ "\"" }
format_string         = @{ "$\"" ~ ("\\\"" | (!("{" | "\"" | NEWLINE) ~ ANY))* ~ "\"" }
format_string_part1   = @{ "$\"" ~ ("\\\"" | (!("{" | NEWLINE) ~ ANY))* ~ "{" }
format_string_part2   = @{ "}" ~ ("\\\"" | (!("{" | NEWLINE) ~ ANY))* ~ "{" }
format_string_part3   = @{ "}" ~ ("\\\"" | (!("\"" | NEWLINE) ~ ANY))* ~ "\"" }
format_string_literal =  { format_string | (format_string_part1 ~ expr ~ (format_string_part2 ~ expr)* ~ format_string_part3) }
literal               =  { boolean_literal | number_literal | string_literal | format_string_literal }

id      = { (ASCII_ALPHA | "_") ~ (ASCII_ALPHANUMERIC | "_")* }
ids     = { id ~ ("." ~ id)* }
anno_if = { "@if" ~ expr ~ NEWLINE+ }

op2         =  { "**" | "||" | "&&" | "<<" | ">>" | "<=" | ">=" | "==" | "!=" | "+" | "-" | "*" | "/" | "%" | "|" | "&" | "^" | "<" | ">" }
inner_sp    = _{ (NEWLINE*) ~ "," ~ (NEWLINE*) }
base_expr   =  { literal | ids }
exprs       =  { (expr ~ (inner_sp ~ expr)*)? }
array_expr  =  { "[" ~ exprs ~ "]" }
map_expr    =  { "{" ~ NEWLINE* ~ (map_assign_pair ~ (inner_sp ~ map_assign_pair)*)* ~ NEWLINE* ~ "}" }
strong_expr =  { base_expr | array_expr | map_expr }
expr_prefix =  { "++" | "--" | "!" | "-" | "~" }
num_unit    =  {
    "nanoseconds"
  | "microseconds"
  | "milliseconds"
  | "seconds"
  | "mins"
  | "hours"
  | "days"
  | "weeks"
  | "months"
  | "years"
  | "nanometers"
  | "micrometers"
  | "millimeters"
  | "meters"
  | "kilometers"
  | "megameters"
  | "KB"
  | "MB"
  | "GB"
  | "TB"
}
expr_suffix =  { ("(" ~ exprs ~ ")") | ("[" ~ expr ~ "]") | "++" | "--" | num_unit }
middle_expr =  { expr_prefix* ~ strong_expr ~ expr_suffix* }
weak_expr   =  { middle_expr ~ (op2 ~ middle_expr)* }
op3_expr    =  { weak_expr ~ "?" ~ middle_expr ~ ":" ~ middle_expr }
expr        =  { op3_expr | weak_expr }

assign_pair     = { anno_if? ~ ids ~ "=" ~ expr ~ NEWLINE+ }
map_assign_pair = { ids ~ ":" ~ expr ~ NEWLINE* }

group_head       = { "[" ~ ids ~ "]" ~ NEWLINE+ }
group_array_head = { "[[" ~ ids ~ "]]" ~ NEWLINE+ }
group_block      = { anno_if? ~ (group_head | group_array_head) ~ assign_pair* }

faml = { SOI ~ NEWLINE* ~ (group_block)* ~ EOI }