Implement filter transformation
This commit is contained in:
parent
2d15165406
commit
373ffc135e
|
@ -1,4 +1,5 @@
|
||||||
use proc_macro2::Span;
|
use proc_macro2::Span;
|
||||||
|
use quote::ToTokens;
|
||||||
use syn::parse::{Parse, ParseStream as SynParseStream, Result as ParseResult};
|
use syn::parse::{Parse, ParseStream as SynParseStream, Result as ParseResult};
|
||||||
use syn::spanned::Spanned;
|
use syn::spanned::Spanned;
|
||||||
use syn::{BinOp, Block, Expr};
|
use syn::{BinOp, Block, Expr};
|
||||||
|
@ -31,7 +32,7 @@ impl Parse for CodeBlock {
|
||||||
let main = s.parse::<Expr>()?;
|
let main = s.parse::<Expr>()?;
|
||||||
|
|
||||||
let code_block = match main {
|
let code_block = match main {
|
||||||
Expr::Binary(b) if matches!(b.op, BinOp::Or(_)) => {
|
Expr::Binary(b) if matches!(b.op, BinOp::BitOr(_)) => {
|
||||||
match *b.right {
|
match *b.right {
|
||||||
Expr::Call(c) => {
|
Expr::Call(c) => {
|
||||||
if let Expr::Path(ref p) = *c.func {
|
if let Expr::Path(ref p) = *c.func {
|
||||||
|
@ -123,6 +124,18 @@ struct SourceBuilder {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl SourceBuilder {
|
impl SourceBuilder {
|
||||||
|
fn new(escape: bool) -> SourceBuilder {
|
||||||
|
SourceBuilder {
|
||||||
|
escape,
|
||||||
|
source: String::from("{\n"),
|
||||||
|
source_map: SourceMap::default(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn reserve(&mut self, additional: usize) {
|
||||||
|
self.source.reserve(additional);
|
||||||
|
}
|
||||||
|
|
||||||
fn write_token<'a>(&mut self, token: &Token<'a>) {
|
fn write_token<'a>(&mut self, token: &Token<'a>) {
|
||||||
let entry = SourceMapEntry {
|
let entry = SourceMapEntry {
|
||||||
original: token.offset(),
|
original: token.offset(),
|
||||||
|
@ -156,16 +169,12 @@ impl SourceBuilder {
|
||||||
escape: bool,
|
escape: bool,
|
||||||
) -> Result<(), Error> {
|
) -> Result<(), Error> {
|
||||||
// parse and split off filter
|
// parse and split off filter
|
||||||
let code_block = syn::parse_str::<CodeBlock>(token.as_str()).map_err(|e| e)?;
|
let code_block = syn::parse_str::<CodeBlock>(token.as_str()).map_err(|e| {
|
||||||
|
let span = e.span();
|
||||||
if let Some(filter) = code_block.filter {
|
let mut err = make_error!(ErrorKind::RustSyntaxError(e));
|
||||||
let mut err = make_error!(ErrorKind::Unimplemented(
|
err.offset = into_offset(token.as_str(), span).map(|p| token.offset() + p);
|
||||||
"Filter is not implemented".to_owned()
|
err
|
||||||
));
|
})?;
|
||||||
err.offset = into_offset(token.as_str(), filter.span());
|
|
||||||
return Err(err);
|
|
||||||
}
|
|
||||||
|
|
||||||
let method = if self.escape && escape {
|
let method = if self.escape && escape {
|
||||||
"render_escaped"
|
"render_escaped"
|
||||||
} else {
|
} else {
|
||||||
|
@ -175,8 +184,46 @@ impl SourceBuilder {
|
||||||
self.source.push_str("__sf_rt::");
|
self.source.push_str("__sf_rt::");
|
||||||
self.source.push_str(method);
|
self.source.push_str(method);
|
||||||
self.source.push_str("!(__sf_buf, ");
|
self.source.push_str("!(__sf_buf, ");
|
||||||
|
|
||||||
|
if let Some(filter) = code_block.filter {
|
||||||
|
let expr_str = code_block.expr.into_token_stream().to_string();
|
||||||
|
let (name, extra_args) = match filter {
|
||||||
|
Filter::Ident(i) => (i.to_string(), None),
|
||||||
|
Filter::Call(c) => (
|
||||||
|
c.func.into_token_stream().to_string(),
|
||||||
|
Some(c.args.into_token_stream().to_string()),
|
||||||
|
),
|
||||||
|
};
|
||||||
|
|
||||||
|
self.source.push_str("sailfish::runtime::filter::");
|
||||||
|
self.source.push_str(&*name);
|
||||||
|
self.source.push_str("(");
|
||||||
|
|
||||||
|
// arguments to filter function
|
||||||
|
{
|
||||||
|
self.source.push_str("&(");
|
||||||
|
let entry = SourceMapEntry {
|
||||||
|
original: token.offset(),
|
||||||
|
new: self.source.len(),
|
||||||
|
length: expr_str.len(),
|
||||||
|
};
|
||||||
|
self.source_map.entries.push(entry);
|
||||||
|
self.source.push_str(&expr_str);
|
||||||
|
self.source.push_str(")");
|
||||||
|
|
||||||
|
if let Some(extra_args) = extra_args {
|
||||||
|
self.source.push_str(", ");
|
||||||
|
self.source.push_str(&*extra_args);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
self.source.push_str(")");
|
||||||
|
} else {
|
||||||
self.write_token(token);
|
self.write_token(token);
|
||||||
|
}
|
||||||
|
|
||||||
self.source.push_str(");\n");
|
self.source.push_str(");\n");
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -286,13 +333,8 @@ impl Translator {
|
||||||
) -> Result<TranslatedSource, Error> {
|
) -> Result<TranslatedSource, Error> {
|
||||||
let original_source = token_iter.original_source;
|
let original_source = token_iter.original_source;
|
||||||
|
|
||||||
let mut source = String::with_capacity(original_source.len());
|
let mut ps = SourceBuilder::new(self.escape);
|
||||||
source.push_str("{\n");
|
ps.reserve(original_source.len());
|
||||||
let mut ps = SourceBuilder {
|
|
||||||
escape: self.escape,
|
|
||||||
source,
|
|
||||||
source_map: SourceMap::default(),
|
|
||||||
};
|
|
||||||
ps.feed_tokens(token_iter)?;
|
ps.feed_tokens(token_iter)?;
|
||||||
|
|
||||||
Ok(ps.finalize()?)
|
Ok(ps.finalize()?)
|
||||||
|
|
Loading…
Reference in New Issue