diff --git a/corpus/literals.txt b/corpus/literals.txt index 2e8ad65..6f28f07 100644 --- a/corpus/literals.txt +++ b/corpus/literals.txt @@ -38,6 +38,15 @@ val string3 = raw"Not a new line \n${ha}" val string4 = s""" works even in multiline strings, ${name} """ + +val string5 = s"$works${without}$spaces" + +val string6 = s"$a$b" + +val string7 = s"$$ $a" + +val string8 = s"$"$a" + -------------------------------------------------------------------------------- (compilation_unit @@ -73,7 +82,43 @@ works even in multiline strings, ${name} (interpolated_string (interpolation (block - (identifier))))))) + (identifier)))))) + (val_definition + (identifier) + (interpolated_string_expression + (identifier) + (interpolated_string + (interpolation + (identifier)) + (interpolation + (block + (identifier))) + (interpolation + (identifier))))) + (val_definition + (identifier) + (interpolated_string_expression + (identifier) + (interpolated_string + (interpolation + (identifier)) + (interpolation + (identifier))))) + (val_definition + (identifier) + (interpolated_string_expression + (identifier) + (interpolated_string + (interpolation + (identifier))))) + (val_definition + (identifier) + (interpolated_string_expression + (identifier) + (interpolated_string + (interpolation + (identifier)))))) + ================================================================================ Integer literals diff --git a/grammar.js b/grammar.js index e3b848f..f55bff3 100644 --- a/grammar.js +++ b/grammar.js @@ -1388,6 +1388,26 @@ module.exports = grammar({ _alpha_identifier: $ => /[\p{Lu}\p{Lt}\p{Nl}\p{Lo}\p{Lm}\$\p{Ll}_\u00AA\u00BB\u02B0-\u02B8\u02C0-\u02C1\u02E0-\u02E4\u037A\u1D78\u1D9B-\u1DBF\u2071\u207F\u2090-\u209C\u2C7C-\u2C7D\uA69C-\uA69D\uA770\uA7F8-\uA7F9\uAB5C-\uAB5F\$][\p{Lu}\p{Lt}\p{Nl}\p{Lo}\p{Lm}\$\p{Ll}_\u00AA\u00BB\u02B0-\u02B8\u02C0-\u02C1\u02E0-\u02E4\u037A\u1D78\u1D9B-\u1DBF\u2071\u207F\u2090-\u209C\u2C7C-\u2C7D\uA69C-\uA69D\uA770\uA7F8-\uA7F9\uAB5C-\uAB5F0-9\$_\p{Ll}]*(_[\-!#%&*+\/\\:<=>?@\u005e\u007c~\p{Sm}\p{So}]+)?/, + /** + * Despite what the lexical syntax suggests, the alphaid rule doesn't apply + * to identifiers that aren't in blocks in interpolated strings (e.g. $foo). + * A more accurate description is given in + * https://www.scala-lang.org/files/archive/spec/2.13/01-lexical-syntax.html + * where it states (regarding dollar sign escapes in interpolated strings) that + * """ + * The simpler form consists of a ‘$’-sign followed by an identifier starting + * with a letter and followed only by letters, digits, and underscore characters + * """ + * where "letters" does not include the $ character. + * + * This rule is similar to the _alpha_identifier rule, with the differences + * being that the $ character is excluded, along with the _(operator_chars) + * suffix and can be approximated as + * /[A-Za-z_][A-Z_a-z0-9]/; + */ + _interpolation_identifier: $ => + /[\p{Lu}\p{Lt}\p{Nl}\p{Lo}\p{Lm}\p{Ll}_\u00AA\u00BB\u02B0-\u02B8\u02C0-\u02C1\u02E0-\u02E4\u037A\u1D78\u1D9B-\u1DBF\u2071\u207F\u2090-\u209C\u2C7C-\u2C7D\uA69C-\uA69D\uA770\uA7F8-\uA7F9\uAB5C-\uAB5F][\p{Lu}\p{Lt}\p{Nl}\p{Lo}\p{Lm}\p{Ll}_\u00AA\u00BB\u02B0-\u02B8\u02C0-\u02C1\u02E0-\u02E4\u037A\u1D78\u1D9B-\u1DBF\u2071\u207F\u2090-\u209C\u2C7C-\u2C7D\uA69C-\uA69D\uA770\uA7F8-\uA7F9\uAB5C-\uAB5F0-9_\p{Ll}]*/, + _backquoted_id: $ => /`[^\n`]+`/, _identifier: $ => choice($.identifier, $.operator_identifier), @@ -1492,18 +1512,22 @@ module.exports = grammar({ _interpolated_multiline_string_start: $ => '"""', - interpolation: $ => seq("$", choice($.identifier, $.block)), + _dollar_escape: $ => seq('$', choice('$', '"')), + + _aliased_interpolation_identifier: $ => alias($._interpolation_identifier, $.identifier), + + interpolation: $ => seq("$", choice($._aliased_interpolation_identifier, $.block)), interpolated_string: $ => choice( seq( $._interpolated_string_start, - repeat(seq($._interpolated_string_middle, $.interpolation)), + repeat(seq($._interpolated_string_middle, choice($._dollar_escape, $.interpolation))), $._interpolated_string_end, ), seq( $._interpolated_multiline_string_start, - repeat(seq($._interpolated_multiline_string_middle, $.interpolation)), + repeat(seq($._interpolated_multiline_string_middle, choice($._dollar_escape, $.interpolation))), $._interpolated_multiline_string_end, ), ), diff --git a/queries/scala/locals.scm b/queries/scala/locals.scm index 8eaa75e..c5027b5 100644 --- a/queries/scala/locals.scm +++ b/queries/scala/locals.scm @@ -27,3 +27,4 @@ name: (identifier) @local.definition) (identifier) @local.reference + diff --git a/test/highlight/basics.scala b/test/highlight/basics.scala index c879c01..9c9f988 100644 --- a/test/highlight/basics.scala +++ b/test/highlight/basics.scala @@ -79,5 +79,16 @@ object Hello { // ^method val hello2 = c"some $meth" // ^method + val hello3 = s"$$$meth$hello2%" +// ^string +// ^punctuation.special +// ^method +// ^punctuation.special +// ^variable +// ^string + val hello4 = s"$"$hello3" +// ^string +// ^punctuation.special +// ^variable }