all: add r and R switches for repeating in string interpolation, '${"abc":3r}' == 'abcabcabc' (#20197)

This commit is contained in:
penguindark 2023-12-17 11:23:17 +01:00 committed by GitHub
parent 51aaf3c49f
commit ae16878272
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
6 changed files with 47 additions and 3 deletions

View file

@ -350,3 +350,17 @@ fn test_interpolate_literal_limits() {
assert '10 ${u32(0o377777_77777)}' == '10 4294967295' assert '10 ${u32(0o377777_77777)}' == '10 4294967295'
assert '11 ${i64(-2147483647)}' == '11 -2147483647' 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'
}

View file

@ -33,6 +33,7 @@ pub enum StrIntpType {
si_g64 si_g64
si_s si_s
si_p si_p
si_r
si_vp si_vp
} }
@ -56,6 +57,7 @@ pub fn (x StrIntpType) str() string {
.si_e64 { 'f64' } // e64 format use f64 data .si_e64 { 'f64' } // e64 format use f64 data
.si_s { 's' } .si_s { 's' }
.si_p { 'p' } .si_p { 'p' }
.si_r { 'r' } // repeat string
.si_vp { 'vp' } .si_vp { 'vp' }
} }
} }
@ -75,6 +77,7 @@ pub mut:
d_f32 f32 d_f32 f32
d_f64 f64 d_f64 f64
d_s string d_s string
d_r string
d_p voidptr d_p voidptr
d_vp voidptr d_vp voidptr
} }
@ -224,6 +227,27 @@ fn (data &StrIntpData) process_str_intp_data(mut sb strings.Builder) {
return 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 // signed int
if typ in [.si_i8, .si_i16, .si_i32, .si_i64] { if typ in [.si_i8, .si_i16, .si_i32, .si_i64] {
mut d := data.d.d_i64 mut d := data.d.d_i64

View file

@ -68,7 +68,7 @@ fn (mut c Checker) string_inter_lit(mut node ast.StringInterLiteral) ast.Type {
mut fmt := node.fmts[i] mut fmt := node.fmts[i]
// analyze and validate format specifier // analyze and validate format specifier
if fmt !in [`E`, `F`, `G`, `e`, `f`, `g`, `d`, `u`, `x`, `X`, `o`, `c`, `s`, `S`, `p`, 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]) c.error('unknown format specifier `${fmt:c}`', node.fmt_poss[i])
} }
if fmt == `_` { // set default representation for type if none has been given 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`]) && 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_float() && fmt !in [`E`, `F`, `G`, `e`, `f`, `g`])
|| (typ.is_pointer() && fmt !in [`p`, `x`, `X`]) || (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.idx() in [ast.i64_type_idx, ast.f64_type_idx] && fmt == `c`))
&& !(typ.is_ptr() && fmt in [`p`, `x`, `X`]) { && !(typ.is_ptr() && fmt in [`p`, `x`, `X`]) {
c.error('illegal format specifier `${fmt:c}` for type `${c.table.get_type_name(ftyp)}`', c.error('illegal format specifier `${fmt:c}` for type `${c.table.get_type_name(ftyp)}`',
node.fmt_poss[i]) node.fmt_poss[i])
} }
if c.table.final_sym(typ).kind in [.array, .array_fixed, .struct_, .interface_, .none_, .map, .sum_type] 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`]) { && !(typ.is_ptr() && fmt in [`p`, `x`, `X`]) {
c.error('illegal format specifier `${fmt:c}` for type `${c.table.get_type_name(ftyp)}`', c.error('illegal format specifier `${fmt:c}` for type `${c.table.get_type_name(ftyp)}`',
node.fmt_poss[i]) node.fmt_poss[i])

View file

@ -1139,6 +1139,7 @@ fn data_str(x StrIntpType) string {
.si_e32 { 'd_f32' } // e32 format use f32 data .si_e32 { 'd_f32' } // e32 format use f32 data
.si_e64 { 'd_f64' } // e64 format use f64 data .si_e64 { 'd_f64' } // e64 format use f64 data
.si_s { 'd_s' } .si_s { 'd_s' }
.si_r { 'd_r' } // repeat string
.si_p { 'd_p' } .si_p { 'd_p' }
.si_vp { 'd_vp' } .si_vp { 'd_vp' }
} }

View file

@ -76,6 +76,8 @@ fn (mut g Gen) str_format(node ast.StringInterLiteral, i int, fmts []u8) (u64, s
} }
*/ */
fmt_type = .si_s fmt_type = .si_s
} else if fspec in [`r`, `R`] {
fmt_type = .si_r
} else if typ.is_float() { } else if typ.is_float() {
if fspec in [`g`, `G`] { if fspec in [`g`, `G`] {
match typ { match typ {

View file

@ -125,6 +125,7 @@ pub enum StrIntpType {
si_g64 si_g64
si_s si_s
si_p si_p
si_r
si_vp si_vp
} }
@ -148,6 +149,7 @@ pub fn type_to_str(x StrIntpType) string {
.si_e64 { return 'f64' } // e64 format use f64 data .si_e64 { return 'f64' } // e64 format use f64 data
.si_s { return 's' } .si_s { return 's' }
.si_p { return 'p' } .si_p { return 'p' }
.si_r { return 'r' } // repeat string
.si_vp { return 'vp' } .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_e64 { return 'd_f64' } // e64 format use f64 data
.si_s { return 'd_s' } .si_s { return 'd_s' }
.si_p { return 'd_p' } .si_p { return 'd_p' }
.si_r { return 'd_r' } // repeat string
.si_vp { return 'd_vp' } .si_vp { return 'd_vp' }
} }
} }