Skip to content

Commit

Permalink
Extract askama_parser from askama_derive
Browse files Browse the repository at this point in the history
couchand committed Mar 6, 2023
1 parent 31759fc commit 3880bf4
Showing 12 changed files with 89 additions and 74 deletions.
2 changes: 2 additions & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
@@ -7,6 +7,7 @@ members = [
"askama_derive",
"askama_escape",
"askama_mendes",
"askama_parser",
"askama_rocket",
"askama_tide",
"askama_warp",
@@ -18,5 +19,6 @@ default-members = [
"askama",
"askama_derive",
"askama_escape",
"askama_parser",
"testing",
]
1 change: 1 addition & 0 deletions askama_derive/Cargo.toml
Original file line number Diff line number Diff line change
@@ -31,6 +31,7 @@ with-tide = []
with-warp = []

[dependencies]
askama_parser = { version = "0.1", path = "../askama_parser" }
mime = "0.3"
mime_guess = "2"
proc-macro2 = "1"
2 changes: 1 addition & 1 deletion askama_derive/src/config.rs
Original file line number Diff line number Diff line change
@@ -6,8 +6,8 @@ use std::{env, fs};
#[cfg(feature = "serde")]
use serde::Deserialize;

use crate::parser::Syntax;
use crate::CompileError;
use askama_parser::Syntax;

#[derive(Debug)]
pub(crate) struct Config<'a> {
4 changes: 2 additions & 2 deletions askama_derive/src/generator.rs
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
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::{
use crate::CompileError;
use askama_parser::{
parse, Block, BlockDef, Call, Cond, CondTest, Expr, Lit, Loop, Match, Node, Raw, Tag, Target,
When, Whitespace, Ws,
};
use crate::CompileError;

use proc_macro::TokenStream;
use quote::{quote, ToTokens};
2 changes: 1 addition & 1 deletion askama_derive/src/heritage.rs
Original file line number Diff line number Diff line change
@@ -2,8 +2,8 @@ use std::collections::HashMap;
use std::path::{Path, PathBuf};

use crate::config::Config;
use crate::parser::{Block, BlockDef, Cond, Loop, Macro, Match, Node, Tag, When};
use crate::CompileError;
use askama_parser::{Block, BlockDef, Cond, Loop, Macro, Match, Node, Tag, When};

pub(crate) struct Heritage<'a> {
pub(crate) root: &'a Context<'a>,
2 changes: 1 addition & 1 deletion askama_derive/src/input.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
use crate::config::Config;
use crate::generator::TemplateArgs;
use crate::parser::Syntax;
use crate::CompileError;
use askama_parser::Syntax;

use std::path::{Path, PathBuf};
use std::str::FromStr;
5 changes: 2 additions & 3 deletions askama_derive/src/lib.rs
Original file line number Diff line number Diff line change
@@ -11,7 +11,6 @@ mod config;
mod generator;
mod heritage;
mod input;
mod parser;

#[proc_macro_derive(Template, attributes(template))]
pub fn derive_template(input: TokenStream) -> TokenStream {
@@ -52,8 +51,8 @@ impl From<String> for CompileError {
}
}

impl From<parser::ParseError> for CompileError {
fn from(e: parser::ParseError) -> Self {
impl From<askama_parser::ParseError> for CompileError {
fn from(e: askama_parser::ParseError) -> Self {
Self::new(e.to_string())
}
}
14 changes: 14 additions & 0 deletions askama_parser/Cargo.toml
Original file line number Diff line number Diff line change
@@ -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"
Original file line number Diff line number Diff line change
@@ -16,7 +16,7 @@ use super::{

/// An Askama expression.
#[derive(Debug, PartialEq)]
pub(crate) enum Expr<'a> {
pub enum Expr<'a> {
/// A boolean literal.
BoolLit(&'a str),
/// A numeric literal.
@@ -66,7 +66,7 @@ impl Expr<'_> {

/// 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)
}

@@ -94,7 +94,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(),
@@ -105,7 +105,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,
35 changes: 17 additions & 18 deletions askama_derive/src/parser/mod.rs → askama_parser/src/lib.rs
Original file line number Diff line number Diff line change
@@ -23,8 +23,8 @@ use nom::multi::separated_list1;
use nom::sequence::{delimited, pair, tuple};
use nom::{error_position, AsChar, IResult, InputTakeAtPosition};

pub(crate) use self::expr::Expr;
pub(crate) use self::node::{
pub use self::expr::Expr;
pub use self::node::{
Block, BlockDef, Call, Cond, CondTest, Lit, Loop, Macro, Match, Node, Raw, Tag, Target, When,
};

@@ -35,19 +35,19 @@ mod tests;

/// Askama template syntax configuration.
#[derive(Debug)]
pub(crate) struct Syntax<'a> {
pub struct Syntax<'a> {
/// Defaults to `"{%"`.
pub(crate) block_start: &'a str,
pub block_start: &'a str,
/// Defaults to `"%}"`.
pub(crate) block_end: &'a str,
pub block_end: &'a str,
/// Defaults to `"{{"`.
pub(crate) expr_start: &'a str,
pub expr_start: &'a str,
/// Defaults to `"}}"`.
pub(crate) expr_end: &'a str,
pub expr_end: &'a str,
/// Defaults to `"{#"`.
pub(crate) comment_start: &'a str,
pub comment_start: &'a str,
/// Defaults to `"#}"`.
pub(crate) comment_end: &'a str,
pub comment_end: &'a str,
}

impl Default for Syntax<'static> {
@@ -65,19 +65,19 @@ impl Default for Syntax<'static> {

/// Whitespace preservation or suppression.
#[derive(Clone, Copy, Debug, PartialEq)]
pub(crate) enum Whitespace {
pub enum Whitespace {
Preserve,
Suppress,
Minimize,
}

/// Whitespace suppression for a `Tag` or `Block`.
#[derive(Clone, Copy, Debug, Default, PartialEq)]
pub(crate) struct Ws {
pub struct Ws {
/// Handling of trailing whitespace on literal text at a transition in to Askama.
pub(crate) flush: Option<Whitespace>,
pub flush: Option<Whitespace>,
/// Handling of leading whitespace on literal text at a transition out of Askama.
pub(crate) prepare: Option<Whitespace>,
pub prepare: Option<Whitespace>,
}

impl Ws {
@@ -127,7 +127,7 @@ impl From<char> for Whitespace {
/// Parse template source to an abstract syntax tree.
///
/// Tries to parse the provided template string using the given syntax.
pub(crate) fn parse<'a>(src: &'a str, syntax: &'a Syntax<'_>) -> Result<Block<'a>, ParseError> {
pub fn parse<'a>(src: &'a str, syntax: &'a Syntax<'_>) -> Result<Block<'a>, ParseError> {
let state = State::new(syntax);
let mut p = all_consuming(complete(|i| Node::parse(i, &state)));
match p(src) {
@@ -164,21 +164,20 @@ pub(crate) fn parse<'a>(src: &'a str, syntax: &'a Syntax<'_>) -> Result<Block<'a

/// An error encountered when parsing template source.
#[derive(Debug)]
pub(crate) struct ParseError {
pub struct ParseError {
row: usize,
column: usize,
snippet: String,
}

#[cfg(test)]
impl ParseError {
/// The line number in the source where the error was identified.
pub(crate) fn line(&self) -> usize {
pub fn line(&self) -> usize {
self.row
}

/// The column number in the source where the error was identified.
pub(crate) fn column(&self) -> usize {
pub fn column(&self) -> usize {
self.column
}
}
86 changes: 43 additions & 43 deletions askama_derive/src/parser/node.rs → askama_parser/src/node.rs
Original file line number Diff line number Diff line change
@@ -21,16 +21,16 @@ use super::{
///
/// This represents both the top-level block of a template and all sub-blocks of statement nodes.
#[derive(Debug, PartialEq)]
pub(crate) struct Block<'a> {
pub struct Block<'a> {
/// The nodes within the block.
pub(crate) nodes: Vec<Node<'a>>,
pub nodes: Vec<Node<'a>>,
/// Whitespace suppression for the inside of the block.
pub(crate) ws: Ws,
pub ws: Ws,
}

impl<'a> Block<'a> {
#[cfg(test)]
pub(crate) fn with_whitespace(ws: Ws) -> Self {
pub fn with_whitespace(ws: Ws) -> Self {
Block { nodes: vec![], ws }
}
}
@@ -43,7 +43,7 @@ impl<'a> PartialEq<Vec<Node<'a>>> for Block<'a> {

/// An Askama template abstract syntax tree node.
#[derive(Debug, PartialEq)]
pub(crate) enum Node<'a> {
pub enum Node<'a> {
/// Literal text to output directly.
Lit(Lit<'a>),
/// An Askama tag, either a comment, expression, or statement.
@@ -62,7 +62,7 @@ pub(crate) enum Node<'a> {
/// may or may not have a matching end tag, depending on the type of statement.
/// Statements with child `Block`s always require an end tag.
#[derive(Debug, PartialEq)]
pub(crate) enum Tag<'a> {
pub enum Tag<'a> {
/// A block comment.
///
/// ```ignore
@@ -182,7 +182,7 @@ pub(crate) enum Tag<'a> {

/// The Askama equivalent of a Rust pattern, the target of a match or assignment.
#[derive(Debug, PartialEq)]
pub(crate) enum Target<'a> {
pub enum Target<'a> {
/// Bind the value to a name.
Name(&'a str),
/// Destructure a tuple value.
@@ -203,104 +203,104 @@ pub(crate) enum Target<'a> {

/// A literal bit of text to output directly.
#[derive(Debug, PartialEq)]
pub(crate) struct Lit<'a> {
pub struct Lit<'a> {
/// White space preceeding the text.
pub(crate) lws: &'a str,
pub lws: &'a str,
/// The literal text itself.
pub(crate) val: &'a str,
pub val: &'a str,
/// White space following the text.
pub(crate) rws: &'a str,
pub rws: &'a str,
}

/// A raw block to output directly.
#[derive(Debug, PartialEq)]
pub(crate) struct Raw<'a> {
pub struct Raw<'a> {
/// The content of the raw block.
pub(crate) lit: Lit<'a>,
pub lit: Lit<'a>,
/// Whitespace suppression for the inside of the block.
pub(crate) ws: Ws,
pub ws: Ws,
}

/// A macro call statement.
#[derive(Debug, PartialEq)]
pub(crate) struct Call<'a> {
pub struct Call<'a> {
/// If the macro is imported, the scope name.
pub(crate) scope: Option<&'a str>,
pub scope: Option<&'a str>,
/// The name of the macro to call.
pub(crate) name: &'a str,
pub name: &'a str,
/// The arguments to the macro.
pub(crate) args: Vec<Expr<'a>>,
pub args: Vec<Expr<'a>>,
}

/// A match statement.
#[derive(Debug, PartialEq)]
pub(crate) struct Match<'a> {
pub struct Match<'a> {
/// The expression to match against.
pub(crate) expr: Expr<'a>,
pub expr: Expr<'a>,
/// Each of the match arms, with a pattern and a body.
pub(crate) arms: Vec<When<'a>>,
pub arms: Vec<When<'a>>,
}

/// A single arm of a match statement.
#[derive(Debug, PartialEq)]
pub(crate) struct When<'a> {
pub struct When<'a> {
/// The target pattern to match.
pub(crate) target: Target<'a>,
pub target: Target<'a>,
/// Body of the match arm.
pub(crate) block: Block<'a>,
pub block: Block<'a>,
}

/// A for loop syntax node.
#[derive(Debug, PartialEq)]
pub(crate) struct Loop<'a> {
pub struct Loop<'a> {
/// The variable of iteration within the loop.
pub(crate) var: Target<'a>,
pub var: Target<'a>,
/// The collection to iterate over.
pub(crate) iter: Expr<'a>,
pub iter: Expr<'a>,
/// An optional condition, which if it evaluates to false should skip that iteration.
pub(crate) cond: Option<Expr<'a>>,
pub cond: Option<Expr<'a>>,
/// The body of the loop.
pub(crate) body: Block<'a>,
pub body: Block<'a>,
/// The else block of the loop, invoked if the collection is empty.
pub(crate) else_block: Block<'a>,
pub else_block: Block<'a>,
}

/// A macro definition.
#[derive(Debug, PartialEq)]
pub(crate) struct Macro<'a> {
pub struct Macro<'a> {
/// The name of the macro.
pub(crate) name: &'a str,
pub name: &'a str,
/// Names of each of the macro's parameters.
pub(crate) args: Vec<&'a str>,
pub args: Vec<&'a str>,
/// The body of the macro.
pub(crate) block: Block<'a>,
pub block: Block<'a>,
}

/// A block statement, either a definition or a reference.
#[derive(Debug, PartialEq)]
pub(crate) struct BlockDef<'a> {
pub struct BlockDef<'a> {
/// The name of the block.
pub(crate) name: &'a str,
pub name: &'a str,
/// The contents of the block.
pub(crate) block: Block<'a>,
pub block: Block<'a>,
}

/// A single branch of a conditional statement.
#[derive(Debug, PartialEq)]
pub(crate) struct Cond<'a> {
pub struct Cond<'a> {
/// The test for this branch, or `None` for the `else` branch.
pub(crate) test: Option<CondTest<'a>>,
pub test: Option<CondTest<'a>>,
/// Body of this conditional branch.
pub(crate) block: Block<'a>,
pub block: Block<'a>,
}

/// An if or if let condition.
#[derive(Debug, PartialEq)]
pub(crate) struct CondTest<'a> {
pub struct CondTest<'a> {
/// For an if let, the assignment target.
pub(crate) target: Option<Target<'a>>,
pub target: Option<Target<'a>>,
/// The condition expression to evaluate.
pub(crate) expr: Expr<'a>,
pub expr: Expr<'a>,
}

impl Node<'_> {
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
use crate::parser::{Block, Expr, Lit, Node, Syntax, Tag, Target, Whitespace, Ws};
use crate::{Block, Expr, Lit, Node, Syntax, Tag, Target, Whitespace, Ws};

fn check_ws_split(s: &str, res: &(&str, &str, &str)) {
let Lit { lws, val, rws } = super::split_ws_parts(s);

0 comments on commit 3880bf4

Please sign in to comment.