<commit_before># encoding: utf-8

require "cheetah"
require "nokogiri"
require "tempfile"

module Y2R
  class Parser
    class SyntaxError < StandardError
    end

    def initialize(options = {})
      @options = options
    end

    def parse(input)
      xml_to_ast(ycp_to_xml(input))
    end

    private

    def ycp_to_xml(ycp)
      module_paths  = @options[:module_paths]  || []
      include_paths = @options[:include_paths] || []

      ycp_file = Tempfile.new("y2r")
      begin
        begin
          ycp_file.write(ycp)
        ensure
          ycp_file.close
        end

        xml_file = Tempfile.new("y2r")
        xml_file.close
        begin
          begin
            ENV["Y2PARSECOMMENTS"] = "1" if @options[:comments]

            cmd = [
              "ycpc",
              "--no-std-modules",
              "--no-std-includes",
              "-c",
              "-x",
              "-o", xml_file.path
            ]

            module_paths.each do |module_path|
              cmd << '--module-path' << module_path
            end

            include_paths.each do |include_path|
              cmd << '--include-path' << include_path
            end

            cmd << ycp_file.path

            Cheetah.run(cmd)
          rescue Cheetah::ExecutionFailed => e
            raise SyntaxError.new(e.stderr)
          end

          xml = File.read(xml_file.path)
        ensure
          xml_file.unlink
        end
      ensure
        ycp_file.unlink
      end

      # Short-term hack to make the YaST testsuite run. This will be done in
      # ycpc in a more generic way later.
      add_testedfiles(ycp, xml)
    end

    def xml_to_ast(xml)
      ast = element_to_node(Nokogiri::XML(xml).root, nil)
      ast.filename = if @options[:reported_file]
        @options[:reported_file]
      else
        @options[:filename] || "default.ycp"
      end
      ast
    end

    def element_to_node(element, context)
      node = case element.name
        when "arg", "cond", "else", "expr", "false", "key", "lhs", "rhs",
             "stmt","then", "true", "until", "value", "ycp"
          element_to_node(element.elements[0], context)

        when "assign"
          AST::YCP::Assign.new(
            :ns    => element["ns"],
            :name  => element["name"],
            :child => element_to_node(element.elements[0], context)
          )

        when "block"
          all_statements = extract_collection(element, "statements", context)

          extracted_statements = if toplevel_block?(element) && @options[:extracted_file]
            extract_file_statements(all_statements, @options[:extracted_file])
          else
            all_statements
          end

          statements = if toplevel_block?(element) && @options[:dont_inline_include_files]
            skip_include_statements(extracted_statements)<commit_msg>Add <yconst> to the list of ignored wrapper elements<commit_after># encoding: utf-8

require "cheetah"
require "nokogiri"
require "tempfile"

module Y2R
  class Parser
    class SyntaxError < StandardError
    end

    def initialize(options = {})
      @options = options
    end

    def parse(input)
      xml_to_ast(ycp_to_xml(input))
    end

    private

    def ycp_to_xml(ycp)
      module_paths  = @options[:module_paths]  || []
      include_paths = @options[:include_paths] || []

      ycp_file = Tempfile.new("y2r")
      begin
        begin
          ycp_file.write(ycp)
        ensure
          ycp_file.close
        end

        xml_file = Tempfile.new("y2r")
        xml_file.close
        begin
          begin
            ENV["Y2PARSECOMMENTS"] = "1" if @options[:comments]

            cmd = [
              "ycpc",
              "--no-std-modules",
              "--no-std-includes",
              "-c",
              "-x",
              "-o", xml_file.path
            ]

            module_paths.each do |module_path|
              cmd << '--module-path' << module_path
            end

            include_paths.each do |include_path|
              cmd << '--include-path' << include_path
            end

            cmd << ycp_file.path

            Cheetah.run(cmd)
          rescue Cheetah::ExecutionFailed => e
            raise SyntaxError.new(e.stderr)
          end

          xml = File.read(xml_file.path)
        ensure
          xml_file.unlink
        end
      ensure
        ycp_file.unlink
      end

      # Short-term hack to make the YaST testsuite run. This will be done in
      # ycpc in a more generic way later.
      add_testedfiles(ycp, xml)
    end

    def xml_to_ast(xml)
      ast = element_to_node(Nokogiri::XML(xml).root, nil)
      ast.filename = if @options[:reported_file]
        @options[:reported_file]
      else
        @options[:filename] || "default.ycp"
      end
      ast
    end

    def element_to_node(element, context)
      node = case element.name
        when "arg", "cond", "else", "expr", "false", "key", "lhs", "rhs",
             "stmt","then", "true", "until", "value", "yconst", "ycp"
          element_to_node(element.elements[0], context)

        when "assign"
          AST::YCP::Assign.new(
            :ns    => element["ns"],
            :name  => element["name"],
            :child => element_to_node(element.elements[0], context)
          )

        when "block"
          all_statements = extract_collection(element, "statements", context)

          extracted_statements = if toplevel_block?(element) && @options[:extracted_file]
            extract_file_statements(all_statements, @options[:extracted_file])
          else
            all_statements
          end

          statements = if toplevel_block?(element) && @options[:dont_inline_include_files]
            skip_include_statements(extracted_statements)
{'fraction_non_alphanumeric': 0.10968636284872639, 'fraction_numerical': 0.002772483105181078, 'mean_word_length': 1.8211143695014662, 'pattern_counts': {'":': 0, '<': 26, '<?xml version=': 0, '>': 12, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 26}, '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': '1256490', 'n_tokens_mistral': 1768, 'n_tokens_neox': 1712, 'n_words': 366}