Skip to content

Commit

Permalink
[D] Add support for interpolated strings
Browse files Browse the repository at this point in the history
Resolves #3988
  • Loading branch information
deathaxe committed Sep 24, 2024
1 parent 618577f commit f81fad7
Show file tree
Hide file tree
Showing 2 changed files with 168 additions and 12 deletions.
105 changes: 93 additions & 12 deletions D/D.sublime-syntax
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,7 @@ variables:
hex_exponent: '(?:[pP]{{exponent}})'

character_lookahead: (?=')
string_lookahead: '(?=`|[rxq]?"|q{)'
string_lookahead: '(?=i?`|[irxq]?"|i?q{)'

definitely_value_lookahead: '(?=!|~|\+|\-|\*|&|\bcast\b|\bdelete\b|\bnew\b|\bimport\b|\bis\b|\b__traits\b|\bfunction\b|\bdelegate\b|[0-9]|\[|\(|{{string_lookahead}}|\b({{language_constant}})\b|\b({{language_variable}})\b)'
definitely_declaration_lookahead: '(?=(?:{{name}}\.)*{{name}}(\s+|\s*\*+\s*|\**\[.*\]\s*){{name}}|\b({{type_qualifier}})\b)'
Expand Down Expand Up @@ -364,10 +364,22 @@ contexts:
1: punctuation.definition.string.end.d
2: storage.type.string.d
pop: true
- match: '{{escape_sequence}}'
scope: constant.character.escape.d
- match: \\.
scope: invalid.illegal.unknown-escape.d
- include: string-escapes
# Interpolated regular string
- match: (i)(")
captures:
1: storage.modifier.string.d
2: punctuation.definition.string.begin.d
set:
- meta_include_prototype: false
- meta_scope: meta.string.d string.quoted.double.d
- match: '(")({{string_postfix}})'
captures:
1: punctuation.definition.string.end.d
2: storage.type.string.d
pop: true
- include: string-interpolations
- include: string-escapes
# Wysiwyg string
- match: (r)(")
captures:
Expand All @@ -392,6 +404,20 @@ contexts:
1: punctuation.definition.string.end.d
2: storage.type.string.d
pop: true
# Interpolated alternate Wysiwyg string
- match: (i)(`)
captures:
1: storage.modifier.string.d
2: punctuation.definition.string.begin.d
set:
- meta_include_prototype: false
- meta_scope: meta.string.d string.quoted.double.raw.backtick.d
- match: '(`)({{string_postfix}})'
captures:
1: punctuation.definition.string.end.d
2: storage.type.string.d
pop: true
- include: string-interpolations
# Deprecated Hex string
- match: (x)(")
captures:
Expand Down Expand Up @@ -502,9 +528,71 @@ contexts:
scope: string.unquoted.embedded.d punctuation.definition.string.end.d
pop: true
- include: tokens-in
# Interpolated token string
- match: '(iq)({)'
captures:
1: storage.modifier.string.d
2: punctuation.definition.string.begin.d
scope: string.unquoted.embedded.d
set:
- meta_scope: meta.string.d
- match: '}'
scope: string.unquoted.embedded.d punctuation.definition.string.end.d
pop: true
- include: tokens-interpolated-in

string-escapes:
- match: '{{escape_sequence}}'
scope: constant.character.escape.d
- match: \\.
scope: invalid.illegal.unknown-escape.d

string-interpolations:
- match: \\\$
scope: constant.character.escape.d
- match: \$\(
scope: punctuation.section.interpolation.begin.d
push: string-interpolation-in

string-interpolation-in:
- clear_scopes: 1
- meta_include_prototype: false
- meta_scope: meta.interpolation.d
- match: \)
scope: punctuation.section.interpolation.end.d
pop: true
- match: (?=\S)
push: first-value

# Purely a set of un-verified tokens
tokens-interpolated-in:
- match: \{
scope: punctuation.section.braces.begin.d
push:
- match: \}
scope: punctuation.section.braces.end.d
pop: true
- include: tokens-interpolated-in
- match: \$\(
scope: punctuation.section.interpolation.begin.d
push:
# don't clear non-existing `string` scope
- meta_include_prototype: false
- meta_scope: meta.interpolation.d
- include: string-interpolation-in
- include: tokens-in-common

tokens-in:
- match: \{
scope: punctuation.section.braces.begin.d
push:
- match: \}
scope: punctuation.section.braces.end.d
pop: true
- include: tokens-in
- include: tokens-in-common

tokens-in-common:
- match: '\b({{keyword}})\b'
scope: keyword.d
- match: '\b({{basic_type}})\b'
Expand Down Expand Up @@ -533,13 +621,6 @@ contexts:
scope: punctuation.section.brackets.begin.d
- match: '\]'
scope: punctuation.section.brackets.end.d
- match: '\{'
scope: punctuation.section.braces.begin.d
push:
- match: '\}'
scope: punctuation.section.braces.end.d
pop: true
- include: tokens-in
- include: not-whitespace-illegal

attribute-specifier-in:
Expand Down
75 changes: 75 additions & 0 deletions D/tests/syntax_test_d.d
Original file line number Diff line number Diff line change
Expand Up @@ -54,11 +54,38 @@ auto wysiwyg = r"f// \n\";
// ^ punctuation.definition.string.begin.d
// ^^ - constant.character.escape.d
// ^ punctuation.definition.string.end.d

auto wysiwygAlt = `f//\n\`;
// ^^^^^^^^ meta.string.d string.quoted.double.raw.backtick.d
// ^ punctuation.definition.string.begin.d
// ^^ - constant.character.escape.d
// ^ punctuation.definition.string.end.d

auto wysiwygInter = i`string $(this.foo)\r\nescaped: \$(bar) func: $(this.baz())\r\n`;
// ^ storage.modifier.string.d
// ^^^^^^^^ meta.string.d string.quoted.double.raw.backtick.d
// ^^^^^^^^^^^ meta.string.d meta.interpolation.d
// ^^ punctuation.section.interpolation.begin.d
// ^^^^ variable.language.d
// ^ punctuation.accessor.dot.d
// ^^^ variable.other.d
// ^ punctuation.section.interpolation.end.d
// ^^^^^^^^^^^^^^^^^^^^^^^^^^^ meta.string.d string.quoted.double.raw.backtick.d
// ^^^^ - constant.character
// ^^ constant.character.escape.d
// ^^^^^^^^^^^^^ meta.string.d meta.interpolation.d
// ^^ punctuation.section.interpolation.begin.d
// ^^^^ variable.language.d
// ^ punctuation.accessor.dot.d
// ^^^ variable.function.d
// ^ punctuation.section.parens.begin.d
// ^ punctuation.section.parens.end.d
// ^ punctuation.section.interpolation.end.d
// ^^^^^ meta.string.d string.quoted.double.raw.backtick.d
// ^^^^ - constant.character
// ^ punctuation.definition.string.end.d
// ^ punctuation.terminator.d - meta.string

auto doubleQuoted = "c://\'\"\?\\\0\a\b\f\n\r\t\v\x0B\2\12\762\u0feb\Uabcdef98\"";
// ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ meta.string.d string.quoted.double.d
// ^ punctuation.definition.string.begin.d
Expand All @@ -76,6 +103,32 @@ auto invalidEscape4 = "\u12398";
// ^^^^^^^^^ meta.string.d string.quoted.double.d
// ^^^^^^ constant.character.escape.d
// ^ - constant.character.escape.d

auto interpolated = i"string $(this.foo)\r\nescaped: \$(bar) func: $(this.baz())\r\n";
// ^ storage.modifier.string.d
// ^^^^^^^^ meta.string.d string.quoted.double.d
// ^^^^^^^^^^^ meta.string.d meta.interpolation.d
// ^^ punctuation.section.interpolation.begin.d
// ^^^^ variable.language.d
// ^ punctuation.accessor.dot.d
// ^^^ variable.other.d
// ^ punctuation.section.interpolation.end.d
// ^^^^^^^^^^^^^^^^^^^^^^^^^^^ meta.string.d string.quoted.double.d
// ^^^^ constant.character.escape.d
// ^^ constant.character.escape.d
// ^^^^^^^^^^^^^ meta.string.d meta.interpolation.d
// ^^ punctuation.section.interpolation.begin.d
// ^^^^ variable.language.d
// ^ punctuation.accessor.dot.d
// ^^^ variable.function.d
// ^ punctuation.section.parens.begin.d
// ^ punctuation.section.parens.end.d
// ^ punctuation.section.interpolation.end.d
// ^^^^^ meta.string.d string.quoted.double.d
// ^^^^ constant.character.escape.d
// ^ punctuation.definition.string.end.d
// ^ punctuation.terminator.d - meta.string

auto hexString = x"00 ba
// ^^^^^^^^ meta.string.d string.quoted.double.raw.d
// ^ storage.modifier.string.d
Expand Down Expand Up @@ -200,6 +253,28 @@ auto tokenString = q{ if { () /*}*/ else /*{*/ } };
// ^ string.unquoted.embedded.d punctuation.definition.string.end.d
// ^ punctuation.terminator.d

auto interpolTokenStr = iq{ if $(this.var) { me = $(this.bar) } }
// ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ meta.string.d
// ^^ storage.modifier.string.d
// ^ punctuation.definition.string.begin.d
// ^^ keyword.d
// ^^^^^^^^^^^ meta.interpolation.d
// ^^ punctuation.section.interpolation.begin.d
// ^^^^ variable.language.d
// ^ punctuation.accessor.dot.d
// ^^^ variable.other.d
// ^ punctuation.section.interpolation.end.d
// ^ punctuation.section.braces.begin.d
// ^ keyword.operator.assignment.d
// ^^^^^^^^^^^ meta.interpolation.d
// ^^ punctuation.section.interpolation.begin.d
// ^^^^ variable.language.d
// ^ punctuation.accessor.dot.d
// ^^^ variable.other.d
// ^ punctuation.section.interpolation.end.d
// ^ punctuation.section.braces.end.d
// ^ punctuation.definition.string.end.d

auto c = 'a';
// ^^^ meta.string.d string.quoted.single.d
c = 'Ó';
Expand Down

0 comments on commit f81fad7

Please sign in to comment.