22// License, v. 2.0. If a copy of the MPL was not distributed with this
33// file, You can obtain one at https://mozilla.org/MPL/2.0/.
44
5- use std:: { collections:: VecDeque , iter:: repeat} ;
5+ use std:: { cmp :: max , collections:: VecDeque , iter:: repeat} ;
66
77use small_string:: SmallString ;
88
@@ -682,7 +682,7 @@ impl StringPrototype {
682682 let search_length = search_string. len ( agent) ;
683683
684684 // 8. Let position be StringIndexOf(s, searchString, 0).
685- let position = if let Some ( position) = search_string . as_str ( agent) . find ( s . as_str ( agent) )
685+ let position = if let Some ( position) = s . as_str ( agent) . find ( search_string . as_str ( agent) )
686686 {
687687 position
688688 } else {
@@ -708,7 +708,7 @@ impl StringPrototype {
708708 // 11. Let following be the substring of s from position + searchLength.
709709 // 12. If functionalReplace is true,
710710 let preceding = & s. as_str ( agent) [ 0 ..position] . to_owned ( ) ;
711- let following = & s. as_str ( agent) [ position..search_length ] . to_owned ( ) ;
711+ let following = & s. as_str ( agent) [ position + search_length.. ] . to_owned ( ) ;
712712
713713 // 14. Return the string-concatenation of preceding, replacement, and following.
714714 let concatenated_result = format ! ( "{}{}{}" , preceding, result. as_str( agent) , following) ;
@@ -718,16 +718,131 @@ impl StringPrototype {
718718 // 6. If functionalReplace is false, Set replaceValue to ? ToString(replaceValue).
719719 let replace_string = to_string ( agent, replace_value) ?;
720720 // Everything are strings: `"foo".replace("o", "a")` => use rust's replace
721+ let result =
722+ s. as_str ( agent)
723+ . replacen ( search_string. as_str ( agent) , replace_string. as_str ( agent) , 1 ) ;
724+ Ok ( String :: from_string ( agent, result) . into_value ( ) )
725+ }
726+
727+ /// ### [22.1.3.20 String.prototype.replaceAll ( searchValue, replaceValue )](https://tc39.es/ecma262/multipage/text-processing.html#sec-string.prototype.replaceall)
728+ fn replace_all ( agent : & mut Agent , this_value : Value , args : ArgumentsList ) -> JsResult < Value > {
729+ // 1. Let O be ? RequireObjectCoercible(this value).
730+ let o = require_object_coercible ( agent, this_value) ?;
731+
732+ let search_value = args. get ( 0 ) ;
733+ let replace_value = args. get ( 1 ) ;
734+
735+ // 2. If searchValue is neither undefined nor null, then
736+ if !search_value. is_null ( ) && !search_value. is_undefined ( ) {
737+ // a. Let isRegExp be ? IsRegExp(searchValue).
738+ let is_reg_exp = false ;
739+
740+ // b. If isRegExp is true, then
741+ if is_reg_exp {
742+ // i. Let flags be ? Get(searchValue, "flags").
743+ // ii. Perform ? RequireObjectCoercible(flags).
744+ // iii. If ? ToString(flags) does not contain "g", throw a TypeError exception.
745+ todo ! ( ) ;
746+ }
747+
748+ // c. Let replacer be ? GetMethod(searchValue, %Symbol.replace%).
749+ let symbol = WellKnownSymbolIndexes :: Replace . into ( ) ;
750+ let replacer = get_method ( agent, search_value, symbol) ?;
751+
752+ // d. If replacer is not undefined, Return ? Call(replacer, searchValue, « O, replaceValue »).
753+ if let Some ( replacer) = replacer {
754+ return call_function (
755+ agent,
756+ replacer,
757+ search_value,
758+ Some ( ArgumentsList ( & [ o, replace_value] ) ) ,
759+ ) ;
760+ }
761+ }
762+
763+ // 3. Let s be ? ToString(O).
764+ let s = to_string ( agent, o) ?;
765+
766+ // 4. Let searchString be ? ToString(searchValue).
767+ let search_string = to_string ( agent, search_value) ?;
768+
769+ // 5. Let functionalReplace be IsCallable(replaceValue).
770+ if let Some ( functional_replace) = is_callable ( replace_value) {
771+ // 7. Let searchLength be the length of searchString.
772+ let search_length = search_string. len ( agent) ;
773+
774+ // 8. Let advanceBy be max(1, searchLength).
775+ let advance_by = max ( 1 , search_length) ;
776+
777+ // 9. Let matchPositions be a new empty List.
778+ let mut match_positions: Vec < usize > = vec ! [ ] ;
779+
780+ // 10. Let position be StringIndexOf(s, searchString, 0).
781+ let search_str = search_string. as_str ( agent) ;
782+ let subject = s. as_str ( agent) . to_owned ( ) ;
783+ let mut position = 0 ;
784+
785+ // 11. Repeat, while position is not not-found,
786+ while let Some ( pos) = subject[ position..] . find ( search_str) {
787+ match_positions. push ( position + pos) ;
788+ position += advance_by + pos;
789+ }
790+
791+ // If none has found, return s.
792+ if match_positions. is_empty ( ) {
793+ return Ok ( s. into_value ( ) ) ;
794+ }
795+
796+ // 12. Let endOfLastMatch be 0.
797+ let mut end_of_last_match = 0 ;
798+
799+ // 13. Let result be the empty String.
800+ let mut result = std:: string:: String :: with_capacity ( subject. len ( ) ) ;
801+
802+ // 14. For each element p of matchPositions, do
803+ for p in match_positions {
804+ // b. let replacement be ? ToString(? Call(replaceValue, undefined, « searchString, 𝔽(p), string »)).
805+ let replacement = call_function (
806+ agent,
807+ functional_replace,
808+ Value :: Undefined ,
809+ Some ( ArgumentsList ( & [
810+ search_string. into_value ( ) ,
811+ Number :: from ( position as u32 ) . into_value ( ) ,
812+ s. into_value ( ) ,
813+ ] ) ) ,
814+ ) ?;
815+
816+ // a. Let preserved be the substring of string from endOfLastMatch to p.
817+ let preserved = & subject[ end_of_last_match..p] ;
818+ // d. Set result to the string-concatenation of result, preserved, and replacement.
819+ let replacement_str = replacement. to_string ( agent) ?;
820+ let replacement_str = replacement_str. as_str ( agent) ;
821+ result. reserve ( preserved. len ( ) + replacement_str. len ( ) ) ;
822+ result. push_str ( preserved) ;
823+ result. push_str ( replacement_str) ;
824+ end_of_last_match = p + search_length;
825+ }
826+
827+ // 15. If endOfLastMatch < the length of string, set result to the string-concatenation of result and the substring of string from endOfLastMatch.
828+ if end_of_last_match < subject. len ( ) {
829+ let preserved = & subject[ end_of_last_match..] ;
830+ result. push_str ( preserved) ;
831+ }
832+
833+ // 16. Return result.
834+ return Ok ( String :: from_string ( agent, result) . into_value ( ) ) ;
835+ }
836+
837+ // 6. If functionalReplace is false, Set replaceValue to ? ToString(replaceValue).
838+ let replace_string = to_string ( agent, replace_value) ?;
839+ // Everything are strings: `"foo".replaceAll("o", "a")` => use rust's replace
721840 let result = s
722841 . as_str ( agent)
723842 . replace ( search_string. as_str ( agent) , replace_string. as_str ( agent) ) ;
724843 Ok ( String :: from_string ( agent, result) . into_value ( ) )
725844 }
726845
727- fn replace_all ( _agent : & mut Agent , _this_value : Value , _: ArgumentsList ) -> JsResult < Value > {
728- todo ! ( )
729- }
730-
731846 fn search ( _agent : & mut Agent , _this_value : Value , _: ArgumentsList ) -> JsResult < Value > {
732847 todo ! ( )
733848 }
0 commit comments