diff --git a/Rakefile b/Rakefile index 862e80f..6fabb88 100755 --- a/Rakefile +++ b/Rakefile @@ -7,6 +7,11 @@ require 'rubygems/package_task' task :default => 'test' +task :ragel do + sh "find . -name '*.rl' | xargs ragel -R" +end + + Rake::TestTask.new(:test) do |t| t.libs << '.' << 'lib' << 'test' t.test_files = FileList['test/liquid/**/*_test.rb'] diff --git a/lib/liquid.rb b/lib/liquid.rb index 82676d0..c641dea 100644 --- a/lib/liquid.rb +++ b/lib/liquid.rb @@ -62,6 +62,7 @@ require 'liquid/standardfilters' require 'liquid/condition' require 'liquid/module_ex' require 'liquid/utils' +require 'liquid/parser' # Load all the tags of the standard library # diff --git a/lib/liquid/context.rb b/lib/liquid/context.rb index 129b71a..a023733 100644 --- a/lib/liquid/context.rb +++ b/lib/liquid/context.rb @@ -1,5 +1,6 @@ module Liquid + # Context keeps the variable stack and resolves variables, as well as keywords # # context['variable'] = 'testing' @@ -125,13 +126,6 @@ module Liquid end private - LITERALS = { - nil => nil, 'nil' => nil, 'null' => nil, '' => nil, - 'true' => true, - 'false' => false, - 'blank' => :blank?, - 'empty' => :empty? - } # Look up variable, either resolve directly after considering the name. We can directly handle # Strings, digits, floats and booleans (true,false). @@ -141,25 +135,42 @@ module Liquid # # Example: # products == empty #=> products.empty? - def resolve(key) - if LITERALS.key?(key) - LITERALS[key] - else - case key - when /^'(.*)'$/ # Single quoted strings - $1 - when /^"(.*)"$/ # Double quoted strings - $1 - when /^(-?\d+)$/ # Integer and floats - $1.to_i - when /^\((\S+)\.\.(\S+)\)$/ # Ranges - (resolve($1).to_i..resolve($2).to_i) - when /^(-?\d[\d\.]+)$/ # Floats - $1.to_f - else - variable(key) + def resolve(key) + case key + when nil, "" + return nil + when "blank?" + return :blank + when "empty?" + return :empty + end + + puts "resolve(#{key})" + + result = Parser.parse(key) + stack = [] + + result.each do |(sym, value)| + case sym + when :identifier + stack.push value + when :lookup + left = stack.pop + stack.push find_variable(left) + when :range + right = stack.pop.to_i + left = stack.pop.to_i + stack.push (left..right) + when :call + parent = stack.pop + key = stack.pop + stack.push lookup_and_evaluate(parent, key) + else + raise "unknown #{sym}" end end + + return stack.first end # Fetches an object starting at the local scope and then moving up the hierachy @@ -254,6 +265,7 @@ module Liquid end end end # squash_instance_assigns_with_environments + end # Context end # Liquid diff --git a/lib/liquid/parser.rb b/lib/liquid/parser.rb new file mode 100644 index 0000000..8f7d39b --- /dev/null +++ b/lib/liquid/parser.rb @@ -0,0 +1,628 @@ + +# line 1 "./lib/liquid/parser.rl" +=begin + LITERALS = { + nil => nil, 'nil' => nil, 'null' => nil, '' => nil, + 'true' => true, + 'false' => false, + 'blank' => :blank?, + 'empty' => :empty? + } + + def resolve(key) + if LITERALS.key?(key) + LITERALS[key] + else + case key + when /^'(.*)'$/ # Single quoted strings + $1 + when /^"(.*)"$/ # Double quoted strings + $1 + when /^(-?\d+)$/ # Integer and floats + $1.to_i + when /^\((\S+)\.\.(\S+)\)$/ # Ranges + (resolve($1).to_i..resolve($2).to_i) + when /^(-?\d[\d\.]+)$/ # Floats + $1.to_f + else + variable(key) + end + end + end +=end + +# line 91 "./lib/liquid/parser.rl" + +# % fix syntax highlighting + + +module Liquid + module Parser + +# line 43 "./lib/liquid/parser.rb" +class << self + attr_accessor :_fsm_actions + private :_fsm_actions, :_fsm_actions= +end +self._fsm_actions = [ + 0, 1, 0, 1, 1, 1, 2, 1, + 3, 1, 4, 1, 5, 1, 6, 1, + 7, 1, 8, 1, 9 +] + +class << self + attr_accessor :_fsm_key_offsets + private :_fsm_key_offsets, :_fsm_key_offsets= +end +self._fsm_key_offsets = [ + 0, 0, 15, 16, 17, 30, 31, 33, + 35, 45, 46, 48, 50, 60, 62, 65, + 68, 81, 81, 83, 87, 89, 92, 100, + 109, 118, 127, 136, 144, 154, 163, 171, + 180, 189, 198, 207, 215, 218, 219, 227, + 236, 245, 254, 263, 271, 281, 290, 298, + 307, 316, 325, 334, 342, 344, 346, 359, + 360, 362, 363, 365, 367, 371, 373, 376, + 384, 393, 402, 411, 420, 428, 438, 447, + 455, 464, 473, 482, 491, 499, 500, 501, + 501, 504, 506, 513, 514, 515, 515, 523, + 531, 539, 547, 554, 563, 571, 578, 586, + 594, 602, 610 +] + +class << self + attr_accessor :_fsm_trans_keys + private :_fsm_trans_keys, :_fsm_trans_keys= +end +self._fsm_trans_keys = [ + 34, 39, 40, 43, 45, 91, 102, 110, + 116, 48, 57, 65, 90, 97, 122, 34, + 39, 34, 39, 43, 45, 102, 110, 116, + 48, 57, 65, 90, 97, 122, 34, 34, + 46, 34, 46, 34, 39, 43, 45, 48, + 57, 65, 90, 97, 122, 39, 39, 46, + 39, 46, 34, 39, 43, 45, 48, 57, + 65, 90, 97, 122, 48, 57, 46, 48, + 57, 46, 48, 57, 34, 39, 43, 45, + 102, 110, 116, 48, 57, 65, 90, 97, + 122, 48, 57, 41, 46, 48, 57, 48, + 57, 41, 48, 57, 41, 95, 48, 57, + 65, 90, 97, 122, 41, 95, 97, 48, + 57, 65, 90, 98, 122, 41, 95, 108, + 48, 57, 65, 90, 97, 122, 41, 95, + 115, 48, 57, 65, 90, 97, 122, 41, + 95, 101, 48, 57, 65, 90, 97, 122, + 41, 95, 48, 57, 65, 90, 97, 122, + 41, 95, 105, 117, 48, 57, 65, 90, + 97, 122, 41, 95, 108, 48, 57, 65, + 90, 97, 122, 41, 95, 48, 57, 65, + 90, 97, 122, 41, 95, 108, 48, 57, + 65, 90, 97, 122, 41, 95, 114, 48, + 57, 65, 90, 97, 122, 41, 95, 117, + 48, 57, 65, 90, 97, 122, 41, 95, + 101, 48, 57, 65, 90, 97, 122, 41, + 95, 48, 57, 65, 90, 97, 122, 46, + 48, 57, 46, 46, 95, 48, 57, 65, + 90, 97, 122, 46, 95, 97, 48, 57, + 65, 90, 98, 122, 46, 95, 108, 48, + 57, 65, 90, 97, 122, 46, 95, 115, + 48, 57, 65, 90, 97, 122, 46, 95, + 101, 48, 57, 65, 90, 97, 122, 46, + 95, 48, 57, 65, 90, 97, 122, 46, + 95, 105, 117, 48, 57, 65, 90, 97, + 122, 46, 95, 108, 48, 57, 65, 90, + 97, 122, 46, 95, 48, 57, 65, 90, + 97, 122, 46, 95, 108, 48, 57, 65, + 90, 97, 122, 46, 95, 114, 48, 57, + 65, 90, 97, 122, 46, 95, 117, 48, + 57, 65, 90, 97, 122, 46, 95, 101, + 48, 57, 65, 90, 97, 122, 46, 95, + 48, 57, 65, 90, 97, 122, 48, 57, + 48, 57, 34, 39, 43, 45, 102, 110, + 116, 48, 57, 65, 90, 97, 122, 34, + 34, 93, 39, 39, 93, 48, 57, 46, + 93, 48, 57, 48, 57, 93, 48, 57, + 93, 95, 48, 57, 65, 90, 97, 122, + 93, 95, 97, 48, 57, 65, 90, 98, + 122, 93, 95, 108, 48, 57, 65, 90, + 97, 122, 93, 95, 115, 48, 57, 65, + 90, 97, 122, 93, 95, 101, 48, 57, + 65, 90, 97, 122, 93, 95, 48, 57, + 65, 90, 97, 122, 93, 95, 105, 117, + 48, 57, 65, 90, 97, 122, 93, 95, + 108, 48, 57, 65, 90, 97, 122, 93, + 95, 48, 57, 65, 90, 97, 122, 93, + 95, 108, 48, 57, 65, 90, 97, 122, + 93, 95, 114, 48, 57, 65, 90, 97, + 122, 93, 95, 117, 48, 57, 65, 90, + 97, 122, 93, 95, 101, 48, 57, 65, + 90, 97, 122, 93, 95, 48, 57, 65, + 90, 97, 122, 34, 39, 46, 48, 57, + 48, 57, 95, 48, 57, 65, 90, 97, + 122, 34, 39, 95, 97, 48, 57, 65, + 90, 98, 122, 95, 108, 48, 57, 65, + 90, 97, 122, 95, 115, 48, 57, 65, + 90, 97, 122, 95, 101, 48, 57, 65, + 90, 97, 122, 95, 48, 57, 65, 90, + 97, 122, 95, 105, 117, 48, 57, 65, + 90, 97, 122, 95, 108, 48, 57, 65, + 90, 97, 122, 95, 48, 57, 65, 90, + 97, 122, 95, 108, 48, 57, 65, 90, + 97, 122, 95, 114, 48, 57, 65, 90, + 97, 122, 95, 117, 48, 57, 65, 90, + 97, 122, 95, 101, 48, 57, 65, 90, + 97, 122, 95, 48, 57, 65, 90, 97, + 122, 0 +] + +class << self + attr_accessor :_fsm_single_lengths + private :_fsm_single_lengths, :_fsm_single_lengths= +end +self._fsm_single_lengths = [ + 0, 9, 1, 1, 7, 1, 2, 2, + 4, 1, 2, 2, 4, 0, 1, 1, + 7, 0, 0, 2, 0, 1, 2, 3, + 3, 3, 3, 2, 4, 3, 2, 3, + 3, 3, 3, 2, 1, 1, 2, 3, + 3, 3, 3, 2, 4, 3, 2, 3, + 3, 3, 3, 2, 0, 0, 7, 1, + 2, 1, 2, 0, 2, 0, 1, 2, + 3, 3, 3, 3, 2, 4, 3, 2, + 3, 3, 3, 3, 2, 1, 1, 0, + 1, 0, 1, 1, 1, 0, 2, 2, + 2, 2, 1, 3, 2, 1, 2, 2, + 2, 2, 1 +] + +class << self + attr_accessor :_fsm_range_lengths + private :_fsm_range_lengths, :_fsm_range_lengths= +end +self._fsm_range_lengths = [ + 0, 3, 0, 0, 3, 0, 0, 0, + 3, 0, 0, 0, 3, 1, 1, 1, + 3, 0, 1, 1, 1, 1, 3, 3, + 3, 3, 3, 3, 3, 3, 3, 3, + 3, 3, 3, 3, 1, 0, 3, 3, + 3, 3, 3, 3, 3, 3, 3, 3, + 3, 3, 3, 3, 1, 1, 3, 0, + 0, 0, 0, 1, 1, 1, 1, 3, + 3, 3, 3, 3, 3, 3, 3, 3, + 3, 3, 3, 3, 3, 0, 0, 0, + 1, 1, 3, 0, 0, 0, 3, 3, + 3, 3, 3, 3, 3, 3, 3, 3, + 3, 3, 3 +] + +class << self + attr_accessor :_fsm_index_offsets + private :_fsm_index_offsets, :_fsm_index_offsets= +end +self._fsm_index_offsets = [ + 0, 0, 13, 15, 17, 28, 30, 33, + 36, 44, 46, 49, 52, 60, 62, 65, + 68, 79, 80, 82, 86, 88, 91, 97, + 104, 111, 118, 125, 131, 139, 146, 152, + 159, 166, 173, 180, 186, 189, 191, 197, + 204, 211, 218, 225, 231, 239, 246, 252, + 259, 266, 273, 280, 286, 288, 290, 301, + 303, 306, 308, 311, 313, 317, 319, 322, + 328, 335, 342, 349, 356, 362, 370, 377, + 383, 390, 397, 404, 411, 417, 419, 421, + 422, 425, 427, 432, 434, 436, 437, 443, + 449, 455, 461, 466, 473, 479, 484, 490, + 496, 502, 508 +] + +class << self + attr_accessor :_fsm_trans_targs + private :_fsm_trans_targs, :_fsm_trans_targs= +end +self._fsm_trans_targs = [ + 2, 3, 4, 52, 52, 54, 86, 91, + 95, 80, 82, 82, 0, 77, 2, 78, + 3, 5, 9, 13, 13, 39, 44, 48, + 14, 38, 38, 0, 6, 5, 6, 7, + 5, 6, 8, 5, 6, 5, 5, 5, + 5, 5, 5, 5, 10, 9, 10, 11, + 9, 10, 12, 9, 9, 10, 9, 9, + 9, 9, 9, 9, 14, 0, 15, 14, + 0, 16, 36, 0, 17, 17, 18, 18, + 23, 28, 32, 19, 22, 22, 0, 17, + 19, 0, 79, 20, 19, 0, 21, 0, + 79, 21, 0, 79, 22, 22, 22, 22, + 0, 79, 22, 24, 22, 22, 22, 0, + 79, 22, 25, 22, 22, 22, 0, 79, + 22, 26, 22, 22, 22, 0, 79, 22, + 27, 22, 22, 22, 0, 79, 22, 22, + 22, 22, 0, 79, 22, 29, 31, 22, + 22, 22, 0, 79, 22, 30, 22, 22, + 22, 0, 79, 22, 22, 22, 22, 0, + 79, 22, 29, 22, 22, 22, 0, 79, + 22, 33, 22, 22, 22, 0, 79, 22, + 34, 22, 22, 22, 0, 79, 22, 35, + 22, 22, 22, 0, 79, 22, 22, 22, + 22, 0, 37, 36, 0, 16, 0, 37, + 38, 38, 38, 38, 0, 37, 38, 40, + 38, 38, 38, 0, 37, 38, 41, 38, + 38, 38, 0, 37, 38, 42, 38, 38, + 38, 0, 37, 38, 43, 38, 38, 38, + 0, 37, 38, 38, 38, 38, 0, 37, + 38, 45, 47, 38, 38, 38, 0, 37, + 38, 46, 38, 38, 38, 0, 37, 38, + 38, 38, 38, 0, 37, 38, 45, 38, + 38, 38, 0, 37, 38, 49, 38, 38, + 38, 0, 37, 38, 50, 38, 38, 38, + 0, 37, 38, 51, 38, 38, 38, 0, + 37, 38, 38, 38, 38, 0, 80, 0, + 81, 0, 55, 57, 59, 59, 64, 69, + 73, 60, 63, 63, 0, 56, 55, 56, + 83, 55, 58, 57, 58, 84, 57, 60, + 0, 61, 85, 60, 0, 62, 0, 85, + 62, 0, 85, 63, 63, 63, 63, 0, + 85, 63, 65, 63, 63, 63, 0, 85, + 63, 66, 63, 63, 63, 0, 85, 63, + 67, 63, 63, 63, 0, 85, 63, 68, + 63, 63, 63, 0, 85, 63, 63, 63, + 63, 0, 85, 63, 70, 72, 63, 63, + 63, 0, 85, 63, 71, 63, 63, 63, + 0, 85, 63, 63, 63, 63, 0, 85, + 63, 70, 63, 63, 63, 0, 85, 63, + 74, 63, 63, 63, 0, 85, 63, 75, + 63, 63, 63, 0, 85, 63, 76, 63, + 63, 63, 0, 85, 63, 63, 63, 63, + 0, 77, 2, 78, 3, 0, 53, 80, + 0, 81, 0, 82, 82, 82, 82, 0, + 56, 55, 58, 57, 0, 82, 87, 82, + 82, 82, 0, 82, 88, 82, 82, 82, + 0, 82, 89, 82, 82, 82, 0, 82, + 90, 82, 82, 82, 0, 82, 82, 82, + 82, 0, 82, 92, 94, 82, 82, 82, + 0, 82, 93, 82, 82, 82, 0, 82, + 82, 82, 82, 0, 82, 92, 82, 82, + 82, 0, 82, 96, 82, 82, 82, 0, + 82, 97, 82, 82, 82, 0, 82, 98, + 82, 82, 82, 0, 82, 82, 82, 82, + 0, 0 +] + +class << self + attr_accessor :_fsm_trans_actions + private :_fsm_trans_actions, :_fsm_trans_actions= +end +self._fsm_trans_actions = [ + 1, 1, 0, 1, 1, 0, 1, 1, + 1, 1, 1, 1, 0, 0, 0, 0, + 0, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 0, 0, 0, 0, 17, + 0, 0, 0, 0, 1, 1, 1, 1, + 1, 1, 1, 0, 0, 0, 0, 17, + 0, 0, 0, 0, 1, 1, 1, 1, + 1, 1, 1, 0, 0, 0, 7, 0, + 0, 0, 0, 0, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 0, 0, + 0, 0, 7, 0, 0, 0, 0, 0, + 9, 0, 0, 19, 0, 0, 0, 0, + 0, 19, 0, 0, 0, 0, 0, 0, + 19, 0, 0, 0, 0, 0, 0, 19, + 0, 0, 0, 0, 0, 0, 19, 0, + 0, 0, 0, 0, 0, 15, 0, 0, + 0, 0, 0, 19, 0, 0, 0, 0, + 0, 0, 0, 19, 0, 0, 0, 0, + 0, 0, 11, 0, 0, 0, 0, 0, + 19, 0, 0, 0, 0, 0, 0, 19, + 0, 0, 0, 0, 0, 0, 19, 0, + 0, 0, 0, 0, 0, 19, 0, 0, + 0, 0, 0, 0, 13, 0, 0, 0, + 0, 0, 9, 0, 0, 0, 0, 19, + 0, 0, 0, 0, 0, 19, 0, 0, + 0, 0, 0, 0, 19, 0, 0, 0, + 0, 0, 0, 19, 0, 0, 0, 0, + 0, 0, 19, 0, 0, 0, 0, 0, + 0, 15, 0, 0, 0, 0, 0, 19, + 0, 0, 0, 0, 0, 0, 0, 19, + 0, 0, 0, 0, 0, 0, 11, 0, + 0, 0, 0, 0, 19, 0, 0, 0, + 0, 0, 0, 19, 0, 0, 0, 0, + 0, 0, 19, 0, 0, 0, 0, 0, + 0, 19, 0, 0, 0, 0, 0, 0, + 13, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 0, 0, 0, 0, + 17, 0, 0, 0, 0, 17, 0, 0, + 0, 0, 7, 0, 0, 0, 0, 9, + 0, 0, 19, 0, 0, 0, 0, 0, + 19, 0, 0, 0, 0, 0, 0, 19, + 0, 0, 0, 0, 0, 0, 19, 0, + 0, 0, 0, 0, 0, 19, 0, 0, + 0, 0, 0, 0, 15, 0, 0, 0, + 0, 0, 19, 0, 0, 0, 0, 0, + 0, 0, 19, 0, 0, 0, 0, 0, + 0, 11, 0, 0, 0, 0, 0, 19, + 0, 0, 0, 0, 0, 0, 19, 0, + 0, 0, 0, 0, 0, 19, 0, 0, + 0, 0, 0, 0, 19, 0, 0, 0, + 0, 0, 0, 13, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0 +] + +class << self + attr_accessor :_fsm_eof_actions + private :_fsm_eof_actions, :_fsm_eof_actions= +end +self._fsm_eof_actions = [ + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 17, 17, 5, + 7, 9, 19, 3, 3, 3, 19, 19, + 19, 19, 15, 19, 19, 11, 19, 19, + 19, 19, 13 +] + +class << self + attr_accessor :fsm_start +end +self.fsm_start = 1; +class << self + attr_accessor :fsm_first_final +end +self.fsm_first_final = 77; +class << self + attr_accessor :fsm_error +end +self.fsm_error = 0; + +class << self + attr_accessor :fsm_en_main +end +self.fsm_en_main = 1; + + +# line 98 "./lib/liquid/parser.rl" + + def self.emit(sym, type, data, tokens) + puts "emitting: #{type} #{sym} -> #{data.inspect}" + tokens.push [sym, data] + end + + def self.parse(data) + eof = data.length + tokens = [] + + +# line 414 "./lib/liquid/parser.rb" +begin + p ||= 0 + pe ||= data.length + cs = fsm_start +end + +# line 109 "./lib/liquid/parser.rl" + +# line 423 "./lib/liquid/parser.rb" +begin + _klen, _trans, _keys, _acts, _nacts = nil + _goto_level = 0 + _resume = 10 + _eof_trans = 15 + _again = 20 + _test_eof = 30 + _out = 40 + while true + _trigger_goto = false + if _goto_level <= 0 + if p == pe + _goto_level = _test_eof + next + end + if cs == 0 + _goto_level = _out + next + end + end + if _goto_level <= _resume + _keys = _fsm_key_offsets[cs] + _trans = _fsm_index_offsets[cs] + _klen = _fsm_single_lengths[cs] + _break_match = false + + begin + if _klen > 0 + _lower = _keys + _upper = _keys + _klen - 1 + + loop do + break if _upper < _lower + _mid = _lower + ( (_upper - _lower) >> 1 ) + + if data[p].ord < _fsm_trans_keys[_mid] + _upper = _mid - 1 + elsif data[p].ord > _fsm_trans_keys[_mid] + _lower = _mid + 1 + else + _trans += (_mid - _keys) + _break_match = true + break + end + end # loop + break if _break_match + _keys += _klen + _trans += _klen + end + _klen = _fsm_range_lengths[cs] + if _klen > 0 + _lower = _keys + _upper = _keys + (_klen << 1) - 2 + loop do + break if _upper < _lower + _mid = _lower + (((_upper-_lower) >> 1) & ~1) + if data[p].ord < _fsm_trans_keys[_mid] + _upper = _mid - 2 + elsif data[p].ord > _fsm_trans_keys[_mid+1] + _lower = _mid + 2 + else + _trans += ((_mid - _keys) >> 1) + _break_match = true + break + end + end # loop + break if _break_match + _trans += _klen + end + end while false + cs = _fsm_trans_targs[_trans] + if _fsm_trans_actions[_trans] != 0 + _acts = _fsm_trans_actions[_trans] + _nacts = _fsm_actions[_acts] + _acts += 1 + while _nacts > 0 + _nacts -= 1 + _acts += 1 + case _fsm_actions[_acts - 1] +when 0 then +# line 34 "./lib/liquid/parser.rl" + begin + + mark = p + end +when 3 then +# line 59 "./lib/liquid/parser.rl" + begin + emit(:id, :integer, Integer(data[mark..p-1]), tokens) end +when 4 then +# line 61 "./lib/liquid/parser.rl" + begin + emit(:id, :float, Float(data[mark..p-1]), tokens) end +when 5 then +# line 63 "./lib/liquid/parser.rl" + begin + emit(:id, :nil, nil, tokens) end +when 6 then +# line 64 "./lib/liquid/parser.rl" + begin + emit(:id, :bool, true, tokens) end +when 7 then +# line 65 "./lib/liquid/parser.rl" + begin + emit(:id, :bool, false, tokens) end +when 8 then +# line 67 "./lib/liquid/parser.rl" + begin + emit(:id, :string, data[mark+1..p-2], tokens) end +when 9 then +# line 74 "./lib/liquid/parser.rl" + begin + + emit(:id, :label, data[mark..p-1], tokens) + emit(:lookup, :variable, nil, tokens) + end +# line 540 "./lib/liquid/parser.rb" + end # action switch + end + end + if _trigger_goto + next + end + end + if _goto_level <= _again + if cs == 0 + _goto_level = _out + next + end + p += 1 + if p != pe + _goto_level = _resume + next + end + end + if _goto_level <= _test_eof + if p == eof + __acts = _fsm_eof_actions[cs] + __nacts = _fsm_actions[__acts] + __acts += 1 + while __nacts > 0 + __nacts -= 1 + __acts += 1 + case _fsm_actions[__acts - 1] +when 1 then +# line 38 "./lib/liquid/parser.rl" + begin + + emit(:lookup, :instruction, nil, tokens) + end +when 2 then +# line 42 "./lib/liquid/parser.rl" + begin + + emit(:range, :instruction, nil, tokens) + end +when 3 then +# line 59 "./lib/liquid/parser.rl" + begin + emit(:id, :integer, Integer(data[mark..p-1]), tokens) end +when 4 then +# line 61 "./lib/liquid/parser.rl" + begin + emit(:id, :float, Float(data[mark..p-1]), tokens) end +when 5 then +# line 63 "./lib/liquid/parser.rl" + begin + emit(:id, :nil, nil, tokens) end +when 6 then +# line 64 "./lib/liquid/parser.rl" + begin + emit(:id, :bool, true, tokens) end +when 7 then +# line 65 "./lib/liquid/parser.rl" + begin + emit(:id, :bool, false, tokens) end +when 8 then +# line 67 "./lib/liquid/parser.rl" + begin + emit(:id, :string, data[mark+1..p-2], tokens) end +when 9 then +# line 74 "./lib/liquid/parser.rl" + begin + + emit(:id, :label, data[mark..p-1], tokens) + emit(:lookup, :variable, nil, tokens) + end +# line 611 "./lib/liquid/parser.rb" + end # eof action switch + end + if _trigger_goto + next + end +end + end + if _goto_level <= _out + break + end + end + end + +# line 110 "./lib/liquid/parser.rl" + return tokens + end + end +end \ No newline at end of file diff --git a/lib/liquid/parser.rl b/lib/liquid/parser.rl new file mode 100644 index 0000000..ac045ee --- /dev/null +++ b/lib/liquid/parser.rl @@ -0,0 +1,113 @@ +=begin + LITERALS = { + nil => nil, 'nil' => nil, 'null' => nil, '' => nil, + 'true' => true, + 'false' => false, + 'blank' => :blank?, + 'empty' => :empty? + } + + def resolve(key) + if LITERALS.key?(key) + LITERALS[key] + else + case key + when /^'(.*)'$/ # Single quoted strings + $1 + when /^"(.*)"$/ # Double quoted strings + $1 + when /^(-?\d+)$/ # Integer and floats + $1.to_i + when /^\((\S+)\.\.(\S+)\)$/ # Ranges + (resolve($1).to_i..resolve($2).to_i) + when /^(-?\d[\d\.]+)$/ # Floats + $1.to_f + else + variable(key) + end + end + end +=end +%%{ + machine fsm; + + action mark { + mark = p + } + + action lookup { + emit(:lookup, :instruction, nil, tokens) + } + + action range { + emit(:range, :instruction, nil, tokens) + } + + var = [a-zA-Z][0-9A-Za-z_]+; + + # strings + string = "\"" any* "\"" | "'" any* "'"; + + # nothingness + nil = "nil" | "null" ; + + integer = ('+'|'-')? digit+; + float = ('+'|'-')? digit+ '.' digit+; + + primitive = ( + + integer >mark %{ emit(:id, :integer, Integer(data[mark..p-1]), tokens) } | + + float >mark %{ emit(:id, :float, Float(data[mark..p-1]), tokens) } | + + nil %{ emit(:id, :nil, nil, tokens) } | + "true" %{ emit(:id, :bool, true, tokens) } | + "false" %{ emit(:id, :bool, false, tokens)} | + + string >mark %{ emit(:id, :string, data[mark+1..p-2], tokens) } + + ); + + constants = ( "true" | "false" | "nil" | "null" ); + + entity = ( + ((alpha [A-Za-z0-9_]*) - (constants)) >mark %{ + emit(:id, :label, data[mark..p-1], tokens) + emit(:lookup, :variable, nil, tokens) + } + ); + + + main := ( + entity | + primitive | + + + "(" (primitive | entity) ".." (primitive | entity) <: ")" %range | + "[" (primitive | entity) "]" %lookup + + ); + +}%% +# % fix syntax highlighting + + +module Liquid + module Parser + %% write data; + + def self.emit(sym, type, data, tokens) + puts "emitting: #{type} #{sym} -> #{data.inspect}" + tokens.push [sym, data] + end + + def self.parse(data) + eof = data.length + tokens = [] + + %% write init; + %% write exec; + return tokens + end + end +end \ No newline at end of file diff --git a/performance/profile.rb b/performance/profile.rb index 0698e06..6f87eca 100644 --- a/performance/profile.rb +++ b/performance/profile.rb @@ -9,11 +9,9 @@ puts 'Running profiler...' results = profiler.run_profile puts 'Success' -puts -[RubyProf::FlatPrinter, RubyProf::GraphPrinter, RubyProf::GraphHtmlPrinter, RubyProf::CallTreePrinter].each do |klass| - filename = (ENV['TMP'] || '/tmp') + (klass.name.include?('Html') ? "/liquid.#{klass.name.downcase}.html" : "/callgrind.liquid.#{klass.name.downcase}.txt") - filename.gsub!(/:+/, '_') - File.open(filename, "w+") { |fp| klass.new(results).print(fp, :print_file => true) } - $stderr.puts "wrote #{klass.name} output to #{filename}" +filename = (ENV['TMP'] || '/tmp') + "/callgrind.liquid.txt" +File.open(filename, "w+") do |fp| + RubyProf::CallTreePrinter.new(results).print(fp, :print_file => true) end +$stderr.puts "wrote RubyProf::CallTreePrinter output to #{filename}" diff --git a/performance/theme_runner.rb b/performance/theme_runner.rb index 98406b3..3be5638 100644 --- a/performance/theme_runner.rb +++ b/performance/theme_runner.rb @@ -23,7 +23,7 @@ class ThemeRunner theme_path = File.dirname(test) + '/theme.liquid' - [File.read(test), (File.file?(theme_path) ? File.read(theme_path) : nil), test] + [Liquid::Template.parse(File.read(test)), File.file?(theme_path) ? Liquid::Template.parse(File.read(theme_path)) : nil, test] end.compact end @@ -53,11 +53,17 @@ class ThemeRunner end +<<<<<<< HEAD def run_profile RubyProf.measure_mode = RubyProf::WALL_TIME +======= + def run(profile = false) + RubyProf.measure_mode = RubyProf::WALL_TIME if profile +>>>>>>> wip # Dup assigns because will make some changes to them assigns = Database.tables.dup + assigns['page_title'] = 'Page title' @tests.each do |liquid, layout, template_name| @@ -66,16 +72,17 @@ class ThemeRunner page_template = File.basename(template_name, File.extname(template_name)) unless @started - RubyProf.start - RubyProf.pause + if profile + RubyProf.start + RubyProf.pause + end @started = true end - html = nil - - RubyProf.resume - html = compile_and_render(liquid, layout, assigns, page_template) - RubyProf.pause + assigns['template'] = page_template + RubyProf.resume if profile + html = render(liquid, layout, assigns) + RubyProf.pause if profile # return the result and the MD5 of the content, this can be used to detect regressions between liquid version @@ -85,19 +92,15 @@ class ThemeRunner # File.open("/tmp/#{File.basename(template_name)}.html", "w+") { |fp| fp <