Compare commits

...
Author SHA1 Message Date
Michael Go 1db4a8690a micro optimization 2024-10-25 01:03:57 -03:00
Michael Go fe52c5c061 micro optimization 2024-10-25 01:00:31 -03:00
Michael Go be8d3a42b6 optimize line number counting 2024-10-25 00:27:52 -03:00
Michael Go f050ae63ad non-lazy tokenizer 2024-10-25 00:15:40 -03:00
Michael Go 00b00032f9 more micro optimization 2024-10-24 23:02:49 -03:00
Michael Go 8e84a32cc4 more micro optimization 2024-10-24 23:00:34 -03:00
Michael Go fb03e48f08 more micro optimization 2024-10-24 22:59:28 -03:00
Michael Go 52a87a7e3a more micro optimization 2024-10-24 22:56:09 -03:00
Michael Go c0bc2d5b0c more micro optimization 2024-10-24 22:43:49 -03:00
Michael Go e88ebb1ab6 more micro optimization 2024-10-24 22:38:53 -03:00
Michael Go 4d3f1a71a2 more micro optimization 2024-10-24 22:38:07 -03:00
Michael Go 7868aee751 more micro optimization 2024-10-24 22:34:01 -03:00
Michael Go 50f7c62714 more micro optimization 2024-10-24 22:32:14 -03:00
Michael Go fe796bca7a more micro optimization 2024-10-24 22:31:14 -03:00
Michael Go 84088e95d6 more micro optimization 2024-10-24 22:24:58 -03:00
Michael Go 45e3ab86da more micro optimization 2024-10-24 22:23:27 -03:00
Michael Go 7b1be1e27b more micro optimization 2024-10-24 22:19:41 -03:00
Michael Go cbbde2f0cb more micro optimization 2024-10-24 22:03:25 -03:00
Michael Go 6bbd2e0021 micro optimization 2024-10-24 21:55:53 -03:00
Michael Go dfe379cf44 lazy tokenizer 2024-10-24 21:42:10 -03:00
+119 -18
View File
@@ -1,22 +1,39 @@
# frozen_string_literal: true
require "strscan"
module Liquid
class Tokenizer
attr_reader :line_number, :for_liquid_tag
TAG_END = /%\}/
TAG_OR_VARIABLE_START = /\{[\{\%}]/
NEWLINE = /\n/
OPEN_CURLEY = 123
CLOSE_CURLEY = 125
PERCENTAGE = 37
def initialize(source, line_numbers = false, line_number: nil, for_liquid_tag: false)
@source = source
@line_number = line_number || (line_numbers ? 1 : nil)
@line_number = line_number || (line_numbers ? 1 : nil)
@for_liquid_tag = for_liquid_tag
@offset = 0
@tokens = tokenize
@tokens = []
tokenize(source)
end
private def tokenize(source)
ss = StringScanner.new(source)
while token = t_shift(ss)
@tokens.push(token)
end
end
def shift
token = @tokens[@offset]
return nil unless token
token = @tokens.shift
@offset += 1
return nil unless token
if @line_number
@line_number += @for_liquid_tag ? 1 : token.count("\n")
@@ -25,21 +42,105 @@ module Liquid
token
end
private def t_shift(ss)
return nil if ss.eos?
@for_liquid_tag ? next_liquid_token(ss) : next_token(ss)
end
private
def tokenize
return [] if @source.empty?
return @source.split("\n") if @for_liquid_tag
tokens = @source.split(TemplateParser)
# removes the rogue empty element at the beginning of the array
if tokens[0]&.empty?
@offset += 1
def next_liquid_token(ss)
# read until we find a \n
start = ss.pos
if ss.scan_until(NEWLINE).nil?
token = ss.rest
ss.terminate
return token
end
tokens
ss.string.byteslice(start, ss.pos - start - 1)
end
def next_token(ss)
if ss.pos == 0
if ss.string.start_with?("{{")
ss.pos = 2
return next_variable_token(ss)
elsif ss.string.start_with?("{%")
ss.pos = 2
return next_tag_token(ss)
else
return next_text_token(ss)
end
end
# possible states: :text, :tag, :variable
byte_a = ss.scan_byte
if byte_a == OPEN_CURLEY
byte_b = ss.scan_byte
if byte_b == PERCENTAGE
return next_tag_token(ss)
elsif byte_b == OPEN_CURLEY
return next_variable_token(ss)
end
ss.pos -= 1
end
ss.pos -= 1
next_text_token(ss)
end
def next_text_token(ss)
start = ss.pos
unless ss.skip_until(TAG_OR_VARIABLE_START)
token = ss.rest
ss.terminate
return token
end
ss.pos -= 2
ss.string.byteslice(start, ss.pos - start)
end
def next_variable_token(ss)
start = ss.pos - 2
# it is possible to see a {% before a }} so we need to check for that
byte_a = ss.scan_byte
until ss.eos?
while ss.eos? == false && byte_a != CLOSE_CURLEY && byte_a != OPEN_CURLEY
byte_a = ss.scan_byte
end
break if ss.eos?
byte_b = ss.scan_byte
if byte_b != CLOSE_CURLEY && byte_b != PERCENTAGE
byte_a = byte_b
next
elsif byte_a == CLOSE_CURLEY && byte_b == CLOSE_CURLEY
return ss.string.byteslice(start, ss.pos - start)
elsif byte_a == OPEN_CURLEY && byte_b == PERCENTAGE
return next_tag_token(ss, start)
end
end
return "{{"
end
def next_tag_token(ss, start = nil)
start ||= ss.pos - 2
ss.scan_until(TAG_END)
ss.string.byteslice(start, ss.pos - start)
end
end
end