|
|
@@ -0,0 +1,156 @@ |
|
|
/++ |
|
|
This module provides definitions to support D's |
|
|
interpolated expression sequence literal, sometimes |
|
|
called string interpolation. |
|
|
|
|
|
|
|
|
--- |
|
|
string str; |
|
|
int num; |
|
|
// the compiler uses this module to implement the |
|
|
// i"..." literal used here. |
|
|
auto a = i"$​(str) has $​(num) items."; |
|
|
--- |
|
|
|
|
|
The variable `a` is a sequence of expressions: |
|
|
|
|
|
--- |
|
|
a[0] == InterpolationHeader() |
|
|
a[$-1] == InterpolationFooter() |
|
|
--- |
|
|
|
|
|
First and last, you see the header and footer, to |
|
|
clearly indicate where interpolation begins and ends. |
|
|
Note that there may be nested interpolated sequences too, |
|
|
each with their own header and footer. Think of them |
|
|
as a set of balanced parenthesis around the contents. |
|
|
|
|
|
Inside, you will find three general categories of |
|
|
content: `InterpolatedLiteral!"string"` for string |
|
|
expressions, `InterpolatedExpression!"code"` for code |
|
|
expressions, and then the values themselves as their |
|
|
own type. |
|
|
|
|
|
In the example: |
|
|
--- |
|
|
auto a = i"$​(str) has $​(num) items."; |
|
|
--- |
|
|
|
|
|
We will find: |
|
|
--- |
|
|
a[0] == InterpolationHeader() |
|
|
a[1] == InterpolatedExpression!"str" |
|
|
a[2] == str |
|
|
a[3] == InterpolatedLiteral!" has "; |
|
|
a[4] == InterpolatedExpression!"num"; |
|
|
a[5] == num |
|
|
a[6] == InterpolatedLiteral!" items."; |
|
|
a[7] == InterpolationFooter() |
|
|
a.length == 8; |
|
|
--- |
|
|
|
|
|
You can see the correspondence with the original |
|
|
input: when you write `$​(expression)`, the string of the |
|
|
expression is passed as `InterpolatedExpression!ThatString`, |
|
|
(excluding any parenthesis around the expression), |
|
|
and everything else is passed as `InterpolatedLiteral!str`, |
|
|
in the same sequence as they appeared in the source. |
|
|
|
|
|
After an `InterpolatedExpression!...`, you will find the |
|
|
actual value(s) in the tuple. (If the expression expanded |
|
|
to multiple values - for example, if it was itself a tuple, |
|
|
there will be multiple values for a single expression.) |
|
|
|
|
|
Library functions should NOT attempt to mixin the code |
|
|
from an `InterpolatedExpression` themselves. Doing so |
|
|
will fail, since it is coming from a different scope anyway. |
|
|
The string is provided to you only for informational purposes |
|
|
and as a sentinel to separate things the user wrote. |
|
|
|
|
|
Your code should be able to handle an empty code string |
|
|
in `InterpolatedExpression` or even an entirely missing |
|
|
`InterpolatedExpression`, in case an implementation decides to |
|
|
not emit these. |
|
|
|
|
|
The `toString` members on these return `null`, except for |
|
|
the `InterpolatedLiteral`, which returns the literal string. |
|
|
This is to ease processing by generic functions like |
|
|
`std.stdio.write` or `std.conv.text`, making them effectively |
|
|
transparently skipped. |
|
|
|
|
|
To extract the string from an `InterpolatedLiteral`, you can |
|
|
use an `is` expression or the `.toString` method. |
|
|
|
|
|
To extract the string from a `InterpolatedExpression`, you can |
|
|
use an `is` expression or the `.expression` member. |
|
|
|
|
|
None of these structures have runtime state. |
|
|
|
|
|
History: |
|
|
Added in dmd 2.10x frontend, released in late 2023. |
|
|
+/ |
|
|
module core.interpolation; |
|
|
|
|
|
/++ |
|
|
Sentinel values to indicate the beginning and end of an |
|
|
interpolated expression sequence. |
|
|
|
|
|
Note that these can nest, so while processing a sequence, |
|
|
it may be helpful to keep a nesting count if that knowledge |
|
|
is important to your application. |
|
|
+/ |
|
|
struct InterpolationHeader { |
|
|
/++ |
|
|
Returns `null` for easy compatibility with existing functions |
|
|
like `std.stdio.writeln` and `std.conv.text`. |
|
|
+/ |
|
|
string toString() const @nogc pure nothrow @safe { |
|
|
return null; |
|
|
} |
|
|
} |
|
|
|
|
|
/// ditto |
|
|
struct InterpolationFooter { |
|
|
/++ |
|
|
Returns `null` for easy compatibility with existing functions |
|
|
like `std.stdio.writeln` and `std.conv.text`. |
|
|
+/ |
|
|
string toString() const @nogc pure nothrow @safe { |
|
|
return null; |
|
|
} |
|
|
} |
|
|
|
|
|
/++ |
|
|
Represents a fragment of a string literal in between expressions |
|
|
passed as part of an interpolated expression sequence. |
|
|
+/ |
|
|
struct InterpolatedLiteral(string text) { |
|
|
/++ |
|
|
Returns the text of the interpolated string literal for this |
|
|
segment of the tuple, for easy access and compatibility with |
|
|
existing functions like `std.stdio.writeln` and `std.conv.text`. |
|
|
+/ |
|
|
string toString() const @nogc pure nothrow @safe { |
|
|
return text; |
|
|
} |
|
|
} |
|
|
|
|
|
/++ |
|
|
Represents the source code of an expression passed as part of an |
|
|
interpolated expression sequence. |
|
|
+/ |
|
|
struct InterpolatedExpression(string text) { |
|
|
/++ |
|
|
Returns the text of an interpolated expression used in the |
|
|
original literal, if provided by the implementation. |
|
|
+/ |
|
|
enum expression = text; |
|
|
|
|
|
/++ |
|
|
Returns `null` for easy compatibility with existing functions |
|
|
like `std.stdio.writeln` and `std.conv.text`. |
|
|
+/ |
|
|
string toString() const @nogc pure nothrow @safe { |
|
|
return null; |
|
|
} |
|
|
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It is probably better to split this into two functions (with a bit of repetition) instead. Should help with compilation speed.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Do you have measurements of compilation speed difference?
Of course, such internal implementation details can be changed at any time.