enprot 0.5.21

Engyon Protected Text (EPT) — confidentiality processor and capability ledger
// EPT directive grammar — formal PEG spec (pest format).
//
// Status: spec (TODO.complete/12). Not yet wired into the Rust parser;
// the hand-written parser in src/etree/parse.rs is the production
// path. This grammar exists to:
//   1. Be the single source of truth for what EPT directives look like.
//   2. Enable third-party parsers (other languages, tooling) to share
//      one grammar.
//   3. Eventually replace the hand-written parser once benchmarks
//      confirm pest is within 2× of hand-written performance.
//
// Conforms to docs/schemas/ept-wire-format-v1.md (the prose spec).
// Tested by the conformance suite planned in TODO.complete/21.

file           = ${ SOI ~ line* ~ EOI }
line           =  { directive_line ~ NL | plain_line }
plain_line     =  { (!directive_start ~ ANY)* }
directive_line =  { ws* ~ directive ~ ws* }
directive      =  { comment_leader ~ ws? ~ left_sep ~ ws? ~ directive_body ~ ws? ~ right_sep }

// Host-language comment leaders we recognize. The parser is permissive:
// any of these may prefix an EPT directive. The choice is informational —
// enprot doesn't enforce that the leader matches the host language.
comment_leader = @{ "//" | "#" | "--" | "/*" | ";" }

// Default separators. Configurable via --left-separator / --right-separator
// or --lang; the grammar captures the most common shape.
left_sep       = _{ "<(" }
right_sep      = _{ ")>" }

// A directive body is one keyword + zero or more arguments.
directive_body =  ${ keyword ~ (ws+ ~ arg)* }

keyword        =  { "BEGIN" | "END" | "ENCRYPTED" | "STORED" | "DATA"
                  | "CHAIN" | "IMMUTABLE" | "MUTABLE" | "MUTED"
                  | "INCLUDE" | "CONFLICT" }

// Three argument shapes:
//   1. bare word (BEGIN/END/ENCRYPTED/etc.)
//   2. key=value extfield
//   3. base64 DATA payload
arg            =  { extfield | base64_data | word }

extfield       =  { key ~ "=" ~ value }
key            = @{ ASCII_ALPHA_LOWER ~ (ASCII_ALPHA_LOWER | ASCII_DIGIT | "-" | "_")* }
value          = @{ (!end_of_value ~ ANY)+ }
end_of_value   = _{ ws | right_sep | NL }

word           = @{ ASCII_ALPHA_UPPER ~ (ASCII_ALPHA_UPPER | ASCII_DIGIT | "_")* }

// base64 (no padding required; padding tolerated). Limited to the
// DATA payload shape (no whitespace inside).
base64_data    = @{ ASCII_ALPHANUMERIC | "+" | "/" | "=" }+

// Lexical helpers.
ws             = _{ " " | "\t" }
NL             = _{ "\n" | "\r\n" }