From 7b7c38b37785b83ce28f1cc5f6e89abb89672276 Mon Sep 17 00:00:00 2001 From: René Kijewski Date: Tue, 1 Aug 2023 03:45:32 +0200 Subject: parser: add type for `Node::Lit` --- askama_derive/src/generator.rs | 13 +++---- askama_parser/src/lib.rs | 10 ++---- askama_parser/src/node.rs | 77 ++++++++++++++++++++++++++---------------- askama_parser/src/tests.rs | 16 +++------ 4 files changed, 61 insertions(+), 55 deletions(-) diff --git a/askama_derive/src/generator.rs b/askama_derive/src/generator.rs index beb3c49..5711c36 100644 --- a/askama_derive/src/generator.rs +++ b/askama_derive/src/generator.rs @@ -2,7 +2,7 @@ use crate::config::{get_template_source, read_config_file, Config, WhitespaceHan use crate::heritage::{Context, Heritage}; use crate::input::{Print, Source, TemplateInput}; use crate::CompileError; -use parser::{Call, Cond, CondTest, Expr, Loop, Match, Node, Parsed, Target, Whitespace, Ws}; +use parser::{Call, Cond, CondTest, Expr, Lit, Loop, Match, Node, Parsed, Target, Whitespace, Ws}; use proc_macro::TokenStream; use quote::{quote, ToTokens}; @@ -626,8 +626,8 @@ impl<'a> Generator<'a> { let mut size_hint = 0; for n in nodes { match *n { - Node::Lit(lws, val, rws) => { - self.visit_lit(lws, val, rws); + Node::Lit(ref lit) => { + self.visit_lit(lit); } Node::Comment(ws) => { self.write_comment(ws); @@ -666,9 +666,9 @@ impl<'a> Generator<'a> { self.flush_ws(m.ws1); self.prepare_ws(m.ws2); } - Node::Raw(ws1, lws, val, rws, ws2) => { + Node::Raw(ws1, ref lit, ws2) => { self.handle_ws(ws1); - self.visit_lit(lws, val, rws); + self.visit_lit(lit); self.handle_ws(ws2); } Node::Import(ref i) => { @@ -1274,8 +1274,9 @@ impl<'a> Generator<'a> { Ok(size_hint) } - fn visit_lit(&mut self, lws: &'a str, val: &'a str, rws: &'a str) { + fn visit_lit(&mut self, lit: &'a Lit<'_>) { assert!(self.next_ws.is_none()); + let Lit { lws, val, rws } = *lit; if !lws.is_empty() { match self.skip_ws { WhitespaceHandling::Suppress => {} diff --git a/askama_parser/src/lib.rs b/askama_parser/src/lib.rs index d095f65..8138a19 100644 --- a/askama_parser/src/lib.rs +++ b/askama_parser/src/lib.rs @@ -16,7 +16,8 @@ use nom::{error_position, AsChar, IResult, InputTakeAtPosition}; pub use self::expr::Expr; pub use self::node::{ - BlockDef, Call, Cond, CondTest, Import, Loop, Macro, Match, Node, Target, When, Whitespace, Ws, + BlockDef, Call, Cond, CondTest, Import, Lit, Loop, Macro, Match, Node, Target, When, + Whitespace, Ws, }; mod expr; @@ -138,13 +139,6 @@ fn ws<'a, O>( delimited(take_till(not_ws), inner, take_till(not_ws)) } -fn split_ws_parts(s: &str) -> Node<'_> { - let trimmed_start = s.trim_start_matches(is_ws); - let len_start = s.len() - trimmed_start.len(); - let trimmed = trimmed_start.trim_end_matches(is_ws); - Node::Lit(&s[..len_start], trimmed, &trimmed_start[trimmed.len()..]) -} - /// Skips input until `end` was found, but does not consume it. /// Returns tuple that would be returned when parsing `end`. fn skip_till<'a, O>( diff --git a/askama_parser/src/node.rs b/askama_parser/src/node.rs index a8325ef..a743b53 100644 --- a/askama_parser/src/node.rs +++ b/askama_parser/src/node.rs @@ -10,13 +10,13 @@ use nom::sequence::{delimited, pair, preceded, terminated, tuple}; use nom::{error_position, IResult}; use super::{ - bool_lit, char_lit, identifier, keyword, num_lit, path, skip_till, split_ws_parts, str_lit, ws, - Expr, State, + bool_lit, char_lit, identifier, is_ws, keyword, num_lit, path, skip_till, str_lit, ws, Expr, + State, }; #[derive(Debug, PartialEq)] pub enum Node<'a> { - Lit(&'a str, &'a str, &'a str), + Lit(Lit<'a>), Comment(Ws), Expr(Ws, Expr<'a>), Call(Call<'a>), @@ -30,7 +30,7 @@ pub enum Node<'a> { Include(Ws, &'a str), Import(Import<'a>), Macro(Macro<'a>), - Raw(Ws, &'a str, &'a str, &'a str, Ws), + Raw(Ws, Lit<'a>, Ws), Break(Ws), Continue(Ws), } @@ -38,33 +38,13 @@ pub enum Node<'a> { impl<'a> Node<'a> { pub(super) fn many(i: &'a str, s: &State<'_>) -> IResult<&'a str, Vec> { many0(alt(( - complete(|i| Self::content(i, s)), + map(complete(|i| Lit::parse(i, s)), Self::Lit), complete(|i| Self::comment(i, s)), complete(|i| Self::expr(i, s)), complete(|i| Self::parse(i, s)), )))(i) } - fn content(i: &'a str, s: &State<'_>) -> IResult<&'a str, Self> { - let p_start = alt(( - tag(s.syntax.block_start), - tag(s.syntax.comment_start), - tag(s.syntax.expr_start), - )); - - let (i, _) = not(eof)(i)?; - let (i, content) = opt(recognize(skip_till(p_start)))(i)?; - let (i, content) = match content { - Some("") => { - // {block,comment,expr}_start follows immediately. - return Err(nom::Err::Error(error_position!(i, ErrorKind::TakeUntil))); - } - Some(content) => (i, content), - None => ("", i), // there is no {block,comment,expr}_start: take everything - }; - Ok((i, split_ws_parts(content))) - } - fn parse(i: &'a str, s: &State<'_>) -> IResult<&'a str, Self> { let mut p = tuple(( |i| s.tag_block_start(i), @@ -244,13 +224,10 @@ impl<'a> Node<'a> { )); let (_, (pws1, _, (nws1, _, (contents, (i, (_, pws2, _, nws2, _)))))) = p(i)?; - let (lws, val, rws) = match split_ws_parts(contents) { - Node::Lit(lws, val, rws) => (lws, val, rws), - _ => unreachable!(), - }; + let val = Lit::split_ws_parts(contents); let ws1 = Ws(pws1, nws1); let ws2 = Ws(pws2, nws2); - Ok((i, Self::Raw(ws1, lws, val, rws, ws2))) + Ok((i, Self::Raw(ws1, val, ws2))) } fn r#break(i: &'a str, s: &State<'_>) -> IResult<&'a str, Self> { @@ -795,6 +772,46 @@ impl<'a> BlockDef<'a> { } } +#[derive(Debug, PartialEq)] +pub struct Lit<'a> { + pub lws: &'a str, + pub val: &'a str, + pub rws: &'a str, +} + +impl<'a> Lit<'a> { + fn parse(i: &'a str, s: &State<'_>) -> IResult<&'a str, Self> { + let p_start = alt(( + tag(s.syntax.block_start), + tag(s.syntax.comment_start), + tag(s.syntax.expr_start), + )); + + let (i, _) = not(eof)(i)?; + let (i, content) = opt(recognize(skip_till(p_start)))(i)?; + let (i, content) = match content { + Some("") => { + // {block,comment,expr}_start follows immediately. + return Err(nom::Err::Error(error_position!(i, ErrorKind::TakeUntil))); + } + Some(content) => (i, content), + None => ("", i), // there is no {block,comment,expr}_start: take everything + }; + Ok((i, Self::split_ws_parts(content))) + } + + pub(crate) fn split_ws_parts(s: &'a str) -> Self { + let trimmed_start = s.trim_start_matches(is_ws); + let len_start = s.len() - trimmed_start.len(); + let trimmed = trimmed_start.trim_end_matches(is_ws); + Self { + lws: &s[..len_start], + val: trimmed, + rws: &trimmed_start[trimmed.len()..], + } + } +} + /// First field is "minus/plus sign was used on the left part of the item". /// /// Second field is "minus/plus sign was used on the right part of the item". diff --git a/askama_parser/src/tests.rs b/askama_parser/src/tests.rs index 61aa279..4717652 100644 --- a/askama_parser/src/tests.rs +++ b/askama_parser/src/tests.rs @@ -1,16 +1,10 @@ -use super::{Ast, Expr, Node, Syntax, Whitespace, Ws}; +use super::{Ast, Expr, Lit, Node, Syntax, Whitespace, Ws}; fn check_ws_split(s: &str, res: &(&str, &str, &str)) { - match super::split_ws_parts(s) { - Node::Lit(lws, s, rws) => { - assert_eq!(lws, res.0); - assert_eq!(s, res.1); - assert_eq!(rws, res.2); - } - _ => { - panic!("fail"); - } - } + let Lit { lws, val, rws } = Lit::split_ws_parts(s); + assert_eq!(lws, res.0); + assert_eq!(val, res.1); + assert_eq!(rws, res.2); } #[test] -- cgit