diff --git a/vlib/builtin/string_int_test.v b/vlib/builtin/string_int_test.v index 94eabc35af..81fafa5f22 100644 --- a/vlib/builtin/string_int_test.v +++ b/vlib/builtin/string_int_test.v @@ -350,3 +350,17 @@ fn test_interpolate_literal_limits() { assert '10 ${u32(0o377777_77777)}' == '10 4294967295' assert '11 ${i64(-2147483647)}' == '11 -2147483647' } + +fn test_string_repetition() { + a := 'pippo' + assert '${'pera':r}' == '' + assert '${'pera':R}' == '' + assert '${'pera':0r}' == '' + assert '${'pera':0R}' == '' + assert '${'pera':1r}' == 'pera' + assert '${'pera':1R}' == 'PERA' + assert '${'pera':2r}' == 'perapera' + assert '${'pera':2R}' == 'PERAPERA' + assert '${a:2r}' == 'pippopippo' + assert '${a:2R}' == 'PIPPOPIPPO' +} diff --git a/vlib/builtin/string_interpolation.v b/vlib/builtin/string_interpolation.v index 1a20d074a8..3c31b274b7 100644 --- a/vlib/builtin/string_interpolation.v +++ b/vlib/builtin/string_interpolation.v @@ -33,6 +33,7 @@ pub enum StrIntpType { si_g64 si_s si_p + si_r si_vp } @@ -56,6 +57,7 @@ pub fn (x StrIntpType) str() string { .si_e64 { 'f64' } // e64 format use f64 data .si_s { 's' } .si_p { 'p' } + .si_r { 'r' } // repeat string .si_vp { 'vp' } } } @@ -75,6 +77,7 @@ pub mut: d_f32 f32 d_f64 f64 d_s string + d_r string d_p voidptr d_vp voidptr } @@ -224,6 +227,27 @@ fn (data &StrIntpData) process_str_intp_data(mut sb strings.Builder) { return } + if typ == .si_r { + if width > 0 { + mut s := '' + if upper_case { + s = data.d.d_s.to_upper() + } else { + s = data.d.d_s.clone() + } + + for _ in 1 .. (1 + (if width > 0 { + width + } else { + 0 + })) { + sb.write_string(s) + } + s.free() + } + return + } + // signed int if typ in [.si_i8, .si_i16, .si_i32, .si_i64] { mut d := data.d.d_i64 diff --git a/vlib/v/checker/str.v b/vlib/v/checker/str.v index 611966072d..c4142d3bbe 100644 --- a/vlib/v/checker/str.v +++ b/vlib/v/checker/str.v @@ -68,7 +68,7 @@ fn (mut c Checker) string_inter_lit(mut node ast.StringInterLiteral) ast.Type { mut fmt := node.fmts[i] // analyze and validate format specifier if fmt !in [`E`, `F`, `G`, `e`, `f`, `g`, `d`, `u`, `x`, `X`, `o`, `c`, `s`, `S`, `p`, - `b`, `_`] { + `b`, `_`, `r`, `R`] { c.error('unknown format specifier `${fmt:c}`', node.fmt_poss[i]) } if fmt == `_` { // set default representation for type if none has been given @@ -99,14 +99,14 @@ fn (mut c Checker) string_inter_lit(mut node ast.StringInterLiteral) ast.Type { && fmt !in [`d`, `c`, `x`, `X`, `o`, `u`, `x`, `X`, `o`, `b`]) || (typ.is_float() && fmt !in [`E`, `F`, `G`, `e`, `f`, `g`]) || (typ.is_pointer() && fmt !in [`p`, `x`, `X`]) - || (typ.is_string() && fmt !in [`s`, `S`]) + || (typ.is_string() && fmt !in [`s`, `S`, `r`, `R`]) || (typ.idx() in [ast.i64_type_idx, ast.f64_type_idx] && fmt == `c`)) && !(typ.is_ptr() && fmt in [`p`, `x`, `X`]) { c.error('illegal format specifier `${fmt:c}` for type `${c.table.get_type_name(ftyp)}`', node.fmt_poss[i]) } if c.table.final_sym(typ).kind in [.array, .array_fixed, .struct_, .interface_, .none_, .map, .sum_type] - && fmt in [`E`, `F`, `G`, `e`, `f`, `g`, `d`, `u`, `x`, `X`, `o`, `c`, `p`, `b`] + && fmt in [`E`, `F`, `G`, `e`, `f`, `g`, `d`, `u`, `x`, `X`, `o`, `c`, `p`, `b`, `r`, `R`] && !(typ.is_ptr() && fmt in [`p`, `x`, `X`]) { c.error('illegal format specifier `${fmt:c}` for type `${c.table.get_type_name(ftyp)}`', node.fmt_poss[i]) diff --git a/vlib/v/gen/c/auto_str_methods.v b/vlib/v/gen/c/auto_str_methods.v index 538894cfdc..9fc7201ece 100644 --- a/vlib/v/gen/c/auto_str_methods.v +++ b/vlib/v/gen/c/auto_str_methods.v @@ -1139,6 +1139,7 @@ fn data_str(x StrIntpType) string { .si_e32 { 'd_f32' } // e32 format use f32 data .si_e64 { 'd_f64' } // e64 format use f64 data .si_s { 'd_s' } + .si_r { 'd_r' } // repeat string .si_p { 'd_p' } .si_vp { 'd_vp' } } diff --git a/vlib/v/gen/c/str_intp.v b/vlib/v/gen/c/str_intp.v index 1c5b7412eb..7f1553cb2c 100644 --- a/vlib/v/gen/c/str_intp.v +++ b/vlib/v/gen/c/str_intp.v @@ -76,6 +76,8 @@ fn (mut g Gen) str_format(node ast.StringInterLiteral, i int, fmts []u8) (u64, s } */ fmt_type = .si_s + } else if fspec in [`r`, `R`] { + fmt_type = .si_r } else if typ.is_float() { if fspec in [`g`, `G`] { match typ { diff --git a/vlib/v/gen/js/auto_str_methods.v b/vlib/v/gen/js/auto_str_methods.v index 0255d5fdd0..714724121d 100644 --- a/vlib/v/gen/js/auto_str_methods.v +++ b/vlib/v/gen/js/auto_str_methods.v @@ -125,6 +125,7 @@ pub enum StrIntpType { si_g64 si_s si_p + si_r si_vp } @@ -148,6 +149,7 @@ pub fn type_to_str(x StrIntpType) string { .si_e64 { return 'f64' } // e64 format use f64 data .si_s { return 's' } .si_p { return 'p' } + .si_r { return 'r' } // repeat string .si_vp { return 'vp' } } } @@ -172,6 +174,7 @@ pub fn data_str(x StrIntpType) string { .si_e64 { return 'd_f64' } // e64 format use f64 data .si_s { return 'd_s' } .si_p { return 'd_p' } + .si_r { return 'd_r' } // repeat string .si_vp { return 'd_vp' } } }