all: rollback to old interpolation (step 2) (#16373)

This commit is contained in:
shove 2022-11-09 22:37:27 +08:00 committed by GitHub
parent dd5f6186a1
commit a199a9afab
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
7 changed files with 53 additions and 99 deletions

View File

@ -4,45 +4,31 @@ vlib/v/checker/tests/str_interpol_invalid_err.vv:8:13: error: illegal format spe
8 | _ = '${[1]:x}' 8 | _ = '${[1]:x}'
| ^ | ^
9 | _ = '${[1]!:x}' 9 | _ = '${[1]!:x}'
10 | _ = '${Foo{}:x}' 10 | // _ = '${Foo{}:x}'
vlib/v/checker/tests/str_interpol_invalid_err.vv:9:14: error: illegal format specifier `x` for type `[1]int` vlib/v/checker/tests/str_interpol_invalid_err.vv:9:14: error: illegal format specifier `x` for type `[1]int`
7 | fn main() { 7 | fn main() {
8 | _ = '${[1]:x}' 8 | _ = '${[1]:x}'
9 | _ = '${[1]!:x}' 9 | _ = '${[1]!:x}'
| ^ | ^
10 | _ = '${Foo{}:x}' 10 | // _ = '${Foo{}:x}'
11 | _ = '${[1]:f}' 11 | _ = '${[1]:f}'
vlib/v/checker/tests/str_interpol_invalid_err.vv:10:15: error: illegal format specifier `x` for type `Foo`
8 | _ = '${[1]:x}'
9 | _ = '${[1]!:x}'
10 | _ = '${Foo{}:x}'
| ^
11 | _ = '${[1]:f}'
12 | _ := '${none:F}'
vlib/v/checker/tests/str_interpol_invalid_err.vv:11:13: error: illegal format specifier `f` for type `[]int` vlib/v/checker/tests/str_interpol_invalid_err.vv:11:13: error: illegal format specifier `f` for type `[]int`
9 | _ = '${[1]!:x}' 9 | _ = '${[1]!:x}'
10 | _ = '${Foo{}:x}' 10 | // _ = '${Foo{}:x}'
11 | _ = '${[1]:f}' 11 | _ = '${[1]:f}'
| ^ | ^
12 | _ := '${none:F}' 12 | _ := '${none:F}'
13 | // _ = '${{"a": "b"}:x}' 13 | // _ = '${{"a": "b"}:x}'
vlib/v/checker/tests/str_interpol_invalid_err.vv:12:15: error: illegal format specifier `F` for type `none` vlib/v/checker/tests/str_interpol_invalid_err.vv:12:15: error: illegal format specifier `F` for type `none`
10 | _ = '${Foo{}:x}' 10 | // _ = '${Foo{}:x}'
11 | _ = '${[1]:f}' 11 | _ = '${[1]:f}'
12 | _ := '${none:F}' 12 | _ := '${none:F}'
| ^ | ^
13 | // _ = '${{"a": "b"}:x}' 13 | // _ = '${{"a": "b"}:x}'
14 | _ = '${Alias(Foo{}):x}' 14 | // _ = '${Alias(Foo{}):x}'
vlib/v/checker/tests/str_interpol_invalid_err.vv:14:22: error: illegal format specifier `x` for type `Alias`
12 | _ := '${none:F}'
13 | // _ = '${{"a": "b"}:x}'
14 | _ = '${Alias(Foo{}):x}'
| ^
15 | _ = '${SumType(int(5)):o}'
16 | }
vlib/v/checker/tests/str_interpol_invalid_err.vv:15:25: error: illegal format specifier `o` for type `SumType` vlib/v/checker/tests/str_interpol_invalid_err.vv:15:25: error: illegal format specifier `o` for type `SumType`
13 | // _ = '${{"a": "b"}:x}' 13 | // _ = '${{"a": "b"}:x}'
14 | _ = '${Alias(Foo{}):x}' 14 | // _ = '${Alias(Foo{}):x}'
15 | _ = '${SumType(int(5)):o}' 15 | _ = '${SumType(int(5)):o}'
| ^ | ^
16 | } 16 | }

View File

@ -7,10 +7,10 @@ type SumType = Alias | int
fn main() { fn main() {
_ = '${[1]:x}' _ = '${[1]:x}'
_ = '${[1]!:x}' _ = '${[1]!:x}'
_ = '${Foo{}:x}' // _ = '${Foo{}:x}'
_ = '${[1]:f}' _ = '${[1]:f}'
_ := '${none:F}' _ := '${none:F}'
// _ = '${{"a": "b"}:x}' // _ = '${{"a": "b"}:x}'
_ = '${Alias(Foo{}):x}' // _ = '${Alias(Foo{}):x}'
_ = '${SumType(int(5)):o}' _ = '${SumType(int(5)):o}'
} }

View File

@ -803,13 +803,11 @@ fn (mut s Scanner) text_scan() token.Token {
} }
`{` { `{` {
if s.is_inside_string { if s.is_inside_string {
prev_char := s.text[s.pos - 1]
next_char := s.text[s.pos + 1]
// Handle new `hello {name}` string interpolation // Handle new `hello {name}` string interpolation
if !next_char.is_space() && next_char != `}` && prev_char != `$` { if !s.text[s.pos + 1].is_space() && s.text[s.pos - 1] != `$` {
return s.new_token(.str_dollar, '', 1) return s.new_token(.str_dollar, '', 1)
} }
if prev_char == `$` { if s.text[s.pos - 1] == `$` {
// Skip { in `${` in strings // Skip { in `${` in strings
continue continue
} else { } else {
@ -1176,7 +1174,6 @@ fn (mut s Scanner) ident_string() string {
} }
c := s.text[s.pos] c := s.text[s.pos]
prevc := s.text[s.pos - 1] prevc := s.text[s.pos - 1]
nextc := s.text[s.pos + 1]
if c == scanner.backslash { if c == scanner.backslash {
backslash_count++ backslash_count++
} }
@ -1198,23 +1195,24 @@ fn (mut s Scanner) ident_string() string {
if backslash_count % 2 == 1 && !is_raw && !is_cstr { if backslash_count % 2 == 1 && !is_raw && !is_cstr {
// Escape `\x` // Escape `\x`
if c == `x` { if c == `x` {
if nextc == s.quote || !(nextc.is_hex_digit() && s.text[s.pos + 2].is_hex_digit()) { if s.text[s.pos + 1] == s.quote || !(s.text[s.pos + 1].is_hex_digit()
&& s.text[s.pos + 2].is_hex_digit()) {
s.error(r'`\x` used without two following hex digits') s.error(r'`\x` used without two following hex digits')
} }
h_escapes_pos << s.pos - 1 h_escapes_pos << s.pos - 1
} }
// Escape `\u` // Escape `\u`
if c == `u` { if c == `u` {
if nextc == s.quote || s.text[s.pos + 2] == s.quote || s.text[s.pos + 3] == s.quote if s.text[s.pos + 1] == s.quote || s.text[s.pos + 2] == s.quote
|| s.text[s.pos + 4] == s.quote || !nextc.is_hex_digit() || s.text[s.pos + 3] == s.quote || s.text[s.pos + 4] == s.quote
|| !s.text[s.pos + 2].is_hex_digit() || !s.text[s.pos + 3].is_hex_digit() || !s.text[s.pos + 1].is_hex_digit() || !s.text[s.pos + 2].is_hex_digit()
|| !s.text[s.pos + 4].is_hex_digit() { || !s.text[s.pos + 3].is_hex_digit() || !s.text[s.pos + 4].is_hex_digit() {
s.error(r'`\u` incomplete unicode character value') s.error(r'`\u` incomplete unicode character value')
} }
u_escapes_pos << s.pos - 1 u_escapes_pos << s.pos - 1
} }
} }
// '${var}' (ignore in vfmt mode) (skip \$) // ${var} (ignore in vfmt mode) (skip \$)
if prevc == `$` && c == `{` && !is_raw if prevc == `$` && c == `{` && !is_raw
&& s.count_symbol_before(s.pos - 2, scanner.backslash) % 2 == 0 { && s.count_symbol_before(s.pos - 2, scanner.backslash) % 2 == 0 {
s.is_inside_string = true s.is_inside_string = true
@ -1223,7 +1221,7 @@ fn (mut s Scanner) ident_string() string {
s.pos -= 2 s.pos -= 2
break break
} }
// '$var' // $var
if prevc == `$` && util.is_name_char(c) && !is_raw if prevc == `$` && util.is_name_char(c) && !is_raw
&& s.count_symbol_before(s.pos - 2, scanner.backslash) % 2 == 0 { && s.count_symbol_before(s.pos - 2, scanner.backslash) % 2 == 0 {
s.is_inside_string = true s.is_inside_string = true
@ -1231,12 +1229,25 @@ fn (mut s Scanner) ident_string() string {
s.pos -= 2 s.pos -= 2
break break
} }
// '{var}' (ignore in vfmt mode) (skip \{) // {var} (ignore in vfmt mode) (skip \{)
if c == `{` && (util.is_name_char(nextc) || nextc == `@`) && prevc != `$` && !is_raw if c == `{` && util.is_name_char(s.text[s.pos + 1]) && prevc != `$` && !is_raw
&& s.count_symbol_before(s.pos - 1, scanner.backslash) % 2 == 0 { && s.count_symbol_before(s.pos - 1, scanner.backslash) % 2 == 0 {
// Detect certain strings with "{" that are not interpolation: // Detect certain strings with "{" that are not interpolation:
// e.g. "{init: " (no "}" at the end) // e.g. "{init: " (no "}" at the end)
if s.is_valid_interpolation(s.pos + 1) { mut is_valid_inter := true
for i := s.pos + 1; i < s.text.len; i++ {
if s.text[i] == `}` {
break
}
if s.text[i] in [`=`, `:`, `\n`, s.inter_quote] {
// We reached the end of the line or string without reaching "}".
// Also if there's "=", there's no way it's a valid interpolation expression:
// e.g. `println("{a.b = 42}")` `println('{foo:bar}')`
is_valid_inter = false
break
}
}
if is_valid_inter {
s.is_inside_string = true s.is_inside_string = true
s.is_enclosed_inter = true s.is_enclosed_inter = true
// so that s.pos points to $ at the next step // so that s.pos points to $ at the next step
@ -1244,19 +1255,6 @@ fn (mut s Scanner) ident_string() string {
break break
} }
} }
// '{var1}{var2}'
if prevc == `{` && (util.is_name_char(c) || c == `@`) && s.text[s.pos - 2] !in [`$`, `{`]
&& !is_raw && s.count_symbol_before(s.pos - 2, scanner.backslash) % 2 == 0 {
// Detect certain strings with "{" that are not interpolation:
// e.g. "{init: " (no "}" at the end)
if s.is_valid_interpolation(s.pos) {
s.is_inside_string = true
s.is_enclosed_inter = true
// so that s.pos points to $ at the next step
s.pos -= 2
break
}
}
if c != scanner.backslash { if c != scanner.backslash {
backslash_count = 0 backslash_count = 0
} }
@ -1312,39 +1310,6 @@ fn (mut s Scanner) ident_string() string {
return lit return lit
} }
fn (s Scanner) is_valid_interpolation(start_pos int) bool {
mut is_valid_inter := true
mut has_rcbr := false
mut inside_par := false
for i := start_pos; i < s.text.len - 1; i++ {
if s.text[i] == `(` {
inside_par = true
}
if s.text[i] == `)` && inside_par {
inside_par = false
}
if s.text[i] == s.quote && !inside_par {
break
}
if s.text[i] == `}` {
// No } in this string, so it's not a valid `{x}` interpolation
has_rcbr = true
}
if s.text[i] == `=` && (s.text[i - 1] in [`!`, `>`, `<`] || s.text[i + 1] == `=`) {
// `!=` `>=` `<=` `==`
return true
}
if s.text[i] == `=` || (s.text[i] == `:` && s.text[i + 1].is_space()) {
// We reached the end of the line or string without reaching "}".
// Also if there's "=", there's no way it's a valid interpolation expression:
// e.g. `println("{a.b = 42}")` `println('{foo: bar}')`
is_valid_inter = false
break
}
}
return is_valid_inter && has_rcbr
}
fn decode_h_escape_single(str string, idx int) (int, string) { fn decode_h_escape_single(str string, idx int) (int, string) {
end_idx := idx + 4 // "\xXX".len == 4 end_idx := idx + 4 // "\xXX".len == 4

View File

@ -9,9 +9,12 @@ fn test_string_interpolation_inner_cbr() {
println(s1) println(s1)
assert s1 == '22' assert s1 == '22'
/*
XTODO
s2 := '${St{}}' s2 := '${St{}}'
println(s2) println(s2)
assert s2 == 'St{}' assert s2 == 'St{}'
*/
s3 := '${{ s3 := '${{
'a': 1 'a': 1