Phase 7d: string interpolation text {expr} text
The readable way to build strings, as you noted `{a} {b}` beats `a + " " + b`.
A backtick string embeds any expression in `{…}` and desugars to the Phase-7c
`+` chain, wrapping each hole in `str(...)`:
`hello {name}, n={count + 1}`
== "hello " + name + ", n=" + str(count + 1)
- Lexer: a backtick captures its content raw as TK_INTERP.
- Parser: parse_interp splits literal runs from `{…}` holes (brace-depth aware,
`{{`/`}}` escape to literal braces), re-lexes each hole as a full expression
(save/restore toks/pi like an import), and folds it all into E_BIN(+) nodes —
so no new AST or runtime beyond the existing concat.
- str(x): a string passes through; int/bool/fixed convert via a small emitted
@fn_int_str prelude (digits from the end of a buffer, '-' for negatives),
emitted once into any program that uses it.
examples/strings.ludic gains interpolation cases (now prints 1..7); the smoke
covers it. Grammar + ludic_syntax.h tokenize backtick strings (holes highlighted
as embedded code). LANGUAGE.md documents it as the preferred form.
Reseeded (22530 lines); C-free fixpoint holds; goldens identical; 18/18; vocab +
doc-fences clean.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
parent
a997e34b2d
commit
ad63f09d53
13 changed files with 4748 additions and 3962 deletions
|
|
@ -37,6 +37,17 @@
|
|||
{
|
||||
"name": "string.quoted.single.ludic",
|
||||
"match": "'(\\\\.|[^'\\\\])'"
|
||||
},
|
||||
{
|
||||
"name": "string.interpolated.ludic",
|
||||
"begin": "`",
|
||||
"end": "`",
|
||||
"beginCaptures": { "0": { "name": "punctuation.definition.string.begin.ludic" } },
|
||||
"endCaptures": { "0": { "name": "punctuation.definition.string.end.ludic" } },
|
||||
"patterns": [
|
||||
{ "name": "meta.embedded.ludic", "begin": "\\{", "end": "\\}", "patterns": [{ "include": "$self" }] },
|
||||
{ "name": "constant.character.escape.ludic", "match": "\\\\." }
|
||||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
|
|
|
|||
|
|
@ -37,6 +37,17 @@
|
|||
{
|
||||
"name": "string.quoted.single.ludic",
|
||||
"match": "'(\\\\.|[^'\\\\])'"
|
||||
},
|
||||
{
|
||||
"name": "string.interpolated.ludic",
|
||||
"begin": "`",
|
||||
"end": "`",
|
||||
"beginCaptures": { "0": { "name": "punctuation.definition.string.begin.ludic" } },
|
||||
"endCaptures": { "0": { "name": "punctuation.definition.string.end.ludic" } },
|
||||
"patterns": [
|
||||
{ "name": "meta.embedded.ludic", "begin": "\\{", "end": "\\}", "patterns": [{ "include": "$self" }] },
|
||||
{ "name": "constant.character.escape.ludic", "match": "\\\\." }
|
||||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
|
|
|
|||
|
|
@ -227,6 +227,12 @@ static void lud_lex(LLex* L, const char* src){
|
|||
if (src[i] == '"') i++; else bad = 1;
|
||||
ltok_push(L, LT_STR, s, i, line, bad); continue;
|
||||
}
|
||||
if (c == '`'){ /* `interpolated {expr}` string */
|
||||
int s = i; i++; int bad = 0;
|
||||
while (src[i] && src[i] != '`'){ if (src[i] == '\\' && src[i+1]) i += 2; else i++; }
|
||||
if (src[i] == '`') i++; else bad = 1;
|
||||
ltok_push(L, LT_STR, s, i, line, bad); continue;
|
||||
}
|
||||
if (c == '\''){
|
||||
int s = i; i++; int bad = 0;
|
||||
if (src[i] == '\\' && src[i+1]) i += 2; else if (src[i] && src[i] != '\n') i++;
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue