<commit_before>﻿namespace IronJS.Native

open System
open System.Text.RegularExpressions

open IronJS
open IronJS.Support.Aliases
open IronJS.Support.CustomOperators
open IronJS.DescriptorAttrs

///
module internal String =

  ///
  let private constructor' (ctor:FO) (this:CO) (args:Args) =
    let value = 
      match args.Length with
      | 0 -> ""
      | _ -> args.[0] |> TC.ToString

    match this with
    | null -> ctor.Env.NewString(value) |> BV.Box
    | _ -> value |> BV.Box
    
  ///
  let private fromCharCode (args:Args) =
    let buffer = Text.StringBuilder(args.Length)

    for i = 0 to args.Length-1 do
      buffer.Append(TC.ToUInt16 args.[i] |> char) |> ignore

    buffer.ToString()
    
  ///
  let setup (env:Env) =
    //
    let ctor = VariadicFunction(constructor') 
    let ctor = ctor $ Utils.createConstructor env (Some 1)

    //
    ctor.MetaData.Name <- "String"

    //
    let fromCharCode = new Func<Args, string>(fromCharCode)
    let fromCharCode = fromCharCode $ Utils.createFunction env (Some 1)
    ctor.Put("fromCharCode", fromCharCode, DontEnum)

    //
    ctor.Put("prototype", env.Prototypes.String, Immutable)

    //
    env.Globals.Put("String", ctor, DontEnum)
    env.Constructors <- {env.Constructors with String=ctor}

  ///
  module Prototype = 

    ///
    let private toString (func:FO) (this:CO) =
      this.CheckType<SO>()
      this |> ValueObject.GetValue
    
    ///
    let private valueOf (func:FO) (this:CO) = 
      toString func this
    
    /// These steps are outlined in the ECMA-262, Section 15.5.4.4
    let private charAt (_:FO) (this:CO) (pos:double) =
      let S = this |> TC.ToString
      let position = pos |> TC.ToInteger
      let size = S.Length
      if position < 0 || position >= size then "" else S.[position] |> string

    /// These steps are outlined in the ECMA-262, Section 15.5.4.5
    let private charCodeAt (_:FO) (this:CO) (pos:double) =
      let S = this |> TC.ToString
      let position = pos |> TC.ToInteger
      let size = S.Length
      if position < 0 || position >= size then nan else S.[position] |> double

    ///
    let private concat (_:FO) (this:CO) (args:Args) =
      let buffer = new Text.StringBuilder(TC.ToString(this))
      let toString (x:BoxedValue) = buffer.Append(TC.ToString(x))
      args |> Array.iter (toString >> ignore)
      buffer.ToString()

    ///
    let private indexOf (_:FO) (this:CO) (subString:string) (index:double) =
      let value = this |> TC.ToString
      let index = index |> TC.ToInt32
      let index = Math.Min(Math.Max(index, 0), value.Length);
      value.IndexOf(subString, index, StringComparison.Ordinal) |> double

    /// These steps are outlined in the ECMA-262, Section 15.5.4.8
    let private lastIndexOf (_:FO) (this:CO) (searchString:BV) (position:BV) =
      let S = this |> TC.ToString
      let searchStr = searchString |> TC.ToString
      let numPos = position |> TC.ToNumber
      let pos =
        if numPos <> numPos
          then Int32.MaxValue
          else numPos |> TC.ToInteger
      let len = S.Length
      let start = Math.Min(Math.Max(pos, 0), len)
      let searchLen = searchStr.Length
      let mutable k = start
      let mutable found = false
      while k >= 0 && not found do
        found <- true
        let mutable j = 0
        while found && j < searchLen do
          if k+searchLen > len || (S.[k+j] <> searchStr.[j]) then
            found <- false
          else
            j <- j + 1
        if not found then
          k <- k - 1
      k |> double

    ///
    let private localeCompare (_:FO) (this:CO) (that:string) =
      let this = TC.ToString(this)
      String.Compare(this, that) $ double

    let private toRegExp (env:Env) (regexp:BV) =
      if regexp.IsRegExp then
        regexp.Object.CastTo<RO>()
      else
        let S = regexp |> TC.ToString
        env.NewRegExp(S) :?> RO

    let private match' (f:FO) (this:CO) (regexp:BV) =
      let S = this |> TC.ToString<commit_msg>Fixed String.prototype.match to correctly map `undefined` to the empty string for RegExp construction.<commit_after>﻿namespace IronJS.Native

open System
open System.Text.RegularExpressions

open IronJS
open IronJS.Support.Aliases
open IronJS.Support.CustomOperators
open IronJS.DescriptorAttrs

///
module internal String =

  ///
  let private constructor' (ctor:FO) (this:CO) (args:Args) =
    let value = 
      match args.Length with
      | 0 -> ""
      | _ -> args.[0] |> TC.ToString

    match this with
    | null -> ctor.Env.NewString(value) |> BV.Box
    | _ -> value |> BV.Box
    
  ///
  let private fromCharCode (args:Args) =
    let buffer = Text.StringBuilder(args.Length)

    for i = 0 to args.Length-1 do
      buffer.Append(TC.ToUInt16 args.[i] |> char) |> ignore

    buffer.ToString()
    
  ///
  let setup (env:Env) =
    //
    let ctor = VariadicFunction(constructor') 
    let ctor = ctor $ Utils.createConstructor env (Some 1)

    //
    ctor.MetaData.Name <- "String"

    //
    let fromCharCode = new Func<Args, string>(fromCharCode)
    let fromCharCode = fromCharCode $ Utils.createFunction env (Some 1)
    ctor.Put("fromCharCode", fromCharCode, DontEnum)

    //
    ctor.Put("prototype", env.Prototypes.String, Immutable)

    //
    env.Globals.Put("String", ctor, DontEnum)
    env.Constructors <- {env.Constructors with String=ctor}

  ///
  module Prototype = 

    ///
    let private toString (func:FO) (this:CO) =
      this.CheckType<SO>()
      this |> ValueObject.GetValue
    
    ///
    let private valueOf (func:FO) (this:CO) = 
      toString func this
    
    /// These steps are outlined in the ECMA-262, Section 15.5.4.4
    let private charAt (_:FO) (this:CO) (pos:double) =
      let S = this |> TC.ToString
      let position = pos |> TC.ToInteger
      let size = S.Length
      if position < 0 || position >= size then "" else S.[position] |> string

    /// These steps are outlined in the ECMA-262, Section 15.5.4.5
    let private charCodeAt (_:FO) (this:CO) (pos:double) =
      let S = this |> TC.ToString
      let position = pos |> TC.ToInteger
      let size = S.Length
      if position < 0 || position >= size then nan else S.[position] |> double

    ///
    let private concat (_:FO) (this:CO) (args:Args) =
      let buffer = new Text.StringBuilder(TC.ToString(this))
      let toString (x:BoxedValue) = buffer.Append(TC.ToString(x))
      args |> Array.iter (toString >> ignore)
      buffer.ToString()

    ///
    let private indexOf (_:FO) (this:CO) (subString:string) (index:double) =
      let value = this |> TC.ToString
      let index = index |> TC.ToInt32
      let index = Math.Min(Math.Max(index, 0), value.Length);
      value.IndexOf(subString, index, StringComparison.Ordinal) |> double

    /// These steps are outlined in the ECMA-262, Section 15.5.4.8
    let private lastIndexOf (_:FO) (this:CO) (searchString:BV) (position:BV) =
      let S = this |> TC.ToString
      let searchStr = searchString |> TC.ToString
      let numPos = position |> TC.ToNumber
      let pos =
        if numPos <> numPos
          then Int32.MaxValue
          else numPos |> TC.ToInteger
      let len = S.Length
      let start = Math.Min(Math.Max(pos, 0), len)
      let searchLen = searchStr.Length
      let mutable k = start
      let mutable found = false
      while k >= 0 && not found do
        found <- true
        let mutable j = 0
        while found && j < searchLen do
          if k+searchLen > len || (S.[k+j] <> searchStr.[j]) then
            found <- false
          else
            j <- j + 1
        if not found then
          k <- k - 1
      k |> double

    ///
    let private localeCompare (_:FO) (this:CO) (that:string) =
      let this = TC.ToString(this)
      String.Compare(this, that) $ double

    let private toRegExp (env:Env) (regexp:BV) =
      if regexp.IsRegExp then
        regexp.Object.CastTo<RO>()
      else
        let S = if regexp.IsUndefined then "" else regexp |> TC.ToString
        env.NewRegExp(S) :?> RO

    let private match' (f:FO) (this:CO) (regexp:BV) =
      let S = this |> TC.ToString
{'fraction_non_alphanumeric': 0.1262613832143736, 'fraction_numerical': 0.010829436377061285, 'mean_word_length': 2.2902834008097166, 'pattern_counts': {'":': 0, '<': 31, '<?xml version=': 0, '>': 81, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 6, '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': '4091821', 'n_tokens_mistral': 2740, 'n_tokens_neox': 2581, 'n_words': 739}