<commit_before>require_relative 'config'

# Class that wraps a Ruby VALUE.
#
class RubyVal
  # Constants
  #
  MASK_32BIT = 2**32 - 1
  MASK_64BIT = 2**64 - 1
  Qfalse = 0
  Qtrue = 20
  Qnil = 8
  Qundef = 52
  IMMEDIATE_MASK = 7
  FIXNUM_FLAG = 1
  FLONUM_MASK = 3
  FLONUM_FLAG = 2
  SYMBOL_FLAG = 12
  SPECIAL_SHIFT = 8
  T_MASK = 0x1F
  FL_USHIFT = 12

  # Based on FL_USERx in ruby.h
  #
  def self.fl_user_mask(n)
    1 << (FL_USHIFT + n)
  end

  def initialize(val)
    @val = val
  end

  def immediate?
    @val & IMMEDIATE_MASK != 0
  end

  def fixnum?
    # Is the low bit set?
    #
    @val & 1 != 0
  end

  def flonum?
    @val & FLONUM_MASK == FLONUM_FLAG
  end

  def static_sym?
    symbol_mask = ~(MASK_64BIT << SPECIAL_SHIFT) & MASK_64BIT
    @val & symbol_mask == SYMBOL_FLAG
  end

  def test_true?
    @val & ~Qnil != 0
  end

  def builtin_type
    rbasic = DbgScript.create_typed_object("#{RUBYMOD}!RBasic", @val)
    type = rbasic.flags.value & T_MASK
    return DbgScript.resolve_enum('ruby_value_type', type), rbasic
  end

  # See 'rb_type' core function.
  #
  def type
    if immediate?
      return Fixnum if fixnum?
      return Float if flonum?
      return TrueClass if @val == Qtrue
      return Symbol if static_sym?
      return "undef" if @val == Qundef
    elsif !test_true?
      return NilClass if @val == Qnil
      return FalseClass if @val == Qfalse
    end
    builtin_type
  end

  def value
    t, rbasic = type
    # Can't use 'case' statement because that uses '===' which doesn't help for
    # comparing classes.
    #
    if t == Fixnum
      @val >> 1
    elsif t == 'RUBY_T_ARRAY'
      RArray.new(rbasic)
    elsif t == 'RUBY_T_STRING'
      RString.new(rbasic)
    else
      "not implemented"
    end
  end

  # Transform to a native Ruby value.
  #
  def to_native
    val = value
    if val.class == RArray
      val.to_a
    elsif val.class == RString
      val.to_s
    else
      val
    end
  end
end

class RString
  def initialize(rbasic)
    @rbasic = rbasic
    @str = DbgScript.create_typed_object(
        "#{RUBYMOD}!RString", @rbasic.address)
  end<commit_msg>Support a few more simple types in RubyVal#value.<commit_after>require_relative 'config'

# Class that wraps a Ruby VALUE.
#
class RubyVal
  # Constants
  #
  MASK_32BIT = 2**32 - 1
  MASK_64BIT = 2**64 - 1
  Qfalse = 0
  Qtrue = 20
  Qnil = 8
  Qundef = 52
  IMMEDIATE_MASK = 7
  FIXNUM_FLAG = 1
  FLONUM_MASK = 3
  FLONUM_FLAG = 2
  SYMBOL_FLAG = 12
  SPECIAL_SHIFT = 8
  T_MASK = 0x1F
  FL_USHIFT = 12

  # Based on FL_USERx in ruby.h
  #
  def self.fl_user_mask(n)
    1 << (FL_USHIFT + n)
  end

  def initialize(val)
    @val = val
  end

  def immediate?
    @val & IMMEDIATE_MASK != 0
  end

  def fixnum?
    # Is the low bit set?
    #
    @val & 1 != 0
  end

  def flonum?
    @val & FLONUM_MASK == FLONUM_FLAG
  end

  def static_sym?
    symbol_mask = ~(MASK_64BIT << SPECIAL_SHIFT) & MASK_64BIT
    @val & symbol_mask == SYMBOL_FLAG
  end

  def test_true?
    @val & ~Qnil != 0
  end

  def builtin_type
    rbasic = DbgScript.create_typed_object("#{RUBYMOD}!RBasic", @val)
    type = rbasic.flags.value & T_MASK
    return DbgScript.resolve_enum('ruby_value_type', type), rbasic
  end

  # See 'rb_type' core function.
  #
  def type
    if immediate?
      return Fixnum if fixnum?
      return Float if flonum?
      return TrueClass if @val == Qtrue
      return Symbol if static_sym?
      return "undef" if @val == Qundef
    elsif !test_true?
      return NilClass if @val == Qnil
      return FalseClass if @val == Qfalse
    end
    builtin_type
  end

  def value
    t, rbasic = type
    # Can't use 'case' statement because that uses '===' which doesn't help for
    # comparing classes.
    #
    if t == Fixnum
      @val >> 1
    elsif t == NilClass
      nil
    elsif t == FalseClass
      false
    elsif t == TrueClass
      true
    elsif t == 'RUBY_T_ARRAY'
      RArray.new(rbasic)
    elsif t == 'RUBY_T_STRING'
      RString.new(rbasic)
    else
      "not implemented"
    end
  end

  # Transform to a native Ruby value.
  #
  def to_native
    val = value
    if val.class == RArray
      val.to_a
    elsif val.class == RString
      val.to_s
    else
      val
    end
  end
end

class RString
  def initialize(rbasic)
    @rbasic = rbasic
    @str = DbgScript.create_typed_object(
        "#{RUBYMOD}!RString", @rbasic.address)
  end
{'fraction_non_alphanumeric': 0.09016764839148166, 'fraction_numerical': 0.017671046669687357, 'mean_word_length': 2.3245481927710845, 'pattern_counts': {'":': 0, '<': 11, '<?xml version=': 0, '>': 7, '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': '3539642', 'n_tokens_mistral': 1745, 'n_tokens_neox': 1637, 'n_words': 466}