<commit_before>require 'parser/current'
require 'temple'
require 'faml/ast'
require 'faml/error'
require 'faml/filter_compilers'
require 'faml/helpers'
require 'faml/rails_helpers'
require 'faml/static_hash_parser'
require 'faml/text_compiler'

module Faml
  class Compiler < Temple::Parser
    class UnparsableRubyCode < Error
    end

    DEFAULT_AUTO_CLOSE_TAGS = %w[
      area base basefont br col command embed frame hr img input isindex keygen
      link menuitem meta param source track wbr
    ]
    DEFAULT_PRESERVE_TAGS = %w[pre textarea code]

    define_options(
      autoclose: DEFAULT_AUTO_CLOSE_TAGS,
      format: :html,
      preserve: DEFAULT_PRESERVE_TAGS,
      use_html_safe: false,
      filename: nil,
    )

    def initialize(*)
      super
      @text_compiler = TextCompiler.new
      @filename = options[:filename]
    end

    def call(ast)
      compile(ast)
    end

    def self.find_and_preserve(input)
      # Taken from the original haml code
      re = /<(#{options[:preserve].map(&Regexp.method(:escape)).join('|')})([^>]*)>(.*?)(<\/\1>)/im
      input.to_s.gsub(re) do |s|
        s =~ re # Can't rely on $1, etc. existing since Rails' SafeBuffer#gsub is incompatible
        "<#{$1}#{$2}>#{Helpers.preserve($3)}</#{$1}>"
      end
    end

    private

    def compile(ast)
      case ast
      when Ast::Root
        compile_root(ast)
      when Ast::Doctype
        compile_doctype(ast)
      when Ast::HtmlComment
        compile_html_comment(ast)
      when Ast::HamlComment
        compile_haml_comment(ast)
      when Ast::Empty
        [:multi]
      when Ast::Element
        compile_element(ast)
      when Ast::Script
        compile_script(ast)
      when Ast::SilentScript
        compile_silent_script(ast)
      when Ast::Text
        compile_text(ast)
      when Ast::Filter
        compile_filter(ast)
      else
        raise "InternalError: Unknown AST node #{ast.class}: #{ast.inspect}"
      end
    rescue Error => e
      if @filename && e.lineno
        e.backtrace.unshift "#{@filename}:#{e.lineno}"
      end
      raise e
    end

    def compile_root(ast)
      [:multi, [:code, "extend ::#{helper_module.name}"]].tap do |temple|
        compile_children(ast, temple)
      end
    end

    def helper_module
      if options[:use_html_safe]
        RailsHelpers
      else
        Helpers
      end
    end

    def compile_children(ast, temple)
      ast.children.each do |c|
        temple << compile(c)
        if need_newline?(c)
          temple << [:mknl]
        end
        unless suppress_code_newline?(c)
          temple << [:newline]
        end
      end
    end
<commit_msg>Unshift backtrace once<commit_after>require 'parser/current'
require 'temple'
require 'faml/ast'
require 'faml/error'
require 'faml/filter_compilers'
require 'faml/helpers'
require 'faml/rails_helpers'
require 'faml/static_hash_parser'
require 'faml/text_compiler'

module Faml
  class Compiler < Temple::Parser
    class UnparsableRubyCode < Error
    end

    DEFAULT_AUTO_CLOSE_TAGS = %w[
      area base basefont br col command embed frame hr img input isindex keygen
      link menuitem meta param source track wbr
    ]
    DEFAULT_PRESERVE_TAGS = %w[pre textarea code]

    define_options(
      autoclose: DEFAULT_AUTO_CLOSE_TAGS,
      format: :html,
      preserve: DEFAULT_PRESERVE_TAGS,
      use_html_safe: false,
      filename: nil,
    )

    def initialize(*)
      super
      @text_compiler = TextCompiler.new
      @filename = options[:filename]
    end

    def call(ast)
      compile(ast)
    rescue Error => e
      if @filename && e.lineno
        e.backtrace.unshift "#{@filename}:#{e.lineno}"
      end
      raise e
    end

    def self.find_and_preserve(input)
      # Taken from the original haml code
      re = /<(#{options[:preserve].map(&Regexp.method(:escape)).join('|')})([^>]*)>(.*?)(<\/\1>)/im
      input.to_s.gsub(re) do |s|
        s =~ re # Can't rely on $1, etc. existing since Rails' SafeBuffer#gsub is incompatible
        "<#{$1}#{$2}>#{Helpers.preserve($3)}</#{$1}>"
      end
    end

    private

    def compile(ast)
      case ast
      when Ast::Root
        compile_root(ast)
      when Ast::Doctype
        compile_doctype(ast)
      when Ast::HtmlComment
        compile_html_comment(ast)
      when Ast::HamlComment
        compile_haml_comment(ast)
      when Ast::Empty
        [:multi]
      when Ast::Element
        compile_element(ast)
      when Ast::Script
        compile_script(ast)
      when Ast::SilentScript
        compile_silent_script(ast)
      when Ast::Text
        compile_text(ast)
      when Ast::Filter
        compile_filter(ast)
      else
        raise "InternalError: Unknown AST node #{ast.class}: #{ast.inspect}"
      end
    end

    def compile_root(ast)
      [:multi, [:code, "extend ::#{helper_module.name}"]].tap do |temple|
        compile_children(ast, temple)
      end
    end

    def helper_module
      if options[:use_html_safe]
        RailsHelpers
      else
        Helpers
      end
    end

    def compile_children(ast, temple)
      ast.children.each do |c|
        temple << compile(c)
        if need_newline?(c)
          temple << [:mknl]
        end
        unless suppress_code_newline?(c)
          temple << [:newline]
        end
      end
    end

{'fraction_non_alphanumeric': 0.10820965620890476, 'fraction_numerical': 0.0022543678376855157, 'mean_word_length': 2.3975749840459475, 'pattern_counts': {'":': 0, '<': 27, '<?xml version=': 0, '>': 15, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '5284206', 'n_tokens_mistral': 1735, 'n_tokens_neox': 1702, 'n_words': 406}