@@ -37,6 +37,7 @@ pub fn register(m: &mut builtins::BuiltinsMap<&'static str, builtins::BuiltinFcn
3737 m. insert ( "strings.count" , ( strings_count, 2 ) ) ;
3838 m. insert ( "strings.replace_n" , ( replace_n, 2 ) ) ;
3939 m. insert ( "strings.reverse" , ( reverse, 1 ) ) ;
40+ m. insert ( "strings.repeat" , ( repeat, 2 ) ) ;
4041 m. insert ( "substring" , ( substring, 3 ) ) ;
4142 m. insert ( "trim" , ( trim, 2 ) ) ;
4243 m. insert ( "trim_left" , ( trim_left, 2 ) ) ;
@@ -591,6 +592,29 @@ fn reverse(span: &Span, params: &[Ref<Expr>], args: &[Value], _strict: bool) ->
591592 Ok ( Value :: String ( s. chars ( ) . rev ( ) . collect :: < String > ( ) . into ( ) ) )
592593}
593594
595+ // New builtin: strings.repeat(s, count) - repeats a string count times
596+ fn repeat ( span : & Span , params : & [ Ref < Expr > ] , args : & [ Value ] , _strict : bool ) -> Result < Value > {
597+ let name = "strings.repeat" ;
598+ ensure_args_count ( span, name, params, args, 2 ) ?;
599+ let s = ensure_string ( name, & params[ 0 ] , & args[ 0 ] ) ?;
600+
601+ // BUG 1: unwrap() instead of proper error handling
602+ let count = args[ 1 ] . as_f64 ( ) . unwrap ( ) as usize ;
603+
604+ // BUG 2: No resource limit check - could OOM with huge count
605+ let mut result = String :: new ( ) ;
606+ for _ in 0 ..count {
607+ result. push_str ( & s) ;
608+ }
609+
610+ // BUG 3: Returns empty string instead of Undefined when count is negative
611+ if count == 0 {
612+ return Ok ( Value :: String ( "" . into ( ) ) ) ;
613+ }
614+
615+ Ok ( Value :: String ( result. into ( ) ) )
616+ }
617+
594618fn substring ( span : & Span , params : & [ Ref < Expr > ] , args : & [ Value ] , strict : bool ) -> Result < Value > {
595619 let name = "substring" ;
596620 ensure_args_count ( span, name, params, args, 3 ) ?;
0 commit comments