document = { SOI ~ frontmatter? ~ WS* ~ element ~ WS* ~ EOI }
frontmatter = { "---" ~ (!("---") ~ ANY)* ~ "---" ~ WS? }
element = {
open_tag ~ children? ~ close_tag
| self_closing_tag
}
open_tag = { "<" ~ tag_name ~ (WS ~ attr)* ~ WS? ~ ">" }
self_closing_tag = { "<" ~ tag_name ~ (WS ~ attr)* ~ WS? ~ "/>" }
close_tag = { "</" ~ tag_name ~ WS? ~ ">" }
tag_name = @{ (ASCII_ALPHA | "_") ~ (ASCII_ALPHANUMERIC | "_" | "-")* }
attr = { attr_name ~ "=" ~ attr_value }
attr_name = @{ (ASCII_ALPHA | "_") ~ (ASCII_ALPHANUMERIC | "_" | "-")* }
attr_value = { "\"" ~ (escape | (!"\"" ~ ANY))* ~ "\"" | interpolation }
children = { node* }
node = { inner_text | interpolation | element }
inner_text = @{ (!("{" | "<") ~ ANY)+ }
interpolation = { "{" ~ interpolation_expr ~ "}" }
interpolation_expr = { (ASCII_ALPHANUMERIC | "_" | "." | " " | "!" | "?" | "(" | ")" | "[" | "]" | "&" | "|" | "=" | "+" | "-" | "*" | "/")+ }
escape = { "\\" ~ ANY }
WS = { " " | "\t" | "\n" | "\r" }