From 87216cff63c2381a35cd0f365a448f9f567859af Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marco=20B=C3=B6ttcher?= <34623283+spacesinmotion@users.noreply.github.com> Date: Thu, 15 Aug 2019 11:41:23 +0200 Subject: [PATCH] compiler: '\$' escape --- compiler/scanner.v | 16 ++++++++++++++-- compiler/tests/string_interpolation_test.v | 17 +++++++++++++++++ 2 files changed, 31 insertions(+), 2 deletions(-) create mode 100644 compiler/tests/string_interpolation_test.v diff --git a/compiler/scanner.v b/compiler/scanner.v index e125d133ef..9b93be354f 100644 --- a/compiler/scanner.v +++ b/compiler/scanner.v @@ -569,6 +569,18 @@ fn (s &Scanner) error(msg string) { exit(1) } + +fn (s Scanner) count_symbol_before(p int, sym byte) int { + mut count := 0 + for i:=p; i>=0; i-- { + if s.text[i] != sym { + break + } + count++ + } + return count +} + // println('array out of bounds $idx len=$a.len') // This is really bad. It needs a major clean up fn (s mut Scanner) ident_string() string { @@ -601,14 +613,14 @@ fn (s mut Scanner) ident_string() string { s.error('0 character in a string literal') } // ${var} - if c == `{` && prevc == `$` { + if c == `{` && prevc == `$` && s.count_symbol_before(s.pos-2, `\\`) % 2 == 0 { s.inside_string = true // so that s.pos points to $ at the next step s.pos -= 2 break } // $var - if (c.is_letter() || c == `_`) && prevc == `$` { + if (c.is_letter() || c == `_`) && prevc == `$` && s.count_symbol_before(s.pos-2, `\\`) % 2 == 0 { s.inside_string = true s.dollar_start = true s.pos -= 2 diff --git a/compiler/tests/string_interpolation_test.v b/compiler/tests/string_interpolation_test.v new file mode 100644 index 0000000000..cda819000f --- /dev/null +++ b/compiler/tests/string_interpolation_test.v @@ -0,0 +1,17 @@ + +fn test_excape_dollar_in_string() { + i := 42 + + assert '($i)' == '(42)' + assert '(\$i)'.contains('i') && !'(\$i)'.contains('42') + assert !'(\\$i)'.contains('i') && '(\\$i)'.contains('42') && '(\\$i)'.contains('\\') + assert '(\\\$i)'.contains('i') && !'(\\\$i)'.contains('42') && '(\\$i)'.contains('\\') + assert !'(\\\\$i)'.contains('i') && '(\\\\$i)'.contains('42') && '(\\\\$i)'.contains('\\\\') + + assert '(${i})' == '(42)' + assert '(\${i})'.contains('i') && !'(\${i})'.contains('42') + assert !'(\\${i})'.contains('i') && '(\\${i})'.contains('42') && '(\\${i})'.contains('\\') + assert '(\\\${i})'.contains('i') && !'(\\\${i})'.contains('42') && '(\\${i})'.contains('\\') + assert !'(\\\\${i})'.contains('i') && '(\\\\${i})'.contains('42') && '(\\\\${i})'.contains('\\\\') + assert i==42 +}