From 913605499a2fd16acc8fff57901e1609acfc2beb Mon Sep 17 00:00:00 2001
From: Andrew Dona-Couch <hi@andrewcou.ch>
Date: Tue, 28 Feb 2023 22:18:35 -0500
Subject: [PATCH] Extract askama_parser from askama_derive

---
 Cargo.toml                                    |  1 +
 askama_derive/Cargo.toml                      |  1 +
 askama_derive/src/config.rs                   |  2 +-
 askama_derive/src/generator.rs                |  4 +-
 askama_derive/src/heritage.rs                 |  4 +-
 askama_derive/src/input.rs                    |  2 +-
 askama_derive/src/lib.rs                      |  1 -
 askama_parser/Cargo.toml                      | 14 ++++++
 .../src/parser => askama_parser/src}/error.rs |  2 +-
 .../src/parser => askama_parser/src}/expr.rs  | 12 ++---
 .../parser/mod.rs => askama_parser/src/lib.rs | 19 +++----
 .../src/parser => askama_parser/src}/node.rs  | 50 +++++++++----------
 .../parser => askama_parser/src}/syntax.rs    | 14 +++---
 .../src/parser => askama_parser/src}/tests.rs |  0
 14 files changed, 69 insertions(+), 57 deletions(-)
 create mode 100644 askama_parser/Cargo.toml
 rename {askama_derive/src/parser => askama_parser/src}/error.rs (95%)
 rename {askama_derive/src/parser => askama_parser/src}/expr.rs (97%)
 rename askama_derive/src/parser/mod.rs => askama_parser/src/lib.rs (96%)
 rename {askama_derive/src/parser => askama_parser/src}/node.rs (95%)
 rename {askama_derive/src/parser => askama_parser/src}/syntax.rs (54%)
 rename {askama_derive/src/parser => askama_parser/src}/tests.rs (100%)

diff --git a/Cargo.toml b/Cargo.toml
index bd8b8daf5..b7f6fd6bc 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -7,6 +7,7 @@ members = [
     "askama_derive",
     "askama_escape",
     "askama_mendes",
+    "askama_parser",
     "askama_rocket",
     "askama_tide",
     "askama_warp",
diff --git a/askama_derive/Cargo.toml b/askama_derive/Cargo.toml
index c13e7cafb..9715e615a 100644
--- a/askama_derive/Cargo.toml
+++ b/askama_derive/Cargo.toml
@@ -31,6 +31,7 @@ with-tide = []
 with-warp = []
 
 [dependencies]
+askama_parser = { version = "0.1", path = "../askama_parser" }
 mime = "0.3"
 mime_guess = "2"
 nom = "7"
diff --git a/askama_derive/src/config.rs b/askama_derive/src/config.rs
index 639e3fea3..7196bb45b 100644
--- a/askama_derive/src/config.rs
+++ b/askama_derive/src/config.rs
@@ -6,7 +6,7 @@ use std::{env, fs};
 #[cfg(feature = "serde")]
 use serde::Deserialize;
 
-use crate::parser::{CompileError, Syntax};
+use askama_parser::{CompileError, Syntax};
 
 #[derive(Debug)]
 pub(crate) struct Config<'a> {
diff --git a/askama_derive/src/generator.rs b/askama_derive/src/generator.rs
index 95b1664a2..ebd8a8eb4 100644
--- a/askama_derive/src/generator.rs
+++ b/askama_derive/src/generator.rs
@@ -1,8 +1,8 @@
 use crate::config::{get_template_source, read_config_file, Config, WhitespaceHandling};
 use crate::heritage::{Context, Heritage};
 use crate::input::{Print, Source, TemplateInput};
-use crate::parser::node::{Cond, CondTest, Loop, Node, Target, When, Whitespace, Ws};
-use crate::parser::{parse, CompileError, Expr};
+use askama_parser::node::{Cond, CondTest, Loop, Node, Target, When, Whitespace, Ws};
+use askama_parser::{parse, CompileError, Expr};
 
 use proc_macro::TokenStream;
 use proc_macro2::Span;
diff --git a/askama_derive/src/heritage.rs b/askama_derive/src/heritage.rs
index 4ba8ec4a4..7c06d4992 100644
--- a/askama_derive/src/heritage.rs
+++ b/askama_derive/src/heritage.rs
@@ -2,8 +2,8 @@ use std::collections::HashMap;
 use std::path::{Path, PathBuf};
 
 use crate::config::Config;
-use crate::parser::error::CompileError;
-use crate::parser::node::{Loop, Macro, Node};
+use askama_parser::error::CompileError;
+use askama_parser::node::{Loop, Macro, Node};
 
 pub(crate) struct Heritage<'a> {
     pub(crate) root: &'a Context<'a>,
diff --git a/askama_derive/src/input.rs b/askama_derive/src/input.rs
index 82cdd8933..5c842e0d1 100644
--- a/askama_derive/src/input.rs
+++ b/askama_derive/src/input.rs
@@ -1,6 +1,6 @@
 use crate::config::Config;
 use crate::generator::TemplateArgs;
-use crate::parser::{CompileError, Syntax};
+use askama_parser::{CompileError, Syntax};
 
 use std::path::{Path, PathBuf};
 use std::str::FromStr;
diff --git a/askama_derive/src/lib.rs b/askama_derive/src/lib.rs
index 6d7237072..439799eb4 100644
--- a/askama_derive/src/lib.rs
+++ b/askama_derive/src/lib.rs
@@ -8,7 +8,6 @@ mod config;
 mod generator;
 mod heritage;
 mod input;
-mod parser;
 
 #[proc_macro_derive(Template, attributes(template))]
 pub fn derive_template(input: TokenStream) -> TokenStream {
diff --git a/askama_parser/Cargo.toml b/askama_parser/Cargo.toml
new file mode 100644
index 000000000..c38699e7e
--- /dev/null
+++ b/askama_parser/Cargo.toml
@@ -0,0 +1,14 @@
+[package]
+name = "askama_parser"
+version = "0.1.0"
+description = "Askama template syntax parser"
+homepage = "https://github.com/djc/askama"
+repository = "https://github.com/djc/askama"
+license = "MIT OR Apache-2.0"
+workspace = ".."
+readme = "../README.md"
+edition = "2021"
+rust-version = "1.58"
+
+[dependencies]
+nom = "7"
diff --git a/askama_derive/src/parser/error.rs b/askama_parser/src/error.rs
similarity index 95%
rename from askama_derive/src/parser/error.rs
rename to askama_parser/src/error.rs
index 27f449778..56b2060d5 100644
--- a/askama_derive/src/parser/error.rs
+++ b/askama_parser/src/error.rs
@@ -2,7 +2,7 @@ use std::borrow::Cow;
 use std::fmt;
 
 #[derive(Debug, Clone)]
-pub(crate) struct CompileError {
+pub struct CompileError {
     msg: Cow<'static, str>,
 }
 
diff --git a/askama_derive/src/parser/expr.rs b/askama_parser/src/expr.rs
similarity index 97%
rename from askama_derive/src/parser/expr.rs
rename to askama_parser/src/expr.rs
index fabaa34cc..bb5ce48b5 100644
--- a/askama_derive/src/parser/expr.rs
+++ b/askama_parser/src/expr.rs
@@ -13,7 +13,7 @@ use super::{
 };
 
 #[derive(Debug, PartialEq)]
-pub(crate) enum Expr<'a> {
+pub enum Expr<'a> {
     BoolLit(&'a str),
     NumLit(&'a str),
     StrLit(&'a str),
@@ -35,17 +35,17 @@ pub(crate) enum Expr<'a> {
 }
 
 impl Expr<'_> {
-    pub(super) fn parse(i: &str) -> IResult<&str, Expr<'_>> {
+    pub(crate) fn parse(i: &str) -> IResult<&str, Expr<'_>> {
         expr_any(i)
     }
 
-    pub(super) fn parse_arguments(i: &str) -> IResult<&str, Vec<Expr<'_>>> {
+    pub(crate) fn parse_arguments(i: &str) -> IResult<&str, Vec<Expr<'_>>> {
         arguments(i)
     }
 
     /// Returns `true` if enough assumptions can be made,
     /// to determine that `self` is copyable.
-    pub(crate) fn is_copyable(&self) -> bool {
+    pub fn is_copyable(&self) -> bool {
         self.is_copyable_within_op(false)
     }
 
@@ -73,7 +73,7 @@ impl Expr<'_> {
     }
 
     /// Returns `true` if this is an `Attr` where the `obj` is `"self"`.
-    pub(crate) fn is_attr_self(&self) -> bool {
+    pub fn is_attr_self(&self) -> bool {
         match self {
             Expr::Attr(obj, _) if matches!(obj.as_ref(), Expr::Var("self")) => true,
             Expr::Attr(obj, _) if matches!(obj.as_ref(), Expr::Attr(..)) => obj.is_attr_self(),
@@ -84,7 +84,7 @@ impl Expr<'_> {
     /// Returns `true` if the outcome of this expression may be used multiple times in the same
     /// `write!()` call, without evaluating the expression again, i.e. the expression should be
     /// side-effect free.
-    pub(crate) fn is_cacheable(&self) -> bool {
+    pub fn is_cacheable(&self) -> bool {
         match self {
             // Literals are the definition of pure:
             Expr::BoolLit(_) => true,
diff --git a/askama_derive/src/parser/mod.rs b/askama_parser/src/lib.rs
similarity index 96%
rename from askama_derive/src/parser/mod.rs
rename to askama_parser/src/lib.rs
index a1d98580c..f1b2c0d3e 100644
--- a/askama_derive/src/parser/mod.rs
+++ b/askama_parser/src/lib.rs
@@ -11,15 +11,15 @@ use nom::multi::separated_list1;
 use nom::sequence::{delimited, pair, tuple};
 use nom::{error_position, AsChar, IResult, InputTakeAtPosition};
 
-pub(crate) use self::error::CompileError;
-pub(crate) use self::expr::Expr;
+pub use self::error::CompileError;
+pub use self::expr::Expr;
 use self::node::{Node, Whitespace};
-pub(crate) use self::syntax::Syntax;
+pub use self::syntax::Syntax;
 
-pub(crate) mod error;
-pub(crate) mod expr;
-pub(crate) mod node;
-pub(crate) mod syntax;
+pub mod error;
+pub mod expr;
+pub mod node;
+pub mod syntax;
 #[cfg(test)]
 mod tests;
 
@@ -60,10 +60,7 @@ impl From<char> for Whitespace {
     }
 }
 
-pub(crate) fn parse<'a>(
-    src: &'a str,
-    syntax: &'a Syntax<'_>,
-) -> Result<Vec<Node<'a>>, CompileError> {
+pub fn parse<'a>(src: &'a str, syntax: &'a Syntax<'_>) -> Result<Vec<Node<'a>>, CompileError> {
     match Node::parse(src, &State::new(syntax)) {
         Ok((left, res)) => {
             if !left.is_empty() {
diff --git a/askama_derive/src/parser/node.rs b/askama_parser/src/node.rs
similarity index 95%
rename from askama_derive/src/parser/node.rs
rename to askama_parser/src/node.rs
index 9f8b37ba0..7b6a009aa 100644
--- a/askama_derive/src/parser/node.rs
+++ b/askama_parser/src/node.rs
@@ -16,7 +16,7 @@ use super::{
 };
 
 #[derive(Debug, PartialEq)]
-pub(crate) enum Node<'a> {
+pub enum Node<'a> {
     Lit(&'a str, &'a str, &'a str),
     Comment(Ws),
     Expr(Ws, Expr<'a>),
@@ -37,7 +37,7 @@ pub(crate) enum Node<'a> {
 }
 
 #[derive(Debug, PartialEq)]
-pub(crate) enum Target<'a> {
+pub enum Target<'a> {
     Name(&'a str),
     Tuple(Vec<&'a str>, Vec<Target<'a>>),
     Struct(Vec<&'a str>, Vec<(&'a str, Target<'a>)>),
@@ -49,56 +49,56 @@ pub(crate) enum Target<'a> {
 }
 
 #[derive(Clone, Copy, Debug, PartialEq)]
-pub(crate) enum Whitespace {
+pub enum Whitespace {
     Preserve,
     Suppress,
     Minimize,
 }
 
 #[derive(Debug, PartialEq)]
-pub(crate) struct Loop<'a> {
-    pub(crate) ws1: Ws,
-    pub(crate) var: Target<'a>,
-    pub(crate) iter: Expr<'a>,
-    pub(crate) cond: Option<Expr<'a>>,
-    pub(crate) body: Vec<Node<'a>>,
-    pub(crate) ws2: Ws,
-    pub(crate) else_block: Vec<Node<'a>>,
-    pub(crate) ws3: Ws,
+pub struct Loop<'a> {
+    pub ws1: Ws,
+    pub var: Target<'a>,
+    pub iter: Expr<'a>,
+    pub cond: Option<Expr<'a>>,
+    pub body: Vec<Node<'a>>,
+    pub ws2: Ws,
+    pub else_block: Vec<Node<'a>>,
+    pub ws3: Ws,
 }
 
-pub(crate) type When<'a> = (Ws, Target<'a>, Vec<Node<'a>>);
+pub type When<'a> = (Ws, Target<'a>, Vec<Node<'a>>);
 
 #[derive(Debug, PartialEq)]
-pub(crate) struct Macro<'a> {
-    pub(crate) ws1: Ws,
-    pub(crate) args: Vec<&'a str>,
-    pub(crate) nodes: Vec<Node<'a>>,
-    pub(crate) ws2: Ws,
+pub struct Macro<'a> {
+    pub ws1: Ws,
+    pub args: Vec<&'a str>,
+    pub nodes: Vec<Node<'a>>,
+    pub ws2: Ws,
 }
 
 /// 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".
 #[derive(Clone, Copy, Debug, PartialEq)]
-pub(crate) struct Ws(pub(crate) Option<Whitespace>, pub(crate) Option<Whitespace>);
+pub struct Ws(pub Option<Whitespace>, pub Option<Whitespace>);
 
-pub(crate) type Cond<'a> = (Ws, Option<CondTest<'a>>, Vec<Node<'a>>);
+pub type Cond<'a> = (Ws, Option<CondTest<'a>>, Vec<Node<'a>>);
 
 #[derive(Debug, PartialEq)]
-pub(crate) struct CondTest<'a> {
-    pub(crate) target: Option<Target<'a>>,
-    pub(crate) expr: Expr<'a>,
+pub struct CondTest<'a> {
+    pub target: Option<Target<'a>>,
+    pub expr: Expr<'a>,
 }
 
 impl Node<'_> {
-    pub(super) fn parse<'a>(i: &'a str, s: &State<'_>) -> IResult<&'a str, Vec<Node<'a>>> {
+    pub(crate) fn parse<'a>(i: &'a str, s: &State<'_>) -> IResult<&'a str, Vec<Node<'a>>> {
         parse_template(i, s)
     }
 }
 
 impl Target<'_> {
-    pub(super) fn parse(i: &str) -> IResult<&str, Target<'_>> {
+    pub(crate) fn parse(i: &str) -> IResult<&str, Target<'_>> {
         target(i)
     }
 }
diff --git a/askama_derive/src/parser/syntax.rs b/askama_parser/src/syntax.rs
similarity index 54%
rename from askama_derive/src/parser/syntax.rs
rename to askama_parser/src/syntax.rs
index 51c563a01..1ec0d448b 100644
--- a/askama_derive/src/parser/syntax.rs
+++ b/askama_parser/src/syntax.rs
@@ -1,11 +1,11 @@
 #[derive(Debug)]
-pub(crate) struct Syntax<'a> {
-    pub(crate) block_start: &'a str,
-    pub(crate) block_end: &'a str,
-    pub(crate) expr_start: &'a str,
-    pub(crate) expr_end: &'a str,
-    pub(crate) comment_start: &'a str,
-    pub(crate) comment_end: &'a str,
+pub struct Syntax<'a> {
+    pub block_start: &'a str,
+    pub block_end: &'a str,
+    pub expr_start: &'a str,
+    pub expr_end: &'a str,
+    pub comment_start: &'a str,
+    pub comment_end: &'a str,
 }
 
 impl Default for Syntax<'static> {
diff --git a/askama_derive/src/parser/tests.rs b/askama_parser/src/tests.rs
similarity index 100%
rename from askama_derive/src/parser/tests.rs
rename to askama_parser/src/tests.rs