Compare commits

...

3 Commits

Author SHA1 Message Date
Dylan Thacker-Smith
0e25e5d5e8 seperator -> separator 2015-07-09 17:03:42 -04:00
Dylan Thacker-Smith
77bdccf5ec Try to make the regexes more readable. 2015-07-09 16:14:36 -04:00
Dylan Thacker-Smith
87e3234b58 Add a lax warning mode to see where we can make the lax parser stricter. 2015-07-09 16:14:32 -04:00
3 changed files with 57 additions and 10 deletions

View File

@@ -3,7 +3,7 @@ module Liquid
def parse_with_selected_parser(markup) def parse_with_selected_parser(markup)
case parse_context.error_mode case parse_context.error_mode
when :strict then strict_parse_with_error_context(markup) when :strict then strict_parse_with_error_context(markup)
when :lax then lax_parse(markup) when :lax, :lax_warn then lax_parse(markup)
when :warn when :warn
begin begin
return strict_parse_with_error_context(markup) return strict_parse_with_error_context(markup)

View File

@@ -10,7 +10,16 @@ module Liquid
# {{ user | link }} # {{ user | link }}
# #
class Variable class Variable
FilterParser = /(?:\s+|#{QuotedFragment}|#{ArgumentSeparator})+/o capture_ignored_variable_prefix = /([\s,\|'"]+?)??/
capture_expression = /(#{QuotedFragment})/o
capture_ignored_filter_prefix = /([^\|]+?)??/
capture_filters = /(#{FilterSeparator}.*)/o
VariableSyntax = /\A\s*#{capture_ignored_variable_prefix}\s*#{capture_expression}\s*(?:#{capture_ignored_filter_prefix}\s*#{capture_filters})?\z/om
capture_lax_separator = /(['"\|]+?)/
capture_filter = /((?:\s+|#{QuotedFragment}|#{ArgumentSeparator})+)/o
FilterParser = /\s*(?:#{FilterSeparator}|#{capture_lax_separator})\s*#{capture_filter}/o
attr_accessor :filters, :name, :line_number attr_accessor :filters, :name, :line_number
attr_reader :parse_context attr_reader :parse_context
alias_method :options, :parse_context alias_method :options, :parse_context
@@ -35,16 +44,19 @@ module Liquid
def lax_parse(markup) def lax_parse(markup)
@filters = [] @filters = []
return unless markup =~ /(#{QuotedFragment})(.*)/om return unless markup =~ VariableSyntax
name_markup = $1 add_syntax_warning("variable prefixed with ignored characters: #{$1.inspect}") if $1
filter_markup = $2 name_markup = $2
add_syntax_warning("variable filter separator prefixed with ignored characters: #{$3.inspect}") if $3
filters_markup = $4
@name = Expression.parse(name_markup) @name = Expression.parse(name_markup)
if filter_markup =~ /#{FilterSeparator}\s*(.*)/om if filters_markup
filters = $1.scan(FilterParser) filters_markup.scan(FilterParser) do |lax_sep, f|
filters.each do |f| add_syntax_warning("unterminated quote or multiple pipe characters used as a filter separator: #{lax_sep.inspect}") if lax_sep
next unless f =~ /\w+/ next unless f =~ /\A\s*(\W+)??(\w+)/
filtername = Regexp.last_match(0) add_syntax_warning("ignored characters before filter name: #{$1.inspect}") if $1
filtername = $2
filterargs = f.scan(/(?:#{FilterArgumentSeparator}|#{ArgumentSeparator})\s*((?:\w+\s*\:\s*)?#{QuotedFragment})/o).flatten filterargs = f.scan(/(?:#{FilterArgumentSeparator}|#{ArgumentSeparator})\s*((?:\w+\s*\:\s*)?#{QuotedFragment})/o).flatten
@filters << parse_filter_expressions(filtername, filterargs) @filters << parse_filter_expressions(filtername, filterargs)
end end
@@ -81,6 +93,13 @@ module Liquid
private private
def add_syntax_warning(warning)
return unless parse_context.error_mode == :lax_warn
error = SyntaxError.new(warning)
error.line_number = parse_context.line_number
parse_context.warnings << error
end
def parse_filter_expressions(filter_name, unparsed_args) def parse_filter_expressions(filter_name, unparsed_args)
filter_args = [] filter_args = []
keyword_args = {} keyword_args = {}

View File

@@ -89,4 +89,32 @@ class VariableTest < Minitest::Test
def test_multiline_variable def test_multiline_variable
assert_equal 'worked', Template.parse("{{\ntest\n}}").render!('test' => 'worked') assert_equal 'worked', Template.parse("{{\ntest\n}}").render!('test' => 'worked')
end end
def test_lax_warnings_for_variable_ignored_prefix
ignored_chars = %(|,'")
template = Liquid::Template.parse("{{ #{ignored_chars}test }}", error_mode: :lax_warn)
assert_equal "works", template.render!('test' => 'works')
assert_equal [Liquid::SyntaxError.new("variable prefixed with ignored characters: #{ignored_chars.inspect}")], template.warnings
end
def test_lax_warnings_for_ignored_variable_filter_prefix
ignored_chars = ",wat? lax!"
template = Liquid::Template.parse("{{ test#{ignored_chars} | noop }}", error_mode: :lax_warn)
assert_equal "works", template.render!('test' => 'works')
assert_equal [Liquid::SyntaxError.new("variable filter separator prefixed with ignored characters: #{ignored_chars.inspect}")], template.warnings
end
def test_lax_warnings_for_weird_filter_chars
template = Liquid::Template.parse("{{ test | upcase \" prepend: 'it ' || append: ' surprisingly' }}", error_mode: :lax_warn)
assert_equal "it WORKS surprisingly", template.render!('test' => 'works')
expected_warnings = ['"', '||'].map{ |sep| Liquid::SyntaxError.new("unterminated quote or multiple pipe characters used as a filter separator: #{sep.inspect}") }
assert_equal expected_warnings, template.warnings
end
def test_lax_warnings_for_ignored_filter_name_prefix
ignored_chars = "'': '"
template = Liquid::Template.parse("{{ test | '': 'prepend ' }}", error_mode: :lax_warn)
assert_equal "prepend wat", template.render!('test' => 'wat')
assert_equal [Liquid::SyntaxError.new("ignored characters before filter name: #{ignored_chars.inspect}")], template.warnings
end
end end