The OpenD Programming Language

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 }