starbase_args 0.1.10

A generic command line argument parser with support for POSIX-based shells and more.
Documentation
COMMENT    = _{ "#" ~ (!"#" ~ ANY)* }
WHITESPACE = _{ " " | "\t" }

id          = _{ ASCII_ALPHANUMERIC | "_" }
id_env      = _{ ASCII_ALPHA_UPPER | ASCII_DIGIT | "_" }
id_starbase = _{ ALPHABETIC | ASCII_DIGIT | JOIN_CONTROL | "_" | "-" | "." | "/" | "\\" }

// SYNTAX:
// https://www.gnu.org/software/bash/manual/html_node/Definitions.html
// https://fishshell.com/docs/current/language.html#table-of-operators

blank       = _{ " " | "\t" }
whitespace  = _{ blank | "\n" | "\r" }
boundary    = _{ whitespace | EOI }
meta_char   = _{ whitespace | "|" | "&" | ";" }
escape_char = _{ "\\" | "/" | "b" | "f" | "n" | "r" | "t" }
fd_char     = _{ ASCII_DIGIT | "-" | "out+err" | "o+e" | "out" | "o" | "err" | "e" }

// OPERATORS:
// https://www.gnu.org/software/bash/manual/html_node/Redirections.html

control_operator          =  {
    ";"
  | "&&"
  | "||"
  | "--"
}
redirect_operator         =  {
    "<>"
  | ">>>"
  | ">>"
  | "<<<"
  | "<<"
  | "&>>"
  | "&>"
  | ">&"
  | ">?"
  | ">^"
  | ">|"
  | "<&"
  | "<?"
  | "<^"
  | "<|"
  | "|>"
  | "|<"
  | ">"
  | "<"
}
redirect_operator_with_fd = @{
    (fd_char ~ redirect_operator ~ fd_char)
  | (fd_char ~ redirect_operator)
  | (redirect_operator ~ fd_char)
}

operator = _{
    control_operator
  | redirect_operator_with_fd
  | redirect_operator
}

// VALUES:

value_quote_inner = _{
    "\\" ~ ((^"x" | ^"u") ~ ASCII_HEX_DIGIT+)
}

value_double_quote_inner = _{
    !("\"" | "\\") ~ ANY
  | "\\" ~ ("\"" | escape_char)
  | value_quote_inner
}
value_double_quote       = @{ "$"? ~ "\"" ~ value_double_quote_inner* ~ "\"" }

value_single_quote_inner = _{
    !("'" | "\\") ~ ANY
  | "\\" ~ ("'" | escape_char)
  | value_quote_inner
}
value_single_quote       = @{ "$"? ~ "'" ~ value_single_quote_inner* ~ "'" }

value_murex_brace_quote = @{ "%(" ~ (!")" ~ ANY)+ ~ ")" }
value_nu_raw_quote      = @{ "r#'" ~ value_single_quote_inner* ~ "'#" }

value_unquoted_inner = _{ !(meta_char | operator) ~ ANY }
value_unquoted       = @{ value_unquoted_inner+ }

value         = _{ value_murex_brace_quote | value_nu_raw_quote | value_double_quote | value_single_quote | value_unquoted }
value_dynamic = _{ expansion | substitution | value }

// EXPANSIONS:
// https://www.gnu.org/software/bash/manual/html_node/Arithmetic-Expansion.html
// https://www.gnu.org/software/bash/manual/html_node/Shell-Parameter-Expansion.html

arithmetic_expansion = { "$((" ~ (!"))" ~ ANY)+ ~ "))" }

brace_expansion = { "{" ~ (!"}" ~ ANY)+ ~ "}" }

parameter_expansion = { "${" ~ (!"}" ~ ANY)+ ~ "}" ~ boundary }

tilde_expansion = { "~" ~ ("+" | "-")? ~ ASCII_DIGIT? ~ ANY* }

moon_token_expansion = @{ "@" ~ id_starbase+ ~ "(" ~ id_starbase+ ~ ")" }

expansion = _{ arithmetic_expansion | parameter_expansion | brace_expansion | tilde_expansion | moon_token_expansion }

// SUBSTITUTION:
// https://www.gnu.org/software/bash/manual/html_node/Command-Substitution.html
// https://www.gnu.org/software/bash/manual/html_node/Process-Substitution.html

command_substitution = { "$(" ~ (!")" ~ ANY)+ ~ ")" | "!(" ~ (!")" ~ ANY)+ ~ ")" | "(" ~ (!")" ~ ANY)+ ~ ")" | "`" ~ (!"`" ~ ANY)+ ~ "`" }

process_substitution = { "<(" ~ (!")" ~ ANY)+ ~ ")" | ">(" ~ (!")" ~ ANY)+ ~ ")" }

substitution = _{ process_substitution | command_substitution }

// ARGUMENTS:

env_var_namespace =  { ^"$e:" | ^"$env::" | ^"$env:" | ^"$env." }
env_var_name      = @{ id_env+ }
env_var           = ${ env_var_namespace? ~ env_var_name ~ "=" ~ value_dynamic }

flag_group = @{ "-" ~ ASCII_ALPHA{2, } }
flag       = @{ "-" ~ ASCII_ALPHA }

option            = @{ ("&" | "--") ~ ASCII_ALPHA ~ (id | "-" | ".")* }
option_with_value = ${ option ~ "=" ~ value_dynamic }

param_special = @{ "$" ~ ("#" | "*" | "@" | "?" | "-" | "$" | "!") }
param         = @{ ("$" | "@") ~ (((ASCII_ALPHA | "_") ~ id*) | ASCII_DIGIT+) ~ boundary }

argument = _{ expansion | substitution | env_var | param_special | param | flag_group | flag | option_with_value | option | value }

// COMMAND LINE:
// https://www.gnu.org/software/bash/manual/html_node/Shell-Commands.html

command            = { argument+ }
command_terminator = { ";" | "&-" | "&!" | "&" | "2>&1" | "\n" | "--" }
command_list       = { command ~ (operator ~ command)* ~ command_terminator? }

pipeline_negated  = { "!" }
pipeline_operator = { "|&" | "&|" | "^|" | "|" | "->" | "=>" | "?" }
pipeline          = { pipeline_negated? ~ command_list ~ (pipeline_operator ~ command_list)* }

// PARSERS:

command_line                       = _{ SOI ~ pipeline ~ EOI }
unquoted_expansion_or_substitution = _{ SOI ~ (expansion | substitution) ~ EOI }