mirror of
https://github.com/Shopify/liquid.git
synced 2026-09-12 23:40:45 -07:00
Cursor: add skip_id, expect_id, skip_fragment for zero-alloc scanning
This commit is contained in:
@@ -53,6 +53,11 @@ module Liquid
|
||||
@ss.string = source
|
||||
end
|
||||
|
||||
# Extract a slice from the source (deferred allocation)
|
||||
def slice(start, len)
|
||||
@source.byteslice(start, len)
|
||||
end
|
||||
|
||||
# ── Whitespace ──────────────────────────────────────────────────
|
||||
# Skip spaces/tabs/newlines/cr, return count of newlines skipped
|
||||
def skip_ws
|
||||
@@ -80,6 +85,39 @@ module Liquid
|
||||
end
|
||||
|
||||
# ── Identifiers ─────────────────────────────────────────────────
|
||||
# Skip an identifier without allocating a string. Returns length skipped, or 0.
|
||||
def skip_id
|
||||
start = @ss.pos
|
||||
b = @ss.peek_byte
|
||||
return 0 unless b && ((b >= 97 && b <= 122) || (b >= 65 && b <= 90) || b == USCORE)
|
||||
@ss.scan_byte
|
||||
while (b = @ss.peek_byte)
|
||||
break unless (b >= 97 && b <= 122) || (b >= 65 && b <= 90) ||
|
||||
(b >= 48 && b <= 57) || b == USCORE || b == DASH
|
||||
@ss.scan_byte
|
||||
end
|
||||
@ss.scan_byte if @ss.peek_byte == QMARK
|
||||
@ss.pos - start
|
||||
end
|
||||
|
||||
# Check if next id matches expected string, consume if so. No allocation.
|
||||
def expect_id(expected)
|
||||
start = @ss.pos
|
||||
len = skip_id
|
||||
if len == expected.bytesize
|
||||
match = true
|
||||
len.times do |i|
|
||||
if @source.getbyte(start + i) != expected.getbyte(i)
|
||||
match = false
|
||||
break
|
||||
end
|
||||
end
|
||||
return true if match
|
||||
end
|
||||
@ss.pos = start
|
||||
false
|
||||
end
|
||||
|
||||
# Scan a single identifier: [a-zA-Z_][\w-]*\??
|
||||
# Returns the string or nil if not at an identifier
|
||||
def scan_id
|
||||
@@ -188,6 +226,25 @@ module Liquid
|
||||
@source.byteslice(start, @ss.pos - start)
|
||||
end
|
||||
|
||||
# Skip a fragment without allocating. Returns length skipped, or 0.
|
||||
def skip_fragment
|
||||
b = @ss.peek_byte
|
||||
return 0 unless b
|
||||
start = @ss.pos
|
||||
if b == QUOTE_S || b == QUOTE_D
|
||||
quote = b
|
||||
@ss.scan_byte
|
||||
@ss.scan_byte while (b = @ss.peek_byte) && b != quote
|
||||
@ss.scan_byte if @ss.peek_byte == quote
|
||||
else
|
||||
while (b = @ss.peek_byte)
|
||||
break if b == SPACE || b == TAB || b == NL || b == CR || b == COMMA || b == PIPE
|
||||
@ss.scan_byte
|
||||
end
|
||||
end
|
||||
@ss.pos - start
|
||||
end
|
||||
|
||||
# Scan a "QuotedFragment" — a quoted string or non-whitespace/comma/pipe run
|
||||
def scan_fragment
|
||||
b = @ss.peek_byte
|
||||
|
||||
Reference in New Issue
Block a user