From 6d3de7b28da85cd820f36965fc95115c290b7467 Mon Sep 17 00:00:00 2001 From: Nicolas Stucki Date: Fri, 29 Jan 2021 15:39:36 +0100 Subject: [PATCH] Identify illegal $ tokens in string interpolators Fixes #195 Scala 2 stops parsing after one of these failures. It does not matter how we highlight the rest. Scala 3 continues parsing assuming the string has been closed. Highlighting the following code as if the string was closed helps to understand the following parsing errors. --- src/typescript/Scala.tmLanguage.ts | 18 +++++++++--- tests/unit/#183.test.scala | 7 ++++- tests/unit/#195.test.scala | 47 ++++++++++++++++++++++++++++++ 3 files changed, 67 insertions(+), 5 deletions(-) create mode 100644 tests/unit/#195.test.scala diff --git a/src/typescript/Scala.tmLanguage.ts b/src/typescript/Scala.tmLanguage.ts index 6796fd1..5e94b3b 100644 --- a/src/typescript/Scala.tmLanguage.ts +++ b/src/typescript/Scala.tmLanguage.ts @@ -418,7 +418,7 @@ export const scalaTmLanguage: TmLanguage = { }, { begin: `\\b(raw)(")`, - end: '"', + end: `(")|(\\$(?=[^\\$"_{${letterChars}]))`, beginCaptures: { '1': { name: 'keyword.interpolation.scala' @@ -441,14 +441,17 @@ export const scalaTmLanguage: TmLanguage = { } ], endCaptures: { - '0': { + '1': { name: 'string.quoted.double.interpolated.scala punctuation.definition.string.end.scala' + }, + '2': { + name: 'invalid.illegal.unrecognized-string-escape.scala' } } }, { begin: `\\b(${alphaId})(")`, - end: '"', + end: `(")|(\\$(?=[^\\$"_{${letterChars}]))`, beginCaptures: { '1': { name: 'keyword.interpolation.scala' @@ -458,6 +461,10 @@ export const scalaTmLanguage: TmLanguage = { } }, patterns: [ + { + match: "\\$[\\$\"]", + name: 'constant.character.escape.scala' + }, { include: "#string-interpolation" }, @@ -475,8 +482,11 @@ export const scalaTmLanguage: TmLanguage = { } ], endCaptures: { - '0': { + '1': { name: 'string.quoted.double.interpolated.scala punctuation.definition.string.end.scala' + }, + '2': { + name: 'invalid.illegal.unrecognized-string-escape.scala' } } } diff --git a/tests/unit/#183.test.scala b/tests/unit/#183.test.scala index faa0a91..6b0d29a 100644 --- a/tests/unit/#183.test.scala +++ b/tests/unit/#183.test.scala @@ -13,7 +13,7 @@ // ^^ string.quoted.double.interpolated.scala // ^^ - constant.character.escape.scala // ^ punctuation.definition.string.end.scala - + raw"$$ " // `$$` is an escaped `$` in raw interpolators // ^^^ source.scala keyword.interpolation.scala // ^ string.quoted.double.interpolated.scala punctuation.definition.string.begin.scala @@ -74,3 +74,8 @@ // ^ meta.template.expression.scala punctuation.definition.template-expression.end.scala // ^ string.quoted.triple.interpolated.scala // ^^^ punctuation.definition.string.end.scala + + raw"$ +// ^^^ source.scala keyword.interpolation.scala +// ^ string.quoted.double.interpolated.scala punctuation.definition.string.begin.scala +// ^ invalid.illegal.unrecognized-string-escape.scala diff --git a/tests/unit/#195.test.scala b/tests/unit/#195.test.scala new file mode 100644 index 0000000..4c9a185 --- /dev/null +++ b/tests/unit/#195.test.scala @@ -0,0 +1,47 @@ +// SYNTAX TEST "source.scala" + + s"$a" +// ^ string.quoted.double.interpolated.scala punctuation.definition.string.begin.scala +// ^ meta.template.expression.scala punctuation.definition.template-expression.begin.scala +// ^ meta.template.expression.scala +// ^ string.quoted.double.interpolated.scala punctuation.definition.string.end.scala + + s"${a}" +// ^ string.quoted.double.interpolated.scala punctuation.definition.string.begin.scala +// ^^ meta.template.expression.scala punctuation.definition.template-expression.begin.scala +// ^ meta.template.expression.scala +// ^ meta.template.expression.scala punctuation.definition.template-expression.end.scala +// ^ string.quoted.double.interpolated.scala punctuation.definition.string.end.scala + + s"$_" +// ^ string.quoted.double.interpolated.scala punctuation.definition.string.begin.scala +// ^ source.scala meta.template.expression.scala punctuation.definition.template-expression.begin.scala +// ^ source.scala meta.template.expression.scala +// ^ string.quoted.double.interpolated.scala punctuation.definition.string.end.scala + + s"$$" +// ^ string.quoted.double.interpolated.scala punctuation.definition.string.begin.scala +// ^^ constant.character.escape.scala +// ^ string.quoted.double.interpolated.scala punctuation.definition.string.end.scala + + s"$"" +// ^ string.quoted.double.interpolated.scala punctuation.definition.string.begin.scala +// ^^ constant.character.escape.scala +// ^ string.quoted.double.interpolated.scala punctuation.definition.string.end.scala + + + s"$ // +// ^ string.quoted.double.interpolated.scala punctuation.definition.string.begin.scala +// ^ invalid.illegal.unrecognized-string-escape.scala +// ^^ comment.line.double-slash.scala punctuation.definition.comment.scala + + s"$+ +// ^ string.quoted.double.interpolated.scala punctuation.definition.string.begin.scala +// ^ invalid.illegal.unrecognized-string-escape.scala +// ^ keyword.operator.arithmetic.scala + + s"$; val a = +// ^ string.quoted.double.interpolated.scala punctuation.definition.string.begin.scala +// ^ invalid.illegal.unrecognized-string-escape.scala +// ^^^^^^^^^^ -string.quoted.double.interpolated.scala +// ^^^ keyword.declaration.stable.scala