mirror of
https://github.com/Shopify/liquid.git
synced 2026-09-29 07:05:12 -07:00
non-lazy tokenizer
This commit is contained in:
+59
-39
@@ -15,15 +15,35 @@ module Liquid
|
|||||||
PERCENTAGE = 37
|
PERCENTAGE = 37
|
||||||
|
|
||||||
def initialize(source, line_numbers = false, line_number: nil, for_liquid_tag: false)
|
def initialize(source, line_numbers = false, line_number: nil, for_liquid_tag: false)
|
||||||
@line_number = line_number || (line_numbers ? 1 : nil)
|
@line_number = line_number || (line_numbers ? 1 : nil)
|
||||||
|
original_line_number = @line_number
|
||||||
|
|
||||||
@for_liquid_tag = for_liquid_tag
|
@for_liquid_tag = for_liquid_tag
|
||||||
@ss = StringScanner.new(source)
|
@tokens = []
|
||||||
|
@line_numbers = []
|
||||||
|
tokenize(source)
|
||||||
|
|
||||||
|
@line_number = original_line_number
|
||||||
|
end
|
||||||
|
|
||||||
|
private def tokenize(source)
|
||||||
|
ss = StringScanner.new(source)
|
||||||
|
|
||||||
|
while token = t_shift(ss)
|
||||||
|
@tokens.push(token)
|
||||||
|
@line_numbers.push(@line_number) if @line_number
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
def shift
|
def shift
|
||||||
return nil if @ss.eos?
|
@line_number = @line_numbers.shift if @line_number
|
||||||
|
@tokens.shift
|
||||||
|
end
|
||||||
|
|
||||||
token = @for_liquid_tag ? next_liquid_token : next_token
|
private def t_shift(ss)
|
||||||
|
return nil if ss.eos?
|
||||||
|
|
||||||
|
token = @for_liquid_tag ? next_liquid_token(ss) : next_token(ss)
|
||||||
|
|
||||||
return nil unless token
|
return nil unless token
|
||||||
|
|
||||||
@@ -36,65 +56,65 @@ module Liquid
|
|||||||
|
|
||||||
private
|
private
|
||||||
|
|
||||||
def next_liquid_token
|
def next_liquid_token(ss)
|
||||||
# read until we find a \n
|
# read until we find a \n
|
||||||
start = @ss.pos
|
start = ss.pos
|
||||||
if @ss.scan_until(NEWLINE).nil?
|
if ss.scan_until(NEWLINE).nil?
|
||||||
token = @ss.rest
|
token = ss.rest
|
||||||
@ss.terminate
|
ss.terminate
|
||||||
return token
|
return token
|
||||||
end
|
end
|
||||||
|
|
||||||
@ss.string.byteslice(start, @ss.pos - start - 1)
|
ss.string.byteslice(start, ss.pos - start - 1)
|
||||||
end
|
end
|
||||||
|
|
||||||
def next_token
|
def next_token(ss)
|
||||||
# possible states: :text, :tag, :variable
|
# possible states: :text, :tag, :variable
|
||||||
byte_a = @ss.scan_byte
|
byte_a = ss.scan_byte
|
||||||
|
|
||||||
if byte_a == OPEN_CURLEY
|
if byte_a == OPEN_CURLEY
|
||||||
byte_b = @ss.scan_byte
|
byte_b = ss.scan_byte
|
||||||
|
|
||||||
if byte_b == PERCENTAGE
|
if byte_b == PERCENTAGE
|
||||||
return next_tag_token
|
return next_tag_token(ss)
|
||||||
elsif byte_b == OPEN_CURLEY
|
elsif byte_b == OPEN_CURLEY
|
||||||
return next_variable_token
|
return next_variable_token(ss)
|
||||||
end
|
end
|
||||||
|
|
||||||
@ss.pos -= 1
|
ss.pos -= 1
|
||||||
end
|
end
|
||||||
|
|
||||||
@ss.pos -= 1
|
ss.pos -= 1
|
||||||
next_text_token
|
next_text_token(ss)
|
||||||
end
|
end
|
||||||
|
|
||||||
def next_text_token
|
def next_text_token(ss)
|
||||||
start = @ss.pos
|
start = ss.pos
|
||||||
|
|
||||||
unless @ss.skip_until(TAG_OR_VARIABLE_START)
|
unless ss.skip_until(TAG_OR_VARIABLE_START)
|
||||||
token = @ss.rest
|
token = ss.rest
|
||||||
@ss.terminate
|
ss.terminate
|
||||||
return token
|
return token
|
||||||
end
|
end
|
||||||
|
|
||||||
@ss.pos -= 2
|
ss.pos -= 2
|
||||||
@ss.string.byteslice(start, @ss.pos - start)
|
ss.string.byteslice(start, ss.pos - start)
|
||||||
end
|
end
|
||||||
|
|
||||||
def next_variable_token
|
def next_variable_token(ss)
|
||||||
start = @ss.pos - 2
|
start = ss.pos - 2
|
||||||
|
|
||||||
# it is possible to see a {% before a }} so we need to check for that
|
# it is possible to see a {% before a }} so we need to check for that
|
||||||
byte_a = @ss.scan_byte
|
byte_a = ss.scan_byte
|
||||||
|
|
||||||
until @ss.eos?
|
until ss.eos?
|
||||||
while @ss.eos? == false && byte_a != CLOSE_CURLEY && byte_a != OPEN_CURLEY
|
while ss.eos? == false && byte_a != CLOSE_CURLEY && byte_a != OPEN_CURLEY
|
||||||
byte_a = @ss.scan_byte
|
byte_a = ss.scan_byte
|
||||||
end
|
end
|
||||||
|
|
||||||
break if @ss.eos?
|
break if ss.eos?
|
||||||
|
|
||||||
byte_b = @ss.scan_byte
|
byte_b = ss.scan_byte
|
||||||
|
|
||||||
if byte_b != CLOSE_CURLEY && byte_b != PERCENTAGE
|
if byte_b != CLOSE_CURLEY && byte_b != PERCENTAGE
|
||||||
byte_a = byte_b
|
byte_a = byte_b
|
||||||
@@ -102,21 +122,21 @@ module Liquid
|
|||||||
end
|
end
|
||||||
|
|
||||||
if byte_a == CLOSE_CURLEY && byte_b == CLOSE_CURLEY
|
if byte_a == CLOSE_CURLEY && byte_b == CLOSE_CURLEY
|
||||||
return @ss.string.byteslice(start, @ss.pos - start)
|
return ss.string.byteslice(start, ss.pos - start)
|
||||||
elsif byte_a == OPEN_CURLEY && byte_b == PERCENTAGE
|
elsif byte_a == OPEN_CURLEY && byte_b == PERCENTAGE
|
||||||
return next_tag_token(start)
|
return next_tag_token(ss, start)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
return "{{"
|
return "{{"
|
||||||
end
|
end
|
||||||
|
|
||||||
def next_tag_token(start = nil)
|
def next_tag_token(ss, start = nil)
|
||||||
start ||= @ss.pos - 2
|
start ||= ss.pos - 2
|
||||||
|
|
||||||
@ss.scan_until(TAG_END)
|
ss.scan_until(TAG_END)
|
||||||
|
|
||||||
@ss.string.byteslice(start, @ss.pos - start)
|
ss.string.byteslice(start, ss.pos - start)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|||||||
Reference in New Issue
Block a user