1 /++ 2 This module provides definitions to support D's 3 interpolated expression sequence literal, sometimes 4 called string interpolation. 5 6 7 --- 8 string str; 9 int num; 10 // the compiler uses this module to implement the 11 // i"..." literal used here. 12 auto a = i"$(str) has $(num) items."; 13 --- 14 15 The variable `a` is a sequence of expressions: 16 17 --- 18 a[0] == InterpolationHeader() 19 a[$-1] == InterpolationFooter() 20 --- 21 22 First and last, you see the header and footer, to 23 clearly indicate where interpolation begins and ends. 24 Note that there may be nested interpolated sequences too, 25 each with their own header and footer. Think of them 26 as a set of balanced parenthesis around the contents. 27 28 Inside, you will find three general categories of 29 content: `InterpolatedLiteral!"string"` for string 30 expressions, `InterpolatedExpression!"code"` for code 31 expressions, and then the values themselves as their 32 own type. 33 34 In the example: 35 --- 36 auto a = i"$(str) has $(num) items."; 37 --- 38 39 We will find: 40 --- 41 a[0] == InterpolationHeader() 42 a[1] == InterpolatedExpression!"str" 43 a[2] == str 44 a[3] == InterpolatedLiteral!" has "; 45 a[4] == InterpolatedExpression!"num"; 46 a[5] == num 47 a[6] == InterpolatedLiteral!" items."; 48 a[7] == InterpolationFooter() 49 a.length == 8; 50 --- 51 52 You can see the correspondence with the original 53 input: when you write `$(expression)`, the string of the 54 expression is passed as `InterpolatedExpression!ThatString`, 55 (excluding any parenthesis around the expression), 56 and everything else is passed as `InterpolatedLiteral!str`, 57 in the same sequence as they appeared in the source. 58 59 After an `InterpolatedExpression!...`, you will find the 60 actual value(s) in the tuple. (If the expression expanded 61 to multiple values - for example, if it was itself a tuple, 62 there will be multiple values for a single expression.) 63 64 Library functions should NOT attempt to mixin the code 65 from an `InterpolatedExpression` themselves. Doing so 66 will fail, since it is coming from a different scope anyway. 67 The string is provided to you only for informational purposes 68 and as a sentinel to separate things the user wrote. 69 70 Your code should be able to handle an empty code string 71 in `InterpolatedExpression` or even an entirely missing 72 `InterpolatedExpression`, in case an implementation decides to 73 not emit these. 74 75 The `toString` members on these return `null`, except for 76 the `InterpolatedLiteral`, which returns the literal string. 77 This is to ease processing by generic functions like 78 `std.stdio.write` or `std.conv.text`, making them effectively 79 transparently skipped. 80 81 To extract the string from an `InterpolatedLiteral`, you can 82 use an `is` expression or the `.toString` method. 83 84 To extract the string from a `InterpolatedExpression`, you can 85 use an `is` expression or the `.expression` member. 86 87 None of these structures have runtime state. 88 89 History: 90 Added in dmd 2.10x frontend, released in late 2023. 91 +/ 92 module core.interpolation; 93 94 /++ 95 Common implementation for returning an empty string, to avoid storing 96 multiple versions of the same function based on templated types below. 97 +/ 98 public string __getEmptyString() @nogc pure nothrow @safe { 99 return ""; 100 } 101 102 /++ 103 Sentinel values to indicate the beginning and end of an 104 interpolated expression sequence. 105 106 Note that these can nest, so while processing a sequence, 107 it may be helpful to keep a nesting count if that knowledge 108 is important to your application. 109 +/ 110 struct InterpolationHeader { 111 /++ 112 Returns `null` for easy compatibility with existing functions 113 like `std.stdio.writeln` and `std.conv.text`. 114 +/ 115 alias toString = __getEmptyString; 116 } 117 118 /// ditto 119 struct InterpolationFooter { 120 /++ 121 Returns `null` for easy compatibility with existing functions 122 like `std.stdio.writeln` and `std.conv.text`. 123 +/ 124 alias toString = __getEmptyString; 125 } 126 127 /++ 128 Represents a fragment of a string literal in between expressions 129 passed as part of an interpolated expression sequence. 130 +/ 131 struct InterpolatedLiteral(string text) { 132 /++ 133 Returns the text of the interpolated string literal for this 134 segment of the tuple, for easy access and compatibility with 135 existing functions like `std.stdio.writeln` and `std.conv.text`. 136 +/ 137 static string toString() @nogc pure nothrow @safe { 138 return text; 139 } 140 } 141 142 /++ 143 Represents the source code of an expression passed as part of an 144 interpolated expression sequence. 145 +/ 146 struct InterpolatedExpression(string text) { 147 /++ 148 Returns the text of an interpolated expression used in the 149 original literal, if provided by the implementation. 150 +/ 151 enum expression = text; 152 153 /++ 154 Returns `null` for easy compatibility with existing functions 155 like `std.stdio.writeln` and `std.conv.text`. 156 +/ 157 alias toString = __getEmptyString; 158 }