diff --git a/astbuild/src/commonMain/kotlin/lang/temper/astbuild/Grammar.kt b/astbuild/src/commonMain/kotlin/lang/temper/astbuild/Grammar.kt
index 2bcd1ac7..81117efe 100644
--- a/astbuild/src/commonMain/kotlin/lang/temper/astbuild/Grammar.kt
+++ b/astbuild/src/commonMain/kotlin/lang/temper/astbuild/Grammar.kt
@@ -1811,7 +1811,7 @@ internal abstract class DomainSpecificLanguage {
val wordMatcher = Match(GrammarDoc.NonTerminal("Word"), emit = true) {
it.tokenType == TokenType.Word
}
- val delimiterMatcher = patternMatcher("^\"+|'$", emit = false)
+ val delimiterMatcher = patternMatcher("^\"+|['`]$", emit = false)
val litMatcher = Match(
GrammarDoc.NonTerminal("Number"),
emit = true,
diff --git a/astbuild/src/commonMain/kotlin/lang/temper/astbuild/GrammarDiagrams.kt b/astbuild/src/commonMain/kotlin/lang/temper/astbuild/GrammarDiagrams.kt
index 3edddc94..7170cab0 100644
--- a/astbuild/src/commonMain/kotlin/lang/temper/astbuild/GrammarDiagrams.kt
+++ b/astbuild/src/commonMain/kotlin/lang/temper/astbuild/GrammarDiagrams.kt
@@ -13,6 +13,22 @@ private val quotedStringGrammarDoc = GrammarDoc.Choice(
GrammarDoc.Terminal("\""),
),
),
+ // `...`
+ GrammarDoc.Sequence(
+ listOf(
+ GrammarDoc.Terminal("`"),
+ stringContentGrammar(sourceCharacterText = "SourceCharacter - ('\\n', '\\r', '\\', '`')"),
+ GrammarDoc.Terminal("`"),
+ ),
+ ),
+ // '...'
+ GrammarDoc.Sequence(
+ listOf(
+ GrammarDoc.Terminal("'"),
+ stringContentGrammar(sourceCharacterText = "SourceCharacter - ('\\n', '\\r', '\\', '\\'')"),
+ GrammarDoc.Terminal("'"),
+ ),
+ ),
// """...
GrammarDoc.Sequence(
listOf(
diff --git a/astbuild/src/commonTest/kotlin/lang/temper/astbuild/BuildTreeTest.kt b/astbuild/src/commonTest/kotlin/lang/temper/astbuild/BuildTreeTest.kt
index 6a30db88..94b85b79 100644
--- a/astbuild/src/commonTest/kotlin/lang/temper/astbuild/BuildTreeTest.kt
+++ b/astbuild/src/commonTest/kotlin/lang/temper/astbuild/BuildTreeTest.kt
@@ -1890,6 +1890,23 @@ class BuildTreeTest {
""",
)
+ @Test
+ fun taggedTemplateStringWithBackquotes() = assertAst(
+ input = $$"f`a${ b }`",
+ startProduction = "Expr",
+ wantJson = """
+ [ "Call", [
+ [ "Value", [ "stringExpr", "Function" ] ],
+ [ "RightName", "f" ],
+ [ "Value", [ true, "Boolean" ] ],
+ [ "Value", [ "a", "String" ] ],
+ [ "Value", [ "interpolate", "Symbol" ] ],
+ [ "RightName", "b" ],
+ ]
+ ]
+ """,
+ )
+
@Test
fun taggedTemplateStringWithStatementFragments() = assertAst(
input = $$"""
diff --git a/docs/for-users/.snippet-hashes.json b/docs/for-users/.snippet-hashes.json
index dc7e5524..96253f95 100644
--- a/docs/for-users/.snippet-hashes.json
+++ b/docs/for-users/.snippet-hashes.json
@@ -466,14 +466,14 @@
"build-user-docs/build/snippet/syntax/StmtBlock/snippet.js": "209DD7FC91CC53AB58A935DEB40D1B3A8439363E86DDF0EBC5C376619051A69C",
"build-user-docs/build/snippet/syntax/StmtBlock/snippet.md": "F758B71E7E310E302F97CE0C2765A0D71F0EC8DC930F6E2BE00A578D6F238C1B",
"build-user-docs/build/snippet/syntax/StmtBlock/snippet.svg": "FE48B62351417FE4F552AEDE3A742D504FC411FD54F0C6BD38C7D6529B482070",
- "build-user-docs/build/snippet/syntax/StringExpr/snippet.js": "F785AC5D9F918AA83A758731646509DD44659B0054E79021B84B38941D6E6189",
- "build-user-docs/build/snippet/syntax/StringExpr/snippet.md": "7D15C0D4170FE7BB2E1A5908F618C7B429833AD6469575B754276BB6323EDEE8",
+ "build-user-docs/build/snippet/syntax/StringExpr/snippet.js": "4770CDAAA87C6C36A07454C66FBBF8E3829E591AEB7AA0DFCFA2FAA17AAC98BF",
+ "build-user-docs/build/snippet/syntax/StringExpr/snippet.md": "78DF29E9563776F84A5F85FC2A1E38103842C31EAAF8826BFFFD5861D356AA39",
"build-user-docs/build/snippet/syntax/StringExpr/snippet.svg": "3670EC808C1342C3A7508470AA4AB8EAF89EB625446E3FED37F14FB76D074C24",
- "build-user-docs/build/snippet/syntax/StringGroup/snippet.js": "987C07471633DE9E46C2382FAD11E7735F98D0F05CA076D0A36AB105ECB94B76",
- "build-user-docs/build/snippet/syntax/StringGroup/snippet.md": "EE3A5FCD0275248E2BC93C90E435BD9B22589C10E7CF44D29291BD10CDB29A29",
+ "build-user-docs/build/snippet/syntax/StringGroup/snippet.js": "F304A1A5A3E01A44A77C3AC0AA61D9BC42E428990D3460AB5C29C9282FD1CBF3",
+ "build-user-docs/build/snippet/syntax/StringGroup/snippet.md": "F001EEFC8FE52D0406AE204B030F1A57B4DF6DBA64200BBE0C122634B022C70A",
"build-user-docs/build/snippet/syntax/StringGroup/snippet.svg": "23A0A3B8A6D2D84410D7AB46AD95376BC40C997F7DCBC697ABB53EB4B8DD7BCE",
- "build-user-docs/build/snippet/syntax/StringGroupTagged/snippet.js": "CD4027EB4CAA1303F07B4006EFC32A5E69188D8F514F95C2596FE459AFFDFB9C",
- "build-user-docs/build/snippet/syntax/StringGroupTagged/snippet.md": "4D017E9EA6DF71BA1190FA13433D6D956A540790A3ABF24625E1D69C09C92271",
+ "build-user-docs/build/snippet/syntax/StringGroupTagged/snippet.js": "751CC60F4215E3ECD44C792B38739A1FCED69529ED53CB353FDEEED19C380376",
+ "build-user-docs/build/snippet/syntax/StringGroupTagged/snippet.md": "0568E628A52CB9D0E58393FCC06A10625D73E55EA32662C0B8AAAE6FF6C423D8",
"build-user-docs/build/snippet/syntax/StringGroupTagged/snippet.svg": "161D42AAFCF4E830B79DFCABA7F7C00792D4494A313EBB8CCA96E6C10CF98275",
"build-user-docs/build/snippet/syntax/StringHole/snippet.js": "673292D00CD16C6B68A788046922FC86D5F49E6D2D37BA14855FE63DD58A1C85",
"build-user-docs/build/snippet/syntax/StringHole/snippet.md": "78EA49B02A3D91C64342B5E4D99B4217E202EAA7F0FDD033E937A8D11A03F54F",
diff --git a/docs/for-users/temper-docs/docs/reference/syntax.md b/docs/for-users/temper-docs/docs/reference/syntax.md
index 96b6bf7d..5fd6b596 100644
--- a/docs/for-users/temper-docs/docs/reference/syntax.md
+++ b/docs/for-users/temper-docs/docs/reference/syntax.md
@@ -452,7 +452,7 @@ Ruby-style block functions (`f { ... }`) and flow-control like
### Syntax for *StringExpr*
-
+
@@ -1457,7 +1457,7 @@ There are two kinds of match cases: run-time type checks that use keyword `is`,
#### Syntax for *StringGroup*
-
+
@@ -1467,7 +1467,7 @@ There are two kinds of match cases: run-time type checks that use keyword `is`,
#### Syntax for *StringGroupTagged*
-
+
diff --git a/docs/for-users/temper-docs/docs/reference/types.md b/docs/for-users/temper-docs/docs/reference/types.md
index d1b5201f..6463fe42 100644
--- a/docs/for-users/temper-docs/docs/reference/types.md
+++ b/docs/for-users/temper-docs/docs/reference/types.md
@@ -1590,7 +1590,7 @@ A *String* is a chunk of textual content.
-
+
diff --git a/docs/for-users/temper-docs/docs/snippet/syntax/StringExpr/snippet.svg b/docs/for-users/temper-docs/docs/snippet/syntax/StringExpr/snippet.svg
index 2f9ea7f2..9d68a1a3 100644
--- a/docs/for-users/temper-docs/docs/snippet/syntax/StringExpr/snippet.svg
+++ b/docs/for-users/temper-docs/docs/snippet/syntax/StringExpr/snippet.svg
@@ -1,4 +1,4 @@
-