<commit_before>require 'evoasm/gen/nodes/parameters_type'

module Evoasm
  module Gen
    module Nodes


      class ParametersType

        def to_c(header:)
          io = StringIO.new
          if header
            CParametersTypeDeclaration.new(unit, basic: false).output io
            io.puts
            CParametersTypeDeclaration.new(unit, basic: true).output io
            io.puts
          end

          %i(set get unset).each do |type|
            CParametersAccessorFunction.new(unit, type, basic: false, stub: !header).output io
            io.puts
            CParametersAccessorFunction.new(unit, type, basic: true, stub: !header).output io
          end

          io.string
        end

        module CParametersTypeUtils
          def parameter_field_name(parameter_name)
            parameter_name.to_s.sub(/\?$/, '')
          end

          def signed_parameter?(parameter_name)
            case parameter_name
            when :disp, :rel, :imm0, :imm, :imm1, :moffs
              true
            else
              false
            end
          end

          def field_type(bitsize, signed)
            int_type_size = 64

            if [8, 16, 32].include?(bitsize)
              int_type_size = bitsize
            end

            int_type = "int#{int_type_size}_t"
            unless signed
              int_type.prepend 'u'
            end

            int_type
          end

          def parameter_bitsize(parameter_name, basic)
            case parameter_name
            when :rex_b, :rex_r, :rex_x, :rex_w,
              :vex_l, :force_rex?, :lock?, :force_sib?,
              :force_disp32?, :force_long_vex?, :reg0_high_byte?,
              :reg1_high_byte?
              1
            when :addr_size
              @unit.address_sizes.bitsize
            when :scale
              2
            when :modrm_reg
              3
            when :vex_v
              4
            when :reg_base, :reg_index, :reg0, :reg1, :reg2, :reg3, :reg4
              @unit.register_ids.bitsize
            when :imm, :imm0,:moffs, :rel
              basic ? 32 : 64
            when :imm1
              # Only used for enter
              8
            when :disp
              32
            when :legacy_prefix_order
              3
            else
              raise "missing C type for param #{parameter_name}"
            end
          end
        end

        class CParametersTypeDeclaration
          include CParametersTypeUtils


          UNIONS = [
            %w(imm imm0 moffs rel),
            %w(imm1 disp)
          ].freeze

          BASIC_UNIONS = [
            %w(imm imm0 moffs rel)
          ].freeze

          def initialize(unit, basic:)
            @unit = unit
            @basic = basic
          end

          def output(io)
            io.puts 'typedef struct {'
            io.indent do
              parameters = @unit.parameter_ids(basic: @basic).symbols
              fields = []
              parameters.each do |parameter_name|
                field_name = parameter_field_name parameter_name

                fields << [field_name, parameter_bitsize(parameter_name, @basic), signed_parameter?(parameter_name)]

                if @unit.undefinedable_parameter? parameter_name, basic: @basic
                  fields << ["#{field_name}_set", 1]
                end
              end

              fields.sort_by do |name, bitsize|
                [bitsize, name]
              end.group_by do |name, _|
                (@basic ? BASIC_UNIONS : UNIONS).index {|union| union.include? name} || name
              end.each_value do |union|
                if union.size > 1
                  io.puts 'evoasm_pack(union {'
                  indent = true
                else
                  indent = false
                end

                io.indent(relative: indent ? 1 : 0) do
                  union.each do |name, bitsize, signed|
                    io.puts "#{field_type bitsize, signed} #{name} : #{bitsize};"
                  end
                end

                if union.size > 1
                  io.puts '});'
                end
              end

              p fields.inject(0) { |acc, (n, s)| acc + s }./(64.0)
            end

            io.puts "} #{@unit.c_parameters_type_name @basic};"
            io.string<commit_msg>evoasm_pack -> evoasm_packed<commit_after>require 'evoasm/gen/nodes/parameters_type'

module Evoasm
  module Gen
    module Nodes


      class ParametersType

        def to_c(header:)
          io = StringIO.new
          if header
            CParametersTypeDeclaration.new(unit, basic: false).output io
            io.puts
            CParametersTypeDeclaration.new(unit, basic: true).output io
            io.puts
          end

          %i(set get unset).each do |type|
            CParametersAccessorFunction.new(unit, type, basic: false, stub: !header).output io
            io.puts
            CParametersAccessorFunction.new(unit, type, basic: true, stub: !header).output io
          end

          io.string
        end

        module CParametersTypeUtils
          def parameter_field_name(parameter_name)
            parameter_name.to_s.sub(/\?$/, '')
          end

          def signed_parameter?(parameter_name)
            case parameter_name
            when :disp, :rel, :imm0, :imm, :imm1, :moffs
              true
            else
              false
            end
          end

          def field_type(bitsize, signed)
            int_type_size = 64

            if [8, 16, 32].include?(bitsize)
              int_type_size = bitsize
            end

            int_type = "int#{int_type_size}_t"
            unless signed
              int_type.prepend 'u'
            end

            int_type
          end

          def parameter_bitsize(parameter_name, basic)
            case parameter_name
            when :rex_b, :rex_r, :rex_x, :rex_w,
              :vex_l, :force_rex?, :lock?, :force_sib?,
              :force_disp32?, :force_long_vex?, :reg0_high_byte?,
              :reg1_high_byte?
              1
            when :addr_size
              @unit.address_sizes.bitsize
            when :scale
              2
            when :modrm_reg
              3
            when :vex_v
              4
            when :reg_base, :reg_index, :reg0, :reg1, :reg2, :reg3, :reg4
              @unit.register_ids.bitsize
            when :imm, :imm0,:moffs, :rel
              basic ? 32 : 64
            when :imm1
              # Only used for enter
              8
            when :disp
              32
            when :legacy_prefix_order
              3
            else
              raise "missing C type for param #{parameter_name}"
            end
          end
        end

        class CParametersTypeDeclaration
          include CParametersTypeUtils


          UNIONS = [
            %w(imm imm0 moffs rel),
            %w(imm1 disp)
          ].freeze

          BASIC_UNIONS = [
            %w(imm imm0 moffs rel)
          ].freeze

          def initialize(unit, basic:)
            @unit = unit
            @basic = basic
          end

          def output(io)
            io.puts 'typedef struct {'
            io.indent do
              parameters = @unit.parameter_ids(basic: @basic).symbols
              fields = []
              parameters.each do |parameter_name|
                field_name = parameter_field_name parameter_name

                fields << [field_name, parameter_bitsize(parameter_name, @basic), signed_parameter?(parameter_name)]

                if @unit.undefinedable_parameter? parameter_name, basic: @basic
                  fields << ["#{field_name}_set", 1]
                end
              end

              fields.sort_by do |name, bitsize|
                [bitsize, name]
              end.group_by do |name, _|
                (@basic ? BASIC_UNIONS : UNIONS).index {|union| union.include? name} || name
              end.each_value do |union|
                if union.size > 1
                  io.puts 'evoasm_packed(union {'
                  indent = true
                else
                  indent = false
                end

                io.indent(relative: indent ? 1 : 0) do
                  union.each do |name, bitsize, signed|
                    io.puts "#{field_type bitsize, signed} #{name} : #{bitsize};"
                  end
                end

                if union.size > 1
                  io.puts '});'
                end
              end

              p fields.inject(0) { |acc, (n, s)| acc + s }./(64.0)
            end

            io.puts "} #{@unit.c_parameters_type_name @basic};"
            io.string
{'fraction_non_alphanumeric': 0.08241948516680134, 'fraction_numerical': 0.010158143830081958, 'mean_word_length': 1.244559585492228, 'pattern_counts': {'":': 0, '<': 11, '<?xml version=': 0, '>': 8, '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': '4431060', 'n_tokens_mistral': 2459, 'n_tokens_neox': 2305, 'n_words': 578}