//
// include/grammar.pest
//
// ftml - Library to parse Wikidot text
// Copyright (C) 2019-2026 Wikijump Team
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU Affero General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Affero General Public License for more details.
//
// You should have received a copy of the GNU Affero General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.
//
// A simple parser generation exclusively to extract [[include]] directives
// within the wikitext. Other elements should be ignored and left as-is.
// Wikidot's "include" rule has some strange logic:
//
// [[include]]s can have leading *and* trailing pipe separators,
// for instance [[include page | a = 1 ]] or [[include page a = 1 | ]] (or both)
// and there can be multiple pipes,
// for instance [[include page || a = 1]] or [[include | | a = 1]]
//
// Additionally, each argument must be separated from each other with a pipe.
// We encapsulate this logic by essentially doing
// "(parameter ~ separator)* ~ (parameter ~ separator?)?
// That is, all internal parameters need pipes inside, but the last does not,
// and is optional should the sequence end in a pipe.
// Top-level rule
include = {
SOI ~ // Because we slice from the start of an include block using regex
"[[" ~ space? ~ ^"include" ~ space ~
page_ref ~ space? ~
(separator ~ space?)? ~
(argument ~ space? ~ separator ~ space?)* ~
(argument ~ space? ~ separator?)? ~
space? ~ include_end
}
include_end = _{
"]]" ~ &(NEWLINE | EOI)
}
argument = {
identifier ~ space? ~
"=" ~ space? ~
value
}
separator = _{
"|" ~ (space? ~ "|")*
}
value = {
(!(include_end | "|") ~ ANY)+
}
// Reference to a page, possibly not on this wiki
page_ref = {
(":" ~ site_name ~ ":")? ~ page_name
}
site_name = _{ (!(" " | "\n" | "\t" | "[" | "|" | "]" | ":") ~ ANY)+ }
page_name = _{ (!(" " | "\n" | "\t" | "[" | "|" | "]") ~ ANY)+ }
// Helpers
identifier = { (ASCII_ALPHANUMERIC | "-" | "_")+ }
space = _{ (" " | "\n" | "\t")+ }
// vim: set fdm=marker foldlevel=0: