Skip to content

Instantly share code, notes, and snippets.

@jg-rp
jg-rp / eval_expression.py
Created January 4, 2022 17:32
Arithmetic expression evaluation using a stack
"""Evaluate arithmetic expressions using a stack by fist converting
an expression from infix notation to postfix notation.
Expressions are tokenized using regular expressions, as described at
https://docs.python.org/3/library/re.html#writing-a-tokenizer
"""
import operator
import re
from collections import deque
@jg-rp
jg-rp / _intro.md
Last active September 2, 2022 06:14
Liquid expression lexer and parser with SLY

A SLY lexer and parser for Liquid filtered expressions.

Filtered expressions are those found in Liquid output statements, echo tags and assign tags.

The result of FilteredExpressionParser().parse() is an AST built from existing Python Liquid Expression objects, rooted at a FilteredExpression.

This is intended to be an example of how one might use SLY to parse an expression for a custom tag in Python Liquid. The tags built-in to Python Liquid do not use SLY (or PLY or any other general purpose parsing package), instead we chose to write our own lexers and recursive descent parsers, one for each of the common Liquid expression types. This decision was made on performance grounds. Benchmarks show Python Liquid's parser to be roughly three times faster for filtered expressions than this SLY implementation.

The following grammar defines the "standard" Liquid filtered expression,

@jg-rp
jg-rp / with_tag.py
Last active September 2, 2022 06:09
# type: ignore
"""
A SLY lexer and parser for a Liquid `with` tag.
expr : ID ":" value { "," ID ":" value }
value : literal
| path
literal : FLOAT
@jg-rp
jg-rp / assignment_expression.bnf
Last active September 9, 2023 21:34
Liquid template expression syntax
expression : ID "=" filtered
filtered : left { "|" filter }
left : literal
| path
| range
literal : FLOAT
| INTEGER