1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106
|
# frozen_string_literal: true
require 'temple/static_analyzer'
require 'hamlit/ruby_expression'
require 'hamlit/string_splitter'
module Hamlit
class Compiler
class ScriptCompiler
def initialize(identity)
@identity = identity
end
def compile(node, &block)
unless Ripper.respond_to?(:lex) # No Ripper.lex in truffleruby
return dynamic_compile(node, &block)
end
no_children = node.children.empty?
case
when no_children && node.value[:escape_interpolation]
compile_interpolated_plain(node)
when no_children && RubyExpression.string_literal?(node.value[:text])
delegate_optimization(node)
when no_children && Temple::StaticAnalyzer.static?(node.value[:text])
static_compile(node)
else
dynamic_compile(node, &block)
end
end
private
# String-interpolated plain text must be compiled with this method
# because we have to escape only interpolated values.
def compile_interpolated_plain(node)
temple = [:multi]
StringSplitter.compile(node.value[:text]).each do |type, value|
case type
when :static
temple << [:static, value]
when :dynamic
temple << [:escape, node.value[:escape_interpolation], [:dynamic, value]]
end
end
temple << [:newline]
end
# :dynamic is optimized in other filter: StringSplitter
def delegate_optimization(node)
[:multi,
[:escape, node.value[:escape_html], [:dynamic, node.value[:text]]],
[:newline],
]
end
def static_compile(node)
str = eval(node.value[:text]).to_s
if node.value[:escape_html]
str = Hamlit::Utils.escape_html(str)
elsif node.value[:preserve]
str = ::Hamlit::HamlHelpers.find_and_preserve(str, %w(textarea pre code))
end
[:multi, [:static, str], [:newline]]
end
def dynamic_compile(node, &block)
var = @identity.generate
temple = compile_script_assign(var, node, &block)
temple << compile_script_result(var, node)
end
def compile_script_assign(var, node, &block)
if node.children.empty?
[:multi,
[:code, "#{var} = (#{node.value[:text]}"],
[:newline],
[:code, ')'],
]
else
[:multi,
[:block, "#{var} = #{node.value[:text]}",
[:multi, [:newline], yield(node)],
],
]
end
end
def compile_script_result(result, node)
if !node.value[:escape_html] && node.value[:preserve]
result = find_and_preserve(result)
else
result = "(#{result}).to_s"
end
[:escape, node.value[:escape_html], [:dynamic, result]]
end
def find_and_preserve(code)
%Q[::Hamlit::HamlHelpers.find_and_preserve(#{code}, %w(textarea pre code))]
end
def escape_html(temple)
[:escape, true, temple]
end
end
end
end
|