Files
liquid/lib/liquid/parse_context.rb
T

93 lines
2.8 KiB
Ruby

# frozen_string_literal: true
module Liquid
class ParseContext
attr_accessor :locale, :line_number, :trim_whitespace, :depth
attr_reader :partial, :warnings, :error_mode, :environment
def initialize(options = Const::EMPTY_HASH)
@environment = options.fetch(:environment, Environment.default)
@template_options = options ? options.dup : {}
@locale = @template_options[:locale] ||= I18n.new
@warnings = []
# constructing new StringScanner in Lexer, Tokenizer, etc is expensive
# This StringScanner will be shared by all of them
@string_scanner = StringScanner.new("")
@expression_cache = if options[:expression_cache].nil?
{}
elsif options[:expression_cache].respond_to?(:[]) && options[:expression_cache].respond_to?(:[]=)
options[:expression_cache]
elsif options[:expression_cache]
{}
end
self.depth = 0
self.partial = false
end
def [](option_key)
@options[option_key]
end
def new_block_body
Liquid::BlockBody.new
end
def new_parser(input)
@string_scanner.string = input
Parser.new(@string_scanner)
end
def new_tokenizer(source, start_line_number: nil, for_liquid_tag: false)
Tokenizer.new(
source: source,
string_scanner: @string_scanner,
line_number: start_line_number,
for_liquid_tag: for_liquid_tag,
)
end
def parse_expression(markup)
if @error_mode == :rigid
# ExpressionParser doesn't use @expression_cache because rigid mode
# must run Lexer and Parser validation on every call to ensure all
# tokens are valid and properly consumed.
#
# The expensive operations (tokenization and validation) cannot be
# cached, while the cheap operation (building Expression objects from
# validated tokens) provides minimal benefit from caching.
#
# Most importantly, caching would skip the validation step entirely,
# which defeats the core purpose of rigid mode: strict validation of
# every expression to catch syntax errors like "product title".
ExpressionParser.parse(markup, self)
else
Expression.parse(markup, @string_scanner, @expression_cache)
end
end
def partial=(value)
@partial = value
@options = value ? partial_options : @template_options
@error_mode = @options[:error_mode] || @environment.error_mode
end
def partial_options
@partial_options ||= begin
dont_pass = @template_options[:include_options_blacklist]
if dont_pass == true
{ locale: locale }
elsif dont_pass.is_a?(Array)
@template_options.reject { |k, _v| dont_pass.include?(k) }
else
@template_options
end
end
end
end
end