You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
The literal text parts are pulled out into one list. The interpolated
104
-
expressions are each wrapped in closures and put into a second list. Then these
105
-
are passed to a function whose name is based on the tag identifier. Wrapping
106
-
the interpolated expressions in closures gives the tag processor control over
107
-
when or if the expressions are evaluated.
108
+
expressions are put into a second list. Then these are passed to a function
109
+
whose name is based on the tag identifier.
108
110
109
111
Since the intent of this feature is brevity, we expect users to choose short tag
110
112
names like `expr` here, `html`, `css`, etc. Since those names are likely to
@@ -118,11 +120,11 @@ that looks something like:
118
120
```dart
119
121
Code exprStringLiteral(
120
122
List<String> strings,
121
-
List<Object? Function()) values) {
123
+
List<Object> values) {
122
124
var buffer = StringBuffer();
123
125
for (var i = 0; i < values.length; i++) {
124
126
buffer.write(strings[i]);
125
-
var value = values[i]();
127
+
var value = values[i];
126
128
if (value is Expression) {
127
129
buffer.write('(' + value.toSource() + ')');
128
130
} else {
@@ -135,7 +137,10 @@ Code exprStringLiteral(
135
137
}
136
138
```
137
139
138
-
Note that this toy implementation implicitly wraps values that are subexpressions in parentheses to avoid precedence errors. The interpolated expressions passed to a tag processor do not need to evaluate to strings. It's up to the processor to define which kinds of values are allowed.
140
+
Note that this toy implementation implicitly wraps values that are
141
+
subexpressions in parentheses to avoid precedence errors. The interpolated
142
+
expressions passed to a tag processor do not need to evaluate to strings. It's
143
+
up to the processor to define which kinds of values are allowed.
139
144
140
145
Note also that the tag handler does not have to *return* a string either. Here
141
146
it returns `Code`. While tag strings are based on Dart string literal syntax,
@@ -228,26 +233,65 @@ A tagged string is an identifier followed by a series of adjacent string
228
233
literals which may contain interpolated expressions. This is treated as
229
234
syntactic sugar for a function call with two list arguments.
230
235
231
-
### Desugaring
232
-
233
236
The tag identifier is suffixed with `StringLiteral` to determine the tag
234
237
processor name.
235
238
239
+
### Static typing
240
+
241
+
It is a compile-time error if:
242
+
243
+
* The tag processor name does not resolve to a function that can be called
244
+
with two positional arguments and no named arguments.
245
+
* `List<String>` cannot be assigned to the first parameter's type.
246
+
* `List<T>` cannot be assigned to the first parameter's type for some `T`.
247
+
This inferred `T` is called the *interpolated expression type*.
248
+
* Any interpolated expression in the string literal cannot be assigned to the
249
+
interpolated expression type.
250
+
251
+
The latter two rules mean that a tag processor can restrict the types of
252
+
expressions that are allowed in interpolation by specifying an element type on
253
+
the second parameter to the function. For example:
254
+
255
+
```dart
256
+
Expression exprStringLiteral(
257
+
List<String> strings,
258
+
List<Expression> values) {
259
+
var buffer = StringBuffer();
260
+
for (var i = 0; i < values.length; i++) {
261
+
buffer.write(strings[i]);
262
+
buffer.write('(' + values[i].toSource() + ')');
263
+
}
264
+
265
+
buffer.write(strings.last);
266
+
return Expression.parse(buffer.toString());
267
+
}
268
+
269
+
main() {
270
+
var identifier = expr "foo";
271
+
var add = expr "$identifier + $identifier"; // OK.
272
+
273
+
var notExpr = 123;
274
+
var subtract = expr "$identifier - $notExpr"; // <-- Error.
275
+
}
276
+
```
277
+
278
+
The marked line has a compile error because `notExpr` has type `int`, which
279
+
cannot be assigned to the expected interpolated expression type `Code.`
280
+
281
+
The type of a tagged string literal expression is the return type of the
282
+
corresponding tagged string literal function.
283
+
284
+
### Desugaring
285
+
236
286
Adjacent strings are implicitly concatenated into a single string as in current
237
287
Dart.
238
288
239
289
The string is split into string parts and interpolation expressions. All of the
240
290
string literal parts from the `SINGLE_LINE_*` and `MULTI_LINE_*` rules are
241
291
collected in order and put in an object that implements `List<String>`.
242
292
243
-
Each `expression` is wrapped in a closure of type `Object? Function()` that
244
-
evaluates and returns the expression when invoked. These closures are collected
245
-
in order into an object that implements `List<Object? Function()>`.
246
-
247
-
**TODO: What if an interpolated expression uses `await`? We could implicitly
248
-
make the function `async` in that case and require the template function to
249
-
handle a future result. Or we could make it a compile-time error like we do
250
-
when using `await` in the initializer of a `late` variable.**
293
+
Every `expression` from those rules is collected in order into an object that
294
+
implements `List<T>` where `T` is the interpolated expression type.
251
295
252
296
The structure of the grammar is such that the list of string parts will always
253
297
be one element longer than the list of expressions. If there are no expressions,
@@ -272,18 +316,6 @@ The tagged string literal is replaced with a call to the tag processor function.
272
316
The list of string parts and expressions (which may be empty) are passed to that
273
317
function as positional arguments.
274
318
275
-
### Static typing
276
-
277
-
It is a compile-time error if:
278
-
279
-
* The tag named suffixed with `StringLiteral` does not resolve to a function
280
-
that can be called with two positional arguments.
281
-
*`List<String>` cannot be assigned to the first parameter's type.
282
-
*`List<Object? Function()>` cannot be assigned to the first parameter's type.
283
-
284
-
The type of a tagged string literal expression is the return type of the
285
-
corresponding tagged string literal function.
286
-
287
319
## Runtime semantics
288
320
289
321
This feature is purely syntactic sugar, so there are no runtime semantics
0 commit comments