Tobi Lutke and Chris Pak
bc60deb671
update autoresearch experiment log
2026-04-04 17:42:33 -07:00
Tobi Lutke and Chris Pak
17b691ee32
Replace @blocks.each with while loop in If render — avoids block proc allocation per render\n\nResult: {"status":"keep","combined_µs":3496,"parse_µs":2356,"render_µs":1140,"allocations":24530}
2026-04-04 17:42:33 -07:00
Tobi Lutke and Chris Pak
de95af5414
Inline to_liquid_value in If render — avoids one method dispatch per condition evaluation\n\nResult: {"status":"keep","combined_µs":3459,"parse_µs":2318,"render_µs":1141,"allocations":24647}
2026-04-04 17:42:33 -07:00
Tobi Lutke and Chris Pak
6faa62697b
Replace simple_lookup? byte scan with match? regex — 8x faster per call, cleaner code\n\nResult: {"status":"keep","combined_µs":3489,"parse_µs":2353,"render_µs":1136,"allocations":24647}
2026-04-04 17:42:33 -07:00
Tobi Lutke and Chris Pak
f39fad8934
Condition#evaluate: skip loop block for simple conditions (no child_relation) — saves 235 allocs\n\nResult: {"status":"keep","combined_µs":3445,"parse_µs":2284,"render_µs":1161,"allocations":24647}
2026-04-04 17:42:33 -07:00
Tobi Lutke and Chris Pak
1aa5854f44
Clean confirmation run: 3,314µs (-55% from main), stable\n\nResult: {"status":"keep","combined_µs":3314,"parse_µs":2203,"render_µs":1111,"allocations":24882}
2026-04-04 17:42:33 -07:00
Tobi Lutke and Chris Pak
feb7036664
update autoresearch docs with current progress
2026-04-04 17:42:33 -07:00
Tobi Lutke and Chris Pak
111aeed8f1
parse_tag_token without StringScanner: pure byte ops avoid reset(token) overhead, -12% combined\n\nResult: {"status":"keep","combined_µs":3350,"parse_µs":2212,"render_µs":1138,"allocations":24882}
2026-04-04 17:42:33 -07:00
Tobi Lutke and Chris Pak
9cbfae22b0
Clean up tokenizer: remove unused StringScanner setup and regex constants\n\nResult: {"status":"keep","combined_µs":3490,"parse_µs":2331,"render_µs":1159,"allocations":24882}
2026-04-04 17:42:33 -07:00
Tobi Lutke and Chris Pak
89076dbf3a
Confirmation run: byteindex tokenizer consistently 3,400-3,600µs\n\nResult: {"status":"keep","combined_µs":3464,"parse_µs":2335,"render_µs":1129,"allocations":24882}
2026-04-04 17:42:33 -07:00
Tobi Lutke and Chris Pak
f2c0fbfa0b
Replace StringScanner tokenizer with String#byteindex — 12% faster parse, no regex overhead for delimiter finding\n\nResult: {"status":"keep","combined_µs":3556,"parse_µs":2388,"render_µs":1168,"allocations":24882}
2026-04-04 17:42:33 -07:00
Tobi Lutke and Chris Pak
78550c0e0d
Baseline: 3,818µs combined, 24,881 allocs\n\nResult: {"status":"keep","combined_µs":3818,"parse_µs":2722,"render_µs":1096,"allocations":24881}
2026-04-04 17:42:33 -07:00
Tobi Lutke and Chris Pak
68d697d1c5
Skip context.evaluate for String lookup keys in VariableLookup — avoids respond_to? dispatch\n\nResult: {"status":"keep","combined_µs":4103,"parse_µs":2881,"render_µs":1222,"allocations":24881}
2026-04-04 17:42:33 -07:00
Tobi Lutke and Chris Pak
a206932c4a
update autoresearch.md with current progress
2026-04-04 17:42:33 -07:00
Tobi Lutke and Chris Pak
8a39c3aa33
Cache no-arg filter tuples [name, EMPTY_ARRAY] — reuse frozen tuples across templates\n\nResult: {"status":"keep","combined_µs":4147,"parse_µs":2992,"render_µs":1155,"allocations":24881}
2026-04-04 17:42:33 -07:00
Tobi Lutke and Chris Pak
89fcea371e
Replace manual blank_string? with regex match — cleaner code\n\nResult: {"status":"keep","combined_µs":4196,"parse_µs":3042,"render_µs":1154,"allocations":25535}
2026-04-04 17:42:33 -07:00
Tobi Lutke and Chris Pak
de8675f8fb
Skip to_liquid_value for String/Integer keys in VariableLookup — avoids respond_to? dispatch\n\nResult: {"status":"keep","combined_µs":4131,"parse_µs":2893,"render_µs":1238,"allocations":25535}
2026-04-04 17:42:33 -07:00
Tobi Lutke and Chris Pak
e3ba4aa958
Minor cleanup: optimize expect_id with while loop and early return\n\nResult: {"status":"keep","combined_µs":4184,"parse_µs":2921,"render_µs":1263,"allocations":25535}
2026-04-04 17:42:33 -07:00
Tobi Lutke and Chris Pak
c3e55e92d9
Replace manual scan_dotted_id with regex\n\nResult: {"status":"keep","combined_µs":4121,"parse_µs":2812,"render_µs":1309,"allocations":25535}
2026-04-04 17:42:33 -07:00
Tobi Lutke and Chris Pak
0924e59840
Replace manual scan_quoted_string with regex capture groups\n\nResult: {"status":"keep","combined_µs":4102,"parse_µs":2849,"render_µs":1253,"allocations":25535}
2026-04-04 17:42:33 -07:00
Tobi Lutke and Chris Pak
8d1f030825
Replace manual rest_blank? with regex skip + eos? check\n\nResult: {"status":"keep","combined_µs":4047,"parse_µs":2795,"render_µs":1252,"allocations":25535}
2026-04-04 17:42:33 -07:00
Tobi Lutke and Chris Pak
4896d6d497
Replace manual scan_comparison_op with regex — cleaner and avoids byteslice allocation for op strings\n\nResult: {"status":"keep","combined_µs":4007,"parse_µs":2808,"render_µs":1199,"allocations":25535}
2026-04-04 17:42:33 -07:00
Tobi Lutke and Chris Pak
edd8fabb3a
Replace manual scan_fragment/scan_quoted_string_raw/skip_fragment with regex — cleaner, same/better perf\n\nResult: {"status":"keep","combined_µs":4132,"parse_µs":2890,"render_µs":1242,"allocations":25535}
2026-04-04 17:42:33 -07:00
Tobi Lutke and Chris Pak
28ede9c539
Replace manual byte-level scan_number with regex — cleaner code, same performance\n\nResult: {"status":"keep","combined_µs":4184,"parse_µs":2931,"render_µs":1253,"allocations":25535}
2026-04-04 17:42:33 -07:00
Tobi Lutke and Chris Pak
14ac591403
Replace manual byte-level scan_id/skip_id with regex — C-level StringScanner.scan is faster than Ruby-level byte scanning\n\nResult: {"status":"keep","combined_µs":4185,"parse_µs":2943,"render_µs":1242,"allocations":25535}
2026-04-04 17:42:33 -07:00
Tobi Lutke and Chris Pak
3f9b8916b2
Fast-path Hash lookups in VariableLookup#evaluate — skip respond_to? checks for Hash objects\n\nResult: {"status":"keep","combined_µs":4110,"parse_µs":2922,"render_µs":1188,"allocations":25535}
2026-04-04 17:42:33 -07:00
Tobi Lutke and Chris Pak
41de814045
Skip to_liquid/context= for primitives in VariableLookup#evaluate\n\nResult: {"status":"keep","combined_µs":4334,"parse_µs":3062,"render_µs":1272,"allocations":25535}
2026-04-04 17:42:33 -07:00
Tobi Lutke and Chris Pak
91d9a509f9
Fast return for primitive types in find_variable — skip to_liquid and respond_to?(:context=)\n\nResult: {"status":"keep","combined_µs":4225,"parse_µs":3009,"render_µs":1216,"allocations":25535}
2026-04-04 17:42:33 -07:00
Tobi Lutke and Chris Pak
37a4c19405
Skip find_index when only one scope in find_variable — go straight to environments\n\nResult: {"status":"keep","combined_µs":4323,"parse_µs":3055,"render_µs":1268,"allocations":25535}
2026-04-04 17:42:33 -07:00
Tobi Lutke and Chris Pak
dc35b765e8
Skip respond_to?(:context=) for primitive types in find_variable — avoids method lookup overhead\n\nResult: {"status":"keep","combined_µs":4207,"parse_µs":2943,"render_µs":1264,"allocations":25535}
2026-04-04 17:42:33 -07:00
Tobi Lutke and Chris Pak
1dfdce82dc
Use EMPTY_ARRAY for empty static_environments in Context — avoids 60 array allocs per render cycle\n\nResult: {"status":"keep","combined_µs":4262,"parse_µs":3079,"render_µs":1183,"allocations":25535}
2026-04-04 17:42:33 -07:00
Tobi Lutke and Chris Pak
bf16d291c9
Lazy @changes hash in Registers — only allocate when a register is actually written\n\nResult: {"status":"keep","combined_µs":4287,"parse_µs":3059,"render_µs":1228,"allocations":25595}
2026-04-04 17:42:33 -07:00
Tobi Lutke and Chris Pak
2da3ae330a
Cache block_delimiter strings per tag name — avoids repeated string interpolation\n\nResult: {"status":"keep","combined_µs":4372,"parse_µs":3127,"render_µs":1245,"allocations":25605}
2026-04-04 17:42:33 -07:00
Tobi Lutke and Chris Pak
1800cffd3b
Lazy Context init: defer StringScanner and @interrupts array allocation until needed\n\nResult: {"status":"keep","combined_µs":4299,"parse_µs":3057,"render_µs":1242,"allocations":26015}
2026-04-04 17:42:33 -07:00
Tobi Lutke and Chris Pak
02764d28f7
Cache small integer to_s (0-999): avoids 267 Integer#to_s allocations per render cycle\n\nResult: {"status":"keep","combined_µs":4158,"parse_µs":2920,"render_µs":1238,"allocations":26128}
2026-04-04 17:42:33 -07:00
Tobi Lutke and Chris Pak
f08fe63042
Replace split+join in truncatewords with manual word scan — avoids array + string allocations\n\nResult: {"status":"keep","combined_µs":4280,"parse_µs":3009,"render_µs":1271,"allocations":26395}
2026-04-04 17:42:33 -07:00
Tobi Lutke and Chris Pak
588966fd1c
Extend fast-path filter parsing to handle comma-separated multi-arg filters (e.g. pluralize: 'item', 'items')\n\nResult: {"status":"keep","combined_µs":4266,"parse_µs":3032,"render_µs":1234,"allocations":26480}
2026-04-04 17:42:33 -07:00
Tobi Lutke and Chris Pak
0e5edcc9da
Avoid expr_markup byteslice when name is entire markup string (no whitespace, no filters)\n\nResult: {"status":"keep","combined_µs":4277,"parse_µs":3057,"render_µs":1220,"allocations":27026}
2026-04-04 17:42:33 -07:00
Tobi Lutke and Chris Pak
3f10ac702c
Fast-path single-arg filter parsing: handle quoted strings, numbers, identifiers without Lexer/Parser\n\nResult: {"status":"keep","combined_µs":4427,"parse_µs":3181,"render_µs":1246,"allocations":27235}
2026-04-04 17:42:33 -07:00
Tobi Lutke and Chris Pak
f31930555e
fix rubocop offenses: autocorrect style/layout violations
2026-04-04 17:42:32 -07:00
Tobi Lutke and Chris Pak
f0ac941ac6
update autoresearch.md with full progress log
2026-04-04 17:42:32 -07:00
Tobi Lutke and Chris Pak
19bf49c116
For tag: migrate lax_parse to Cursor with zero-alloc skip_id/expect_id
2026-04-04 17:42:32 -07:00
Tobi Lutke and Chris Pak
5204033588
Cursor: add skip_id, expect_id, skip_fragment for zero-alloc scanning
2026-04-04 17:42:32 -07:00
Tobi Lutke and Chris Pak
b0c9f576af
REVERTED: Cursor for For tag adds 148 allocs from scan_id/scan_fragment string creation\n\nResult: {"status":"discard","combined_µs":5049,"parse_us":3765,"render_us":1284,"allocations":29793,"parse_µs":3765,"render_µs":1284}
2026-04-04 17:42:32 -07:00
Tobi Lutke and Chris Pak
343ae1da56
remove dead BlockBody.parse_tag_token and If SIMPLE_CONDITION - now in Cursor
2026-04-04 17:42:32 -07:00
Tobi Lutke and Chris Pak
f42593dc50
introduce Cursor class: centralize byte-level scanning for tag/variable/condition parsing
2026-04-04 17:42:32 -07:00
Tobi Lutke and Chris Pak
80edd212a0
add parse_simple to skip simple_lookup? check when caller validates
2026-04-04 17:42:32 -07:00
Tobi Lutke and Chris Pak
65d7568403
fast-path VariableLookup init: skip scan_variable for simple identifier chains
2026-04-04 17:42:32 -07:00
Tobi Lutke and Chris Pak
c2ba6b0676
avoid allocating seen={} hash in Utils.to_s/inspect when not needed
2026-04-04 17:42:32 -07:00
Tobi Lutke and Chris Pak
92ca381fb1
update autoresearch.sh: 3-run best-of, skip liquid-spec for speed
2026-04-04 17:42:32 -07:00
Tobi Lutke and Chris Pak
1032d57532
optimize Context init: avoid unnecessary array wrapping for environments
2026-04-04 17:42:32 -07:00
Tobi Lutke and Chris Pak
e1a0e7e716
use frozen EMPTY_ARRAY/EMPTY_HASH for Context @filters/@disabled_tags
2026-04-04 17:42:32 -07:00
Tobi Lutke and Chris Pak
1f309b19a7
replace INTEGER_REGEX/FLOAT_REGEX with byte-level parse_number
2026-04-04 17:42:32 -07:00
Tobi Lutke and Chris Pak
c6617accc5
replace SIMPLE_CONDITION regex with manual byte parser in if/elsif lax_parse
2026-04-04 17:42:32 -07:00
Tobi Lutke and Chris Pak
cf062e1da2
fast-path slice_collection: skip copy for full Array without offset/limit
2026-04-04 17:42:32 -07:00
Tobi Lutke and Chris Pak
06a718cd69
add invoke_two fast path for single-arg filter invocation, avoids splat chain
2026-04-04 17:42:32 -07:00
Tobi Lutke and Chris Pak
50888426a1
fast-path find_variable: check top scope first before find_index
2026-04-04 17:42:32 -07:00
Tobi Lutke and Chris Pak
1a29584f96
add invoke_single fast path for no-arg filter invocation, avoids splat alloc
2026-04-04 17:42:32 -07:00
Tobi Lutke and Chris Pak
9d16eb3d05
fast-path simple if truthiness: use byte scanner before SIMPLE_CONDITION regex
2026-04-04 17:42:32 -07:00
Tobi Lutke and Chris Pak
f879183a23
update autoresearch.md progress log
2026-04-04 17:42:32 -07:00
Tobi Lutke and Chris Pak
34971c0314
replace WhitespaceOrNothing regex with byte-level blank_string? check
2026-04-04 17:42:32 -07:00
Tobi Lutke and Chris Pak
f24ca042a2
avoid array allocation in parse_tag_token: return tag_name, store markup/newlines as class ivars
2026-04-04 17:42:32 -07:00
Tobi Lutke and Chris Pak
4ea4350775
clean up filter parsing: Lexer fallback for args, no-arg fast scan stays
2026-04-04 17:42:32 -07:00
Tobi Lutke and Chris Pak
aedd2dded6
autoresearch.md: add strategic direction toward single-pass scanner architecture
2026-04-04 17:42:32 -07:00
Tobi Lutke and Chris Pak
e1f363c72c
add security constraint to autoresearch.md, fix strict mode gate
2026-04-04 17:42:32 -07:00
Tobi Lutke and Chris Pak
808dad6fab
split filter parsing: scan no-arg filters directly, only invoke Lexer when args present
2026-04-04 17:42:32 -07:00
Tobi Lutke and Chris Pak
c82b6e58ef
autoresearch: add autoresearch.md/sh, increase benchmark warmup to 20 iterations
2026-04-04 17:42:32 -07:00
Tobi Lutke and Chris Pak
b994f22983
extend fast-path to handle quoted string literal variables (262 more fast-pathed)
2026-04-04 17:42:32 -07:00
Tobi Lutke and Chris Pak
62877e666c
skip filter arg splat for no-arg filters, trim render loop comments
2026-04-04 17:42:32 -07:00
Tobi Lutke and Chris Pak
48a2fae5f6
hoist write score check out of render loop: skip increment_write_score when no limits active
2026-04-04 17:42:32 -07:00
Tobi Lutke and Chris Pak
27fcb3a4c9
use frozen EMPTY_ARRAY for disabled_tags in Variable
2026-04-04 17:33:53 -07:00
Tobi Lutke and Chris Pak
6e9782c5cc
return [tag_name, markup, newlines] from parse_tag_token: avoid 2 whitespace string allocs
2026-04-04 17:33:53 -07:00
Tobi Lutke and Chris Pak
da57336be9
use getbyte dispatch instead of start_with? in parse_for_document
2026-04-04 17:33:53 -07:00
Tobi Lutke and Chris Pak
28f29433e4
avoid empty array allocation in evaluate_filter_expressions for no-arg filters
2026-04-04 17:33:53 -07:00
Tobi Lutke and Chris Pak
4ff5523713
replace For tag Syntax regex with manual byte-level parser
2026-04-04 17:33:53 -07:00
Tobi Lutke and Chris Pak
f388c873de
expose expression_cache/string_scanner via attr_reader, skip regex in filter args without colon
2026-04-04 17:33:53 -07:00
Tobi Lutke and Chris Pak
543c1e1fe7
unified fast-path Variable parsing: handle both plain lookups and filter chains without full Lexer pass for name
2026-04-04 17:33:53 -07:00
Tobi Lutke and Chris Pak
885c8df159
fast-path render for filter-less variables: skip render method overhead
2026-04-04 17:33:53 -07:00
Tobi Lutke and Chris Pak
8f67d81023
skip TagAttributes scan in for tag when no colon present
2026-04-04 17:33:53 -07:00
Tobi Lutke and Chris Pak
01f33e96e8
fast-path simple if conditions: skip ExpressionsAndOperators scan for single conditions
2026-04-04 17:33:53 -07:00
Tobi Lutke and Chris Pak
9e6f93a494
replace SIMPLE_VARIABLE regex with byte-level scanner to avoid MatchData
2026-04-04 17:33:53 -07:00
Tobi Lutke and Chris Pak
dc6e9799e9
fast-path simple variable parsing: skip Lexer/Parser for plain dot-separated lookups
2026-04-04 17:33:53 -07:00
Tobi Lutke and Chris Pak
98e29aa4a7
use frozen EMPTY_ARRAY for Variable filters when no filters present
2026-04-04 17:33:53 -07:00
Tobi Lutke and Chris Pak
a404cf10d0
fast-path variable_lookups: skip mutable string alloc when no dot/bracket follows
2026-04-04 17:33:53 -07:00
Tobi Lutke and Chris Pak
e73b41f3b6
fast-path String in render_obj_to_output, avoid Utils.to_s dispatch for common case
2026-04-04 17:33:53 -07:00
Tobi Lutke and Chris Pak
9d9d094e20
short-circuit parse_number with first-byte check before regex
2026-04-04 17:33:53 -07:00
Tobi Lutke and Chris Pak
4c96b5f682
avoid unnecessary strip allocation in Expression.parse, use byteslice for string literals
2026-04-04 17:33:53 -07:00
Tobi Lutke and Chris Pak
0b19c0ce44
use equal? for frozen array comparison in Lexer, skip whitespace with \s+
2026-04-04 17:33:53 -07:00
Tobi Lutke and Chris Pak
a43d970473
use getbyte instead of string indexing in whitespace_handler and create_variable
2026-04-04 17:33:53 -07:00
Tobi Lutke and Chris Pak
3751f95da2
add auto/bench.sh: unit tests + liquid-spec + perf benchmark
2026-04-04 17:33:53 -07:00
Tobi Lutke and Chris Pak
6ffd0e2339
replace VariableParser regex scan with manual byte parser in VariableLookup
2026-04-04 17:33:53 -07:00
Tobi Lutke and Chris Pak
dc7dda2253
replace FullToken regex with manual byte parsing in parse_for_document
2026-04-04 17:33:53 -07:00
Tobi Lutke and Chris Pak
2479b26f5c
add quick benchmark script for autoresearch
2026-04-04 17:33:53 -07:00
Tobi Lutke and Claude Opus 4.5
eaa9f215bf
Add lax and YJIT liquid-spec adapters
...
- ruby_liquid_lax.rb: Tests lax parsing mode with :lax_parsing feature
- ruby_liquid_yjit.rb: Tests YJIT + strict mode + ActiveSupport
Matrix results: 4483 matched, 18 different (lax edge cases), 61 skipped
🤖 Generated with [Claude Code](https://claude.com/claude-code )
Co-Authored-By: Claude Opus 4.5 <[email protected] >
2026-01-05 15:11:29 -10:00
Tobi Lutke and Claude Opus 4.5
ccd05e869c
Make blank/empty comparisons invariant to ActiveSupport
...
- Implement liquid_blank? and liquid_empty? methods in Condition
to emulate ActiveSupport's behavior when it's not loaded
- This ensures templates like `{% if x == blank %}` work identically
whether ActiveSupport is loaded or not
- Update liquid-spec adapters for new API (ctx parameter)
- Add rake spec task for running liquid-spec matrix
🤖 Generated with [Claude Code](https://claude.com/claude-code )
Co-Authored-By: Claude Opus 4.5 <[email protected] >
2026-01-05 14:54:43 -10:00
Tobias Lütke and GitHub
a4a29f3e08
Merge pull request #2034 from Shopify/fix-liquid-spec-without-activesupport
...
Require liquid-spec to be run on commit automatically and related fixes
2026-01-01 22:32:38 -05:00
Tobi Lutke
0058e4322b
Add fail-fast: false to prevent job cancellation
2026-01-01 22:30:14 -05:00
Tobi Lutke
50e1789537
Use liquid-spec feature branch until PR is merged
2026-01-01 22:29:32 -05:00
Tobi Lutke
79a2e042ff
Use liquid-spec main branch
2026-01-01 22:24:00 -05:00
Tobi Lutke
ddee08fb95
Add activesupport feature to with_active_support adapter
...
Both adapters now pass with 0 failures:
- ruby_liquid.rb: 4194 passed (skips activesupport and shopify_error_handling specs)
- ruby_liquid_with_active_support.rb: 4203 passed (skips shopify_error_handling specs)
2026-01-01 22:21:47 -05:00