duster/src/duster/parser.rs

124 lines
2.9 KiB
Rust
Raw Normal View History

use nom::branch::alt;
use nom::bytes::complete::is_a;
use nom::bytes::complete::tag;
use nom::bytes::complete::take_until;
use nom::combinator::map;
use nom::combinator::recognize;
use nom::combinator::value;
2020-04-05 00:51:10 +00:00
use nom::multi::many0;
use nom::multi::separated_list;
use nom::sequence::delimited;
2020-04-05 00:51:10 +00:00
use nom::sequence::preceded;
use nom::sequence::tuple;
use nom::IResult;
#[derive(Clone, Debug)]
enum DustTag<'a> {
DTSpecial(Special),
DTComment(Comment<'a>),
DTReference(Reference<'a>),
}
#[derive(Clone, Debug)]
enum Special {
Space,
NewLine,
CarriageReturn,
LeftCurlyBrace,
RightCurlyBrace,
}
#[derive(Clone, Debug)]
struct Comment<'a> {
value: &'a str,
}
#[derive(Clone, Debug)]
struct Path<'a> {
keys: Vec<&'a str>,
}
#[derive(Clone, Debug)]
struct Reference<'a> {
path: Path<'a>,
2020-04-05 00:51:10 +00:00
filters: Vec<Filter>,
}
#[derive(Clone, Debug)]
enum Filter {
HtmlEncode,
DisableHtmlEncode,
JavascriptStringEncode,
EncodeUri,
EncodeUriComponent,
JsonStringify,
JsonParse,
}
fn dust_tag(i: &str) -> IResult<&str, DustTag> {
alt((
map(special, DustTag::DTSpecial),
map(comment, DustTag::DTComment),
map(reference, DustTag::DTReference),
))(i)
}
fn special(i: &str) -> IResult<&str, Special> {
delimited(
tag("{~"),
alt((
value(Special::Space, tag("s")),
value(Special::NewLine, tag("s")),
value(Special::CarriageReturn, tag("s")),
value(Special::LeftCurlyBrace, tag("s")),
value(Special::RightCurlyBrace, tag("s")),
)),
tag("}"),
)(i)
}
fn comment(i: &str) -> IResult<&str, Comment> {
map(delimited(tag("{!"), take_until("!}"), tag("!}")), |body| {
Comment { value: body }
})(i)
}
fn path(i: &str) -> IResult<&str, Path> {
map(
separated_list(
tag("."),
recognize(tuple((
is_a("abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ_$"),
is_a("abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ_$0123456789-"),
))),
),
|body| Path { keys: body },
)(i)
}
fn reference(i: &str) -> IResult<&str, Reference> {
2020-04-05 00:51:10 +00:00
let (remaining, (p, filters)) = delimited(tag("{"), tuple((path, many0(filter))), tag("}"))(i)?;
Ok((
remaining,
Reference {
path: p,
filters: filters,
},
))
}
fn filter(i: &str) -> IResult<&str, Filter> {
preceded(
tag("|"),
alt((
value(Filter::JsonStringify, tag("js")),
value(Filter::JsonParse, tag("jp")),
value(Filter::EncodeUriComponent, tag("uc")),
value(Filter::HtmlEncode, tag("h")),
value(Filter::DisableHtmlEncode, tag("s")),
value(Filter::JavascriptStringEncode, tag("j")),
value(Filter::EncodeUri, tag("u")),
)),
)(i)
}