Skip to content

Commit

Permalink
Key map literals with quoted strings
Browse files Browse the repository at this point in the history
  • Loading branch information
rossmacarthur committed Jan 18, 2025
1 parent 97fca45 commit 043f02b
Show file tree
Hide file tree
Showing 9 changed files with 33 additions and 132 deletions.
File renamed without changes.
104 changes: 0 additions & 104 deletions benches/benchdata/literals/upon.html

This file was deleted.

4 changes: 2 additions & 2 deletions benches/benches/engines.rs
Original file line number Diff line number Diff line change
Expand Up @@ -76,8 +76,8 @@ pub fn bench_compile(c: &mut Criterion) {

{
let mut g = c.benchmark_group("compile/literals");
bench!(g, Minijinja, "literals/minijinja.html");
bench!(g, Upon, "literals/upon.html");
bench!(g, Minijinja, "literals/jinja.html");
bench!(g, Upon, "literals/jinja.html");
}
}

Expand Down
4 changes: 2 additions & 2 deletions benches/src/tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -66,12 +66,12 @@ fn filters_upon() {

#[test]
fn literals_minijinja() {
t!(Minijinja, "../benchdata/literals/minijinja.html");
t!(Minijinja, "../benchdata/literals/jinja.html");
}

#[test]
fn literals_upon() {
t!(Upon, "../benchdata/literals/upon.html");
t!(Upon, "../benchdata/literals/jinja.html");
}

#[test]
Expand Down
37 changes: 21 additions & 16 deletions src/compile/parse.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,9 +7,9 @@ use crate::{Engine, Error, Result, Value};

/// A parser that constructs an AST from a token stream.
///
/// The parser is implemented as a simple hand written parser with no recursion.
/// It sometimes needs to peek at the next token to know how to proceed and uses
/// the `peeked` buffer to do this.
/// The parser is implemented as a simple hand written parser. It sometimes
/// needs to peek at the next token to know how to proceed and uses the `peeked`
/// buffer to do this.
pub struct Parser<'engine, 'source> {
/// A lexer that tokenizes the template source.
tokens: Lexer<'engine, 'source>,
Expand Down Expand Up @@ -403,9 +403,7 @@ impl<'engine, 'source> Parser<'engine, 'source> {
}
Keyword::EndWith => Ok(Block::EndWith),
Keyword::Include => {
let span = self.expect(Token::String)?;
let name = self.parse_string(span)?;
let name = ast::String { name, span };
let name = self.parse_string()?;
let globals = if self.is_next_keyword(Keyword::With)? {
self.expect_keyword(Keyword::With)?;
Some(self.parse_expr()?)
Expand Down Expand Up @@ -437,7 +435,7 @@ impl<'engine, 'source> Parser<'engine, 'source> {

/// Parses an expression.
///
/// This is a variable with zero or more function calls. For example:
/// This is a base expression with zero or more function calls. For example:
///
/// user.name | lower | prefix: "Mr. "
///
Expand Down Expand Up @@ -678,7 +676,7 @@ impl<'engine, 'source> Parser<'engine, 'source> {
}
}

/// Parse an integer.
/// Parse a literal integer.
fn parse_literal_integer(&self, raw: &str, span: Span, sign: Sign) -> Result<ast::Literal> {
let digits = raw.as_bytes();
let (i, radix) = match digits {
Expand Down Expand Up @@ -718,7 +716,7 @@ impl<'engine, 'source> Parser<'engine, 'source> {
Ok(ast::Literal { value, span })
}

/// Parses a float.
/// Parses a literal float.
fn parse_literal_float(&self, raw: &str, span: Span, sign: Sign) -> Result<ast::Literal> {
let float: f64 = raw
.parse()
Expand All @@ -730,14 +728,21 @@ impl<'engine, 'source> Parser<'engine, 'source> {
Ok(ast::Literal { value, span })
}

/// Parses a string.
/// Parses a literal string.
fn parse_literal_string(&self, span: Span) -> Result<ast::Literal> {
let value = Value::String(self.parse_string(span)?);
let value = Value::String(self.parse_quoted_string(span)?);
Ok(ast::Literal { value, span })
}

/// Parses a string and handles escape characters.
fn parse_string(&self, span: Span) -> Result<String> {
/// Parses a string.
fn parse_string(&mut self) -> Result<ast::String> {
let span = self.expect(Token::String)?;
let value = self.parse_quoted_string(span)?;
Ok(ast::String { value, span })
}

/// Parses a quoted string and handles escape characters.
fn parse_quoted_string(&self, span: Span) -> Result<String> {
let raw = &self.source()[span];
let string = if raw.contains('\\') {
let mut iter = raw.char_indices().map(|(i, c)| (span.m + i, c));
Expand Down Expand Up @@ -774,7 +779,7 @@ impl<'engine, 'source> Parser<'engine, 'source> {
Ok(string)
}

/// Parses a list literal.
/// Parses a list.
fn parse_list(&mut self, span: Span) -> Result<ast::List> {
let mut items = Vec::new();
loop {
Expand All @@ -792,14 +797,14 @@ impl<'engine, 'source> Parser<'engine, 'source> {
Ok(ast::List { items, span })
}

/// Parses a map literal.
/// Parses a map.
fn parse_map(&mut self, span: Span) -> Result<ast::Map> {
let mut items = Vec::new();
loop {
if self.is_next(Token::CloseBrace)? {
break;
}
let key = self.parse_ident()?;
let key = self.parse_string()?;
self.expect(Token::Colon)?;
let value = self.parse_base_expr()?;
items.push((key, value));
Expand Down
2 changes: 1 addition & 1 deletion src/render/core.rs
Original file line number Diff line number Diff line change
Expand Up @@ -246,7 +246,7 @@ where
}

Instr::ExprMapInsert(key) => {
let key = t.source[key.span].to_owned();
let key = key.value.clone();
let (value, _) = exprs.pop().unwrap();
match exprs.last_mut().unwrap() {
(ValueCow::Owned(Value::Map(m)), _) => {
Expand Down
6 changes: 3 additions & 3 deletions src/types/ast.rs
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@ pub struct Include {

#[cfg_attr(internal_debug, derive(Debug))]
pub struct String {
pub name: std::string::String,
pub value: std::string::String,
pub span: Span,
}

Expand Down Expand Up @@ -155,7 +155,7 @@ pub struct List {

#[cfg_attr(internal_debug, derive(Debug))]
pub struct Map {
pub items: Vec<(Ident, BaseExpr)>,
pub items: Vec<(String, BaseExpr)>,
pub span: Span,
}

Expand All @@ -167,7 +167,7 @@ impl Scope {

impl String {
pub fn as_str(&self) -> &str {
self.name.as_str()
self.value.as_str()
}
}

Expand Down
2 changes: 1 addition & 1 deletion src/types/program.rs
Original file line number Diff line number Diff line change
Expand Up @@ -71,7 +71,7 @@ pub enum Instr {
ExprListPush,

/// Insert an item to the current map expression
ExprMapInsert(ast::Ident),
ExprMapInsert(ast::String),

/// Apply the filter using the value and args on the top of the stack.
///
Expand Down
6 changes: 3 additions & 3 deletions tests/render.rs
Original file line number Diff line number Diff line change
Expand Up @@ -138,7 +138,7 @@ fn render_inline_expr_literal_map() {
let mut engine = Engine::new();
engine.add_formatter("debug", debug);
let result = engine
.compile(r#"{{ {a: true, b: 123, c: -3.14, d: "test", e: lorem} | debug }}"#)
.compile(r#"{{ {"a": true, "b": 123, "c": -3.14, "d": "test", "e": lorem} | debug }}"#)
.unwrap()
.render(&engine, value! { lorem: "ipsum" })
.to_string()
Expand All @@ -151,7 +151,7 @@ fn render_inline_expr_nested_lists_and_maps() {
let mut engine = Engine::new();
engine.add_formatter("debug", debug);
let result = engine
.compile(r#"{{ [true, [123, -3.14], {a: "test", b: lorem, c: [1, 2]}] | debug }}"#)
.compile(r#"{{ [true, [123, -3.14], {"a": "test", "b": lorem, "c": [1, 2]}] | debug }}"#)
.unwrap()
.render(&engine, value! { lorem: "ipsum" })
.to_string()
Expand Down Expand Up @@ -1170,7 +1170,7 @@ fn render_include_with_statement_map() {
let mut engine = Engine::new();
engine.add_template("nested", "{{ dolor }}").unwrap();
let result = engine
.compile(r#"lorem {% include "nested" with { dolor: dolor } %} sit"#)
.compile(r#"lorem {% include "nested" with { "dolor": dolor } %} sit"#)
.unwrap()
.render(&engine, value! { dolor: "test" })
.to_string()
Expand Down

0 comments on commit 043f02b

Please sign in to comment.