From 6d3de7b28da85cd820f36965fc95115c290b7467 Mon Sep 17 00:00:00 2001 From: Nicolas Stucki Date: Fri, 29 Jan 2021 15:39:36 +0100 Subject: [PATCH 1/3] 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 From b28000b2aee00fb38f970cf21a3731739a26f041 Mon Sep 17 00:00:00 2001 From: Nicolas Stucki Date: Fri, 29 Jan 2021 15:57:08 +0100 Subject: [PATCH 2/3] Highlight illegal $ as end of string --- src/typescript/Scala.tmLanguage.ts | 14 ++++---------- tests/unit/#183.test.scala | 2 +- tests/unit/#195.test.scala | 6 +++--- 3 files changed, 8 insertions(+), 14 deletions(-) diff --git a/src/typescript/Scala.tmLanguage.ts b/src/typescript/Scala.tmLanguage.ts index 5e94b3b..c22b96c 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: `(")|(\\$(?=[^\\$"_{${letterChars}]))`, + end: `"|\\$(?=[^\\$"_{${letterChars}])`, beginCaptures: { '1': { name: 'keyword.interpolation.scala' @@ -441,17 +441,14 @@ export const scalaTmLanguage: TmLanguage = { } ], endCaptures: { - '1': { + '0': { name: 'string.quoted.double.interpolated.scala punctuation.definition.string.end.scala' - }, - '2': { - name: 'invalid.illegal.unrecognized-string-escape.scala' } } }, { begin: `\\b(${alphaId})(")`, - end: `(")|(\\$(?=[^\\$"_{${letterChars}]))`, + end: `"|\\$(?=[^\\$"_{${letterChars}])`, beginCaptures: { '1': { name: 'keyword.interpolation.scala' @@ -482,11 +479,8 @@ export const scalaTmLanguage: TmLanguage = { } ], endCaptures: { - '1': { + '0': { 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 6b0d29a..2952e57 100644 --- a/tests/unit/#183.test.scala +++ b/tests/unit/#183.test.scala @@ -78,4 +78,4 @@ raw"$ // ^^^ source.scala keyword.interpolation.scala // ^ string.quoted.double.interpolated.scala punctuation.definition.string.begin.scala -// ^ invalid.illegal.unrecognized-string-escape.scala +// ^ string.quoted.double.interpolated.scala punctuation.definition.string.end.scala diff --git a/tests/unit/#195.test.scala b/tests/unit/#195.test.scala index 4c9a185..56d302f 100644 --- a/tests/unit/#195.test.scala +++ b/tests/unit/#195.test.scala @@ -32,16 +32,16 @@ s"$ // // ^ string.quoted.double.interpolated.scala punctuation.definition.string.begin.scala -// ^ invalid.illegal.unrecognized-string-escape.scala +// ^ string.quoted.double.interpolated.scala punctuation.definition.string.end.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 +// ^ string.quoted.double.interpolated.scala punctuation.definition.string.end.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 punctuation.definition.string.end.scala // ^^^^^^^^^^ -string.quoted.double.interpolated.scala // ^^^ keyword.declaration.stable.scala From e72b4c95debc2c38e509a7e9ee360de69245e8dd Mon Sep 17 00:00:00 2001 From: Nicolas Stucki Date: Fri, 5 Feb 2021 15:47:57 +0100 Subject: [PATCH 3/3] Improve highlighting strategy for illegal $ Also fix missing rules for `"""` and `raw` --- src/typescript/Scala.tmLanguage.ts | 28 ++++++++++++----- tests/unit/#183.test.scala | 2 +- tests/unit/#195.test.scala | 49 +++++++++++++++++++++++++----- 3 files changed, 63 insertions(+), 16 deletions(-) diff --git a/src/typescript/Scala.tmLanguage.ts b/src/typescript/Scala.tmLanguage.ts index c22b96c..7300246 100644 --- a/src/typescript/Scala.tmLanguage.ts +++ b/src/typescript/Scala.tmLanguage.ts @@ -333,7 +333,7 @@ export const scalaTmLanguage: TmLanguage = { }, { begin: `\\b(raw)(""")`, - end: '"""(?!")', + end: `(""")(?!")|\\$\n|(\\$[^\\$"_{${letterChars}])`, beginCaptures: { '1': { name: 'keyword.interpolation.scala' @@ -356,14 +356,17 @@ export const scalaTmLanguage: TmLanguage = { } ], endCaptures: { - '0': { + '1': { name: 'string.quoted.triple.interpolated.scala punctuation.definition.string.end.scala' + }, + '2': { + name: 'invalid.illegal.unrecognized-string-escape.scala' } } }, { begin: `\\b(${alphaId})(""")`, - end: '"""(?!")', + end: `(""")(?!")|\\$\n|(\\$[^\\$"_{${letterChars}])`, beginCaptures: { '1': { name: 'keyword.interpolation.scala' @@ -386,8 +389,11 @@ export const scalaTmLanguage: TmLanguage = { } ], endCaptures: { - '0': { + '1': { name: 'string.quoted.triple.interpolated.scala punctuation.definition.string.end.scala' + }, + '2': { + name: 'invalid.illegal.unrecognized-string-escape.scala' } } }, @@ -418,7 +424,7 @@ export const scalaTmLanguage: TmLanguage = { }, { begin: `\\b(raw)(")`, - end: `"|\\$(?=[^\\$"_{${letterChars}])`, + end: `(")|\\$\n|(\\$[^\\$"_{${letterChars}])`, beginCaptures: { '1': { name: 'keyword.interpolation.scala' @@ -441,14 +447,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: `"|\\$(?=[^\\$"_{${letterChars}])`, + end: `(")|\\$\n|(\\$[^\\$"_{${letterChars}])`, beginCaptures: { '1': { name: 'keyword.interpolation.scala' @@ -479,8 +488,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 2952e57..9592cc8 100644 --- a/tests/unit/#183.test.scala +++ b/tests/unit/#183.test.scala @@ -78,4 +78,4 @@ raw"$ // ^^^ source.scala keyword.interpolation.scala // ^ string.quoted.double.interpolated.scala punctuation.definition.string.begin.scala -// ^ string.quoted.double.interpolated.scala punctuation.definition.string.end.scala +// ^ - string.quoted.double.interpolated.scala punctuation.definition.string.end.scala diff --git a/tests/unit/#195.test.scala b/tests/unit/#195.test.scala index 56d302f..b8200c0 100644 --- a/tests/unit/#195.test.scala +++ b/tests/unit/#195.test.scala @@ -30,18 +30,53 @@ // ^ string.quoted.double.interpolated.scala punctuation.definition.string.end.scala + s"$ +// ^ string.quoted.double.interpolated.scala punctuation.definition.string.begin.scala +// ^ - string.quoted.double.interpolated.scala punctuation.definition.string.end.scala +// ^ - constant.character.escape.scala + + s"$ // // ^ string.quoted.double.interpolated.scala punctuation.definition.string.begin.scala -// ^ string.quoted.double.interpolated.scala punctuation.definition.string.end.scala -// ^^ comment.line.double-slash.scala punctuation.definition.comment.scala +// ^^ invalid.illegal.unrecognized-string-escape.scala - s"$+ + s"$++ // ^ string.quoted.double.interpolated.scala punctuation.definition.string.begin.scala -// ^ string.quoted.double.interpolated.scala punctuation.definition.string.end.scala -// ^ keyword.operator.arithmetic.scala +// ^^ invalid.illegal.unrecognized-string-escape.scala +// ^ keyword.operator.arithmetic.scala s"$; val a = // ^ string.quoted.double.interpolated.scala punctuation.definition.string.begin.scala -// ^ string.quoted.double.interpolated.scala punctuation.definition.string.end.scala -// ^^^^^^^^^^ -string.quoted.double.interpolated.scala +// ^^ invalid.illegal.unrecognized-string-escape.scala +// ^^^^^^^^ -string.quoted.double.interpolated.scala // ^^^ keyword.declaration.stable.scala + + raw"$ +// ^^^ source.scala keyword.interpolation.scala +// ^ string.quoted.double.interpolated.scala punctuation.definition.string.begin.scala +// ^ - string.quoted.double.interpolated.scala invalid.illegal.unrecognized-string-escape.scala + + raw"$4 +// ^^^ source.scala keyword.interpolation.scala +// ^ string.quoted.double.interpolated.scala punctuation.definition.string.begin.scala +// ^^ invalid.illegal.unrecognized-string-escape.scala + + raw"""$ +// ^^^ source.scala keyword.interpolation.scala +// ^^^ string.quoted.triple.interpolated.scala punctuation.definition.string.begin.scala +// ^ - string.quoted.triple.interpolated.scala invalid.illegal.unrecognized-string-escape.scala + + raw"""$8 +// ^^^ source.scala keyword.interpolation.scala +// ^^^ string.quoted.triple.interpolated.scala punctuation.definition.string.begin.scala +// ^^ invalid.illegal.unrecognized-string-escape.scala + + s"""$ +// ^ source.scala keyword.interpolation.scala +// ^^^ string.quoted.triple.interpolated.scala punctuation.definition.string.begin.scala +// ^ - string.quoted.triple.interpolated.scala invalid.illegal.unrecognized-string-escape.scala + + s"""$8 +// ^ source.scala keyword.interpolation.scala +// ^^^ string.quoted.triple.interpolated.scala punctuation.definition.string.begin.scala +// ^^ invalid.illegal.unrecognized-string-escape.scala