use ast::*;
whitespace -> &'input str
= $(' ') / $('\t') / $('\r') / $('\n')
identifier -> &'input str
= $([a-zA-Z][a-zA-Z0-9_-]*)
pub escape -> Data
= escape:$("\\" .)
{
Data::Escape(escape[1..].to_string())
}
pub line_break -> Data
= line_break:$("\n"*<1,1000>)
{
Data::LineBreak(line_break.len())
}
pub paragraph_break -> Data
= paragraph_break:$("\n"*<2,1000>)
{
Data::ParagraphBreak(paragraph_break.len())
}
pub url -> Data
= schema:url_schema host:url_host port:url_port? path:url_path? query:url_query?
{
let mut output = String::new();
output.push_str(&schema);
output.push_str(&host);
if let Some(port) = port {
output.push_str(&port);
}
if let Some(path) = path {
output.push_str(&path);
}
if let Some(query) = query {
output.push_str(&query);
}
Data::Url(output)
}
url_schema -> String
= schema:$([a-z]+ "://")
{
schema.to_string()
}
url_host -> String
= host:$([^:/]+)
{
host.to_string()
}
url_port -> String
= port:$(":" [0-9]+)
{
port.to_string()
}
url_path -> String
= path:$("/" [^:?&#]+)
{
path.to_string()
}
url_query -> String
= query:$([?&#] [^:]*)
{
query.to_string()
}
pub attribute -> Data
= class_attribute / data_attribute / id_attribute / named_attribute
pub attributes -> Vec<Data>
= attributes:attribute ++ (whitespace*)
{
attributes
}
pub attribute_text -> Data
= text:$([^\\{}@#%.:]+)
{
Data::Text(text.to_string())
}
pub attribute_children -> Data
= url / attribute_text / escape
pub class_attribute -> Data
= "." name:$(identifier)
{
ClassAttribute::new(name.to_string())
}
pub data_attribute -> Data
= "%" name:$(identifier) whitespace* children:attribute_children*
{
let length = children.len();
let children: Option<Vec<Data>> = match length {
0 => None,
_ => Some(children)
};
DataAttribute::new(name.to_string(), children)
}
pub id_attribute -> Data
= "#" name:$(identifier)
{
IdAttribute::new(name.to_string())
}
pub named_attribute -> Data
= "@" name:$(identifier) whitespace* children:attribute_children*
{
let length = children.len();
let children: Option<Vec<Data>> = match length {
0 => None,
_ => Some(children)
};
NamedAttribute::new(name.to_string(), children)
}
pub element_text -> Data
= text:$([^\\{}\n]+)
{
Data::Text(text.to_string())
}
pub element_children -> Data
= element_text / escape / paragraph_break / line_break / element / preformatted_element / childless_element
pub element -> Data
= "{" name:identifier whitespace* attributes:attributes? ":" !"#" whitespace* children:element_children* "}"
{
let length = children.len();
let children: Option<Vec<Data>> = match length {
0 => None,
_ => Some(children)
};
Element::new(name.to_string(), attributes, children)
}
pub childless_element -> Data
= "{" name:identifier whitespace* attributes:attributes? whitespace* "}"
{
Element::new(name.to_string(), attributes, None)
}
pub preformatted_chunk -> &'input str
= $("\\#}" / [^\\])
pub preformatted_chunks -> &'input str
= $(!":#" !"#}" preformatted_chunk)
pub preformatted_children -> Option<Vec<Data>>
= ":#" chunks:preformatted_chunks* "#}"
{
let mut output: Vec<Data> = Vec::new();
let mut text = String::new();
for chunk in &chunks {
if chunk.starts_with("\\") {
if text.len() > 0 {
output.push(Data::Text(text));
text = String::new();
}
output.push(Data::Escape(chunk[1..].to_string()));
} else {
text.push_str(chunk);
}
}
if text.len() > 0 {
output.push(Data::Text(text));
}
if output.len() > 0 {
Some(output)
} else {
None
}
}
pub preformatted_element -> Data
= "{" name:identifier whitespace* attributes:attributes? whitespace* children:preformatted_children
{
Element::new(name.to_string(), attributes, children)
}
pub document -> Data
= children:element_children* EOF
{
Element::new(String::from("_root_"), None, Some(children))
}
EOF = #quiet<!.> / #expected("EOF")