diff --git a/vlib/v/ast/ast.v b/vlib/v/ast/ast.v index 22229371ba..5f6eea6276 100644 --- a/vlib/v/ast/ast.v +++ b/vlib/v/ast/ast.v @@ -216,7 +216,6 @@ pub: fills []bool fmt_poss []token.Pos pos token.Pos - has_dollar []bool // two interpolation ways are temporarily supported pub mut: exprs []Expr expr_types []Type diff --git a/vlib/v/ast/str.v b/vlib/v/ast/str.v index 879bf2442b..9dd9c9ee33 100644 --- a/vlib/v/ast/str.v +++ b/vlib/v/ast/str.v @@ -230,7 +230,7 @@ pub fn (lit &StringInterLiteral) get_fspec_braces(i int) (string, bool) { needs_fspec := lit.need_fmts[i] || lit.pluss[i] || (lit.fills[i] && lit.fwidths[i] >= 0) || lit.fwidths[i] != 0 || lit.precisions[i] != 987698 - mut needs_braces := !lit.has_dollar[i] || needs_fspec + mut needs_braces := needs_fspec sx := lit.exprs[i].str() if sx.contains(r'"') || sx.contains(r"'") { needs_braces = true @@ -480,9 +480,7 @@ pub fn (x Expr) str() string { if i >= x.exprs.len { break } - if x.has_dollar[i] { - res.write_string('$') - } + res.write_string('$') fspec_str, needs_braces := x.get_fspec_braces(i) if needs_braces { res.write_string('{') diff --git a/vlib/v/checker/tests/str_interpol_invalid_err.out b/vlib/v/checker/tests/str_interpol_invalid_err.out index 41c68f0423..28f5252eef 100644 --- a/vlib/v/checker/tests/str_interpol_invalid_err.out +++ b/vlib/v/checker/tests/str_interpol_invalid_err.out @@ -1,5 +1,5 @@ vlib/v/checker/tests/str_interpol_invalid_err.vv:8:13: error: illegal format specifier `x` for type `[]int` - 6 | + 6 | 7 | fn main() { 8 | _ = '${[1]:x}' | ^ @@ -25,30 +25,23 @@ vlib/v/checker/tests/str_interpol_invalid_err.vv:11:13: error: illegal format sp 11 | _ = '${[1]: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` 10 | _ = '${Foo{}:x}' 11 | _ = '${[1]:f}' 12 | _ := '${none:F}' | ^ - 13 | _ = '${{"a": "b"}:x}' + 13 | // _ = '${{"a": "b"}:x}' 14 | _ = '${Alias(Foo{}):x}' -vlib/v/checker/tests/str_interpol_invalid_err.vv:13:20: error: illegal format specifier `x` for type `map[string]string` - 11 | _ = '${[1]:f}' - 12 | _ := '${none:F}' - 13 | _ = '${{"a": "b"}:x}' - | ^ - 14 | _ = '${Alias(Foo{}):x}' - 15 | _ = '${SumType(int(5)):o}' 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}' + 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` - 13 | _ = '${{"a": "b"}:x}' + 13 | // _ = '${{"a": "b"}:x}' 14 | _ = '${Alias(Foo{}):x}' 15 | _ = '${SumType(int(5)):o}' | ^ diff --git a/vlib/v/checker/tests/str_interpol_invalid_err.vv b/vlib/v/checker/tests/str_interpol_invalid_err.vv index b938fcfc5d..556a798f33 100644 --- a/vlib/v/checker/tests/str_interpol_invalid_err.vv +++ b/vlib/v/checker/tests/str_interpol_invalid_err.vv @@ -10,7 +10,7 @@ fn main() { _ = '${Foo{}:x}' _ = '${[1]:f}' _ := '${none:F}' - _ = '${{"a": "b"}:x}' + // _ = '${{"a": "b"}:x}' _ = '${Alias(Foo{}):x}' _ = '${SumType(int(5)):o}' } diff --git a/vlib/v/fmt/fmt.v b/vlib/v/fmt/fmt.v index 8f0867446b..76cb8715d0 100644 --- a/vlib/v/fmt/fmt.v +++ b/vlib/v/fmt/fmt.v @@ -2706,9 +2706,7 @@ pub fn (mut f Fmt) string_inter_literal(node ast.StringInterLiteral) { if i >= node.exprs.len { break } - if node.has_dollar[i] { - f.write('$') - } + f.write('$') fspec_str, needs_braces := node.get_fspec_braces(i) if needs_braces { f.write('{') diff --git a/vlib/v/parser/parser.v b/vlib/v/parser/parser.v index 4d6b87aa9b..e77be9842e 100644 --- a/vlib/v/parser/parser.v +++ b/vlib/v/parser/parser.v @@ -3056,7 +3056,7 @@ fn (mut p Parser) string_expr() ast.Expr { val := p.tok.lit mut pos := p.tok.pos() pos.last_line = pos.line_nr + val.count('\n') - if p.peek_tok.kind != .str_dollar && p.peek_tok.kind != .str_lcbr { + if p.peek_tok.kind != .str_dollar { p.next() p.filter_string_vet_errors(pos) node = ast.StringLiteral{ @@ -3076,16 +3076,14 @@ fn (mut p Parser) string_expr() ast.Expr { mut fills := []bool{} mut fmts := []u8{} mut fposs := []token.Pos{} - mut has_dollar := []bool{} // Handle $ interpolation p.inside_str_interp = true for p.tok.kind == .string { vals << p.tok.lit p.next() - if p.tok.kind != .str_dollar && p.tok.kind != .str_lcbr { + if p.tok.kind != .str_dollar { break } - has_dollar_ := p.tok.kind == .str_dollar p.next() exprs << p.expr(0) mut has_fmt := false @@ -3138,7 +3136,6 @@ fn (mut p Parser) string_expr() ast.Expr { fmts << fmt fills << fill fposs << p.prev_tok.pos() - has_dollar << has_dollar_ } pos = pos.extend(p.prev_tok.pos()) p.filter_string_vet_errors(pos) @@ -3153,7 +3150,6 @@ fn (mut p Parser) string_expr() ast.Expr { fmts: fmts fmt_poss: fposs pos: pos - has_dollar: has_dollar } // need_fmts: prelimery - until checker finds out if really needed p.inside_str_interp = false diff --git a/vlib/v/scanner/scanner.v b/vlib/v/scanner/scanner.v index 43570db410..94840d4c62 100644 --- a/vlib/v/scanner/scanner.v +++ b/vlib/v/scanner/scanner.v @@ -37,7 +37,6 @@ pub mut: is_inter_start bool // for hacky string interpolation TODO simplify is_inter_end bool is_enclosed_inter bool - is_inside_interpolation bool // avoid nesting interpolation line_comment string last_lt int = -1 // position of latest < is_started bool @@ -109,7 +108,7 @@ pub enum CommentsMode { // new scanner from file. pub fn new_scanner_file(file_path string, comments_mode CommentsMode, pref &pref.Preferences) !&Scanner { if !os.is_file(file_path) { - return error('{file_path} is not a .v file') + return error('$file_path is not a .v file') } raw_text := util.read_file(file_path) or { return err } mut s := &Scanner{ @@ -287,7 +286,7 @@ fn (mut s Scanner) ident_bin_number() string { s.error('number part of this binary is not provided') } else if has_wrong_digit { s.pos = first_wrong_digit_pos // adjust error position - s.error('this binary number has unsuitable digit `{first_wrong_digit.str()}`') + s.error('this binary number has unsuitable digit `$first_wrong_digit.str()`') } number := s.num_lit(start_pos, s.pos) s.pos-- @@ -331,7 +330,7 @@ fn (mut s Scanner) ident_hex_number() string { s.error('number part of this hexadecimal is not provided') } else if has_wrong_digit { s.pos = first_wrong_digit_pos // adjust error position - s.error('this hexadecimal number has unsuitable digit `{first_wrong_digit.str()}`') + s.error('this hexadecimal number has unsuitable digit `$first_wrong_digit.str()`') } number := s.num_lit(start_pos, s.pos) s.pos-- @@ -371,7 +370,7 @@ fn (mut s Scanner) ident_oct_number() string { s.error('number part of this octal is not provided') } else if has_wrong_digit { s.pos = first_wrong_digit_pos // adjust error position - s.error('this octal number has unsuitable digit `{first_wrong_digit.str()}`') + s.error('this octal number has unsuitable digit `$first_wrong_digit.str()`') } number := s.num_lit(start_pos, s.pos) s.pos-- @@ -447,7 +446,7 @@ fn (mut s Scanner) ident_dec_number() string { symbol_length++ } float_symbol := s.text[s.pos - 2 - symbol_length..s.pos - 1] - s.warn('float literals should have a digit after the decimal point, e.g. `{float_symbol}.0`') + s.warn('float literals should have a digit after the decimal point, e.g. `${float_symbol}.0`') } } } @@ -481,7 +480,7 @@ fn (mut s Scanner) ident_dec_number() string { // error check: wrong digit s.pos = first_wrong_digit_pos // adjust error position if !s.pref.translated { - s.error('this number has unsuitable digit `{first_wrong_digit.str()}`') + s.error('this number has unsuitable digit `$first_wrong_digit.str()`') } } else if s.text[s.pos - 1] in [`e`, `E`] { // error check: 5e @@ -544,7 +543,7 @@ fn (mut s Scanner) end_of_file() token.Token { if s.eofs > 50 { s.line_nr-- panic( - 'the end of file `{s.file_path}` has been reached 50 times already, the v parser is probably stuck.\n' + + 'the end of file `$s.file_path` has been reached 50 times already, the v parser is probably stuck.\n' + 'This should not happen. Please report the bug here, and include the last 2-3 lines of your source code:\n' + 'https://github.com/vlang/v/issues/new?labels=Bug&template=bug_report.md') } @@ -567,7 +566,7 @@ fn (mut s Scanner) scan_all_tokens_in_buffer() { s.tidx = 0 $if debugscanner ? { for t in s.all_tokens { - eprintln('> tidx:{t.tidx:-5} | kind: {t.kind:-10} | lit: {t.lit}') + eprintln('> tidx:${t.tidx:-5} | kind: ${t.kind:-10} | lit: $t.lit') } } } @@ -678,14 +677,13 @@ fn (mut s Scanner) text_scan() token.Token { s.is_inter_end = true s.is_inter_start = false s.is_inside_string = false - s.is_inside_interpolation = false } } // end of `$expr` // allow `'$a.b'` and `'$a.c()'` if s.is_inter_start && next_char == `\\` && s.look_ahead(2) !in [`x`, `n`, `r`, `\\`, `t`, `e`, `"`, `'`] { - s.warn('unknown escape sequence \\{s.look_ahead(2)}') + s.warn('unknown escape sequence \\${s.look_ahead(2)}') } if s.is_inter_start && next_char == `(` { if s.look_ahead(2) != `)` { @@ -694,7 +692,6 @@ fn (mut s Scanner) text_scan() token.Token { } else if s.is_inter_start && next_char != `.` { s.is_inter_end = true s.is_inter_start = false - s.is_inside_interpolation = false } return s.new_token(.name, name, name.len) } else if c.is_digit() || (c == `.` && nextc.is_digit()) { @@ -723,7 +720,6 @@ fn (mut s Scanner) text_scan() token.Token { s.is_inter_start = false if next_char == s.quote { s.is_inside_string = false - s.is_inside_interpolation = false } return s.new_token(.rpar, '', 1) } @@ -810,12 +806,10 @@ fn (mut s Scanner) text_scan() token.Token { prev_char := s.text[s.pos - 1] next_char := s.text[s.pos + 1] // Handle new `hello {name}` string interpolation - if !s.is_inside_interpolation && !next_char.is_space() && next_char != `}` - && prev_char != `$` { - s.is_inside_interpolation = true - return s.new_token(.str_lcbr, '', 1) + if !next_char.is_space() && next_char != `}` && prev_char != `$` { + return s.new_token(.str_dollar, '', 1) } - if s.is_inside_interpolation && prev_char == `$` { + if prev_char == `$` { // Skip { in `${` in strings continue } else { @@ -826,7 +820,6 @@ fn (mut s Scanner) text_scan() token.Token { } `$` { if s.is_inside_string { - s.is_inside_interpolation = true return s.new_token(.str_dollar, '', 1) } else { return s.new_token(.dollar, '', 1) @@ -844,11 +837,9 @@ fn (mut s Scanner) text_scan() token.Token { if s.text[s.pos] == s.quote { s.is_inside_string = false s.is_enclosed_inter = false - s.is_inside_interpolation = false return s.new_token(.string, '', 1) } s.is_enclosed_inter = false - s.is_inside_interpolation = false ident_string := s.ident_string() return s.new_token(.string, ident_string, ident_string.len + 2) // + two quotes } else { @@ -901,7 +892,7 @@ fn (mut s Scanner) text_scan() token.Token { mut at_error_msg := '@ must be used before keywords or compile time variables (e.g. `@type string` or `@FN`)' // If name is all uppercase, the user is probably looking for a compile time variable ("at-token") if name.is_upper() { - at_error_msg += '\nAvailable compile time variables:\n{token.valid_at_tokens}' + at_error_msg += '\nAvailable compile time variables:\n$token.valid_at_tokens' } s.error(at_error_msg) } @@ -1125,7 +1116,7 @@ fn (mut s Scanner) invalid_character() { len := utf8_char_len(s.text[s.pos]) end := mathutil.min(s.pos + len, s.text.len) c := s.text[s.pos..end] - s.error('invalid character `{c}`') + s.error('invalid character `$c`') } fn (s &Scanner) current_column() int { @@ -1228,7 +1219,6 @@ fn (mut s Scanner) ident_string() string { && s.count_symbol_before(s.pos - 2, scanner.backslash) % 2 == 0 { s.is_inside_string = true s.is_enclosed_inter = true - s.is_inside_interpolation = true // so that s.pos points to $ at the next step s.pos -= 2 break @@ -1238,7 +1228,6 @@ fn (mut s Scanner) ident_string() string { && s.count_symbol_before(s.pos - 2, scanner.backslash) % 2 == 0 { s.is_inside_string = true s.is_inter_start = true - s.is_inside_interpolation = true s.pos -= 2 break } @@ -1410,7 +1399,7 @@ fn (mut s Scanner) decode_u_escape_single(str string, idx int) (int, string) { escaped_code_point := strconv.parse_uint(str[idx + 2..end_idx], 16, 32) or { 0 } // Check if Escaped Code Point is invalid or not if rune(escaped_code_point).length_in_bytes() == -1 { - s.error('invalid unicode point `{str}`') + s.error('invalid unicode point `$str`') } return end_idx, utf32_to_str(u32(escaped_code_point)) @@ -1531,15 +1520,15 @@ fn (mut s Scanner) ident_char() string { u := c.runes() if u.len != 1 { if escaped_hex || escaped_unicode { - s.error('invalid character literal `{orig}` => `{c}` ({u}) (escape sequence did not refer to a singular rune)') + s.error('invalid character literal `$orig` => `$c` ($u) (escape sequence did not refer to a singular rune)') } else if u.len == 0 { s.add_error_detail_with_pos('use quotes for strings, backticks for characters', lspos) - s.error('invalid empty character literal `{orig}`') + s.error('invalid empty character literal `$orig`') } else { s.add_error_detail_with_pos('use quotes for strings, backticks for characters', lspos) - s.error('invalid character literal `{orig}` => `{c}` ({u}) (more than one character)') + s.error('invalid character literal `$orig` => `$c` ($u) (more than one character)') } } } @@ -1713,6 +1702,6 @@ fn (mut s Scanner) vet_error(msg string, fix vet.FixKind) { fn (mut s Scanner) trace(fbase string, message string) { if s.file_base == fbase { - println('> s.trace | {fbase:-10s} | {message}') + println('> s.trace | ${fbase:-10s} | $message') } } diff --git a/vlib/v/tests/inout/string_interpolation_inner_expr_cbr.out b/vlib/v/tests/inout/string_interpolation_inner_expr_cbr.out deleted file mode 100644 index 41f0b6d769..0000000000 --- a/vlib/v/tests/inout/string_interpolation_inner_expr_cbr.out +++ /dev/null @@ -1,2 +0,0 @@ -Foo = def -Foo = def diff --git a/vlib/v/tests/inout/string_interpolation_inner_expr_cbr.vv b/vlib/v/tests/inout/string_interpolation_inner_expr_cbr.vv deleted file mode 100644 index f63cc64124..0000000000 --- a/vlib/v/tests/inout/string_interpolation_inner_expr_cbr.vv +++ /dev/null @@ -1,9 +0,0 @@ -enum Foo { - abc - def -} - -fn main() { - println('Foo = {Foo.def}') - println('Foo = {unsafe { Foo(1) }}') -} diff --git a/vlib/v/tests/string_new_interpolation_test.v b/vlib/v/tests/string_new_interpolation_test.v deleted file mode 100644 index ddb6032a21..0000000000 --- a/vlib/v/tests/string_new_interpolation_test.v +++ /dev/null @@ -1,57 +0,0 @@ -fn test_string_new_interpolation() { - a, b, c, d := 1, 2, 3, 4 - - println('{a}{b}{c}{d}') - assert '{a}{b}{c}{d}' == '1234' - - println('{a} {b} {c} {d}') - assert '{a} {b} {c} {d}' == '1 2 3 4' - - println('{a}{{b}}') - assert '{a}{{b}}' == '1{2}' - - println('{a}\{{b}}') - assert '{a}\{{b}}' == '1{2}' - - println('{a}{{{{{b}}}}}') - assert '{a}{{{{{b}}}}}' == '1{{{{2}}}}' - - s := 'hello' - println('{s == 'hello'}') - assert '{s == 'hello'}' == 'true' - println('{s != 'hello'}') - assert '{s != 'hello'}' == 'false' - - n := 22 - println('{n >= 10}') - assert '{n >= 10}' == 'true' - println('{n <= 10}') - assert '{n <= 10}' == 'false' - - println('{n:10}') - assert '{n:10}' == ' 22' - - f := 2.234 - println('{f:05.2f}') - assert '{f:05.2f}' == '02.23' - - println('{@FILE}') - assert '{@FILE}'.contains('string_new_interpolation_test.v') - - ret := foo() - println(ret) - assert ret == r'[]T{aaa, bbb, ccc}' -} - -fn foo() string { - match true { - true { - fields := ['aaa', 'bbb', 'ccc'] - return '[]T{{fields.join(', ')}}' - } - else { - fields := ['aaa', 'bbb', 'ccc'] - return 'const ({fields.join(' ')})' - } - } -} diff --git a/vlib/v/token/token.v b/vlib/v/token/token.v index 323d3b3cb3..88e9e04b8c 100644 --- a/vlib/v/token/token.v +++ b/vlib/v/token/token.v @@ -46,8 +46,7 @@ pub enum Kind { hash // # dollar // $ at // @ - str_dollar // ${} or $, old interpolation - str_lcbr // {interpolation + str_dollar left_shift // << right_shift // >> unsigned_right_shift // >>> @@ -271,8 +270,7 @@ fn build_token_str() []string { s[Kind.nl] = 'NLL' s[Kind.dollar] = '$' s[Kind.at] = '@' - s[Kind.str_dollar] = 'string interpolation1' - s[Kind.str_lcbr] = 'string interpolation2' + s[Kind.str_dollar] = '$2' s[Kind.key_assert] = 'assert' s[Kind.key_struct] = 'struct' s[Kind.key_if] = 'if' @@ -543,7 +541,6 @@ pub fn kind_to_string(k Kind) string { .dollar { 'dollar' } .at { 'at' } .str_dollar { 'str_dollar' } - .str_lcbr { 'str_lcbr' } .left_shift { 'left_shift' } .right_shift { 'right_shift' } .unsigned_right_shift { 'unsigned_right_shift' } @@ -666,7 +663,6 @@ pub fn kind_from_string(s string) !Kind { 'dollar' { .dollar } 'at' { .at } 'str_dollar' { .str_dollar } - 'str_lcbr' { .str_lcbr } 'left_shift' { .left_shift } 'right_shift' { .right_shift } 'unsigned_right_shift' { .unsigned_right_shift }