1
- import " package:angular/src/facade/exceptions.dart" show BaseException;
1
+ import ' package:angular/src/facade/exceptions.dart' show BaseException;
2
2
3
3
import '../chars.dart' ;
4
4
import '../expression_parser/ast.dart' as compiler_ast;
@@ -24,24 +24,39 @@ abstract class NameResolver {
24
24
/// Returns variable declarations for all locals used in this scope.
25
25
List <o.Statement > getLocalDeclarations ();
26
26
27
- o.Expression createLiteralList (List <o.Expression > values);
27
+ /// Creates a closure that returns a list of [type] when [values] change.
28
+ o.Expression createLiteralList (
29
+ List <o.Expression > values, {
30
+ o.OutputType type,
31
+ });
32
+
33
+ /// Creates a closure that returns a map of [type] when [values] change.
28
34
o.Expression createLiteralMap (
29
- List <List <dynamic /* String | o . Expression */ >> values);
35
+ List <List <dynamic /* String | o.Expression */ >> values, {
36
+ o.OutputType type,
37
+ });
38
+
30
39
int createUniqueBindIndex ();
31
40
32
41
/// Creates a name resolver with shared state for use in a new method scope.
33
42
NameResolver scope ();
34
43
}
35
44
45
+ /// Converts a bound [AST] expression to an [Expression] .
46
+ ///
47
+ /// If non-null, [boundType] is the type of the input to which [expression] is
48
+ /// bound. This is used to support empty expressions for boolean inputs, and to
49
+ /// type annotate collection literal bindings.
36
50
o.Expression convertCdExpressionToIr (
37
- NameResolver nameResolver,
38
- o.Expression implicitReceiver,
39
- compiler_ast.AST expression,
40
- bool preserveWhitespace,
41
- bool emptyIsTrue) {
51
+ NameResolver nameResolver,
52
+ o.Expression implicitReceiver,
53
+ compiler_ast.AST expression,
54
+ bool preserveWhitespace,
55
+ o.OutputType boundType,
56
+ ) {
42
57
assert (nameResolver != null );
43
58
var visitor = new _AstToIrVisitor (
44
- nameResolver, implicitReceiver, preserveWhitespace, emptyIsTrue );
59
+ nameResolver, implicitReceiver, preserveWhitespace, boundType );
45
60
return expression.visit (visitor, _Mode .Expression );
46
61
}
47
62
@@ -52,7 +67,7 @@ List<o.Statement> convertCdStatementToIr(
52
67
bool preserveWhitespace) {
53
68
assert (nameResolver != null );
54
69
var visitor = new _AstToIrVisitor (
55
- nameResolver, implicitReceiver, preserveWhitespace, false );
70
+ nameResolver, implicitReceiver, preserveWhitespace, null );
56
71
var statements = < o.Statement > [];
57
72
flattenStatements (stmt.visit (visitor, _Mode .Statement ), statements);
58
73
return statements;
@@ -84,19 +99,32 @@ dynamic /* o . Expression | o . Statement */ convertToStatementIfNeeded(
84
99
class _AstToIrVisitor implements compiler_ast.AstVisitor {
85
100
final NameResolver _nameResolver;
86
101
final o.Expression _implicitReceiver;
87
- final bool preserveWhitespace;
88
- final bool emptyIsTrue;
102
+ final bool _preserveWhitespace;
103
+
104
+ /// The type to which this expression is bound.
105
+ ///
106
+ /// This is used to support empty expressions for booleans bindings, and type
107
+ /// pure proxy fields for collection literals.
108
+ final o.OutputType _boundType;
109
+
110
+ /// Whether the current AST is the root of the expression.
111
+ ///
112
+ /// This is used to indicate whether [_boundType] can be used to type pure
113
+ /// proxy fields for collection literals.
114
+ bool _visitingRoot;
89
115
90
116
_AstToIrVisitor (
91
117
this ._nameResolver,
92
118
this ._implicitReceiver,
93
- this .preserveWhitespace,
94
- this .emptyIsTrue,
95
- ) {
119
+ this ._preserveWhitespace,
120
+ this ._boundType,
121
+ )
122
+ : _visitingRoot = true {
96
123
assert (_nameResolver != null );
97
124
}
98
125
99
126
dynamic visitBinary (compiler_ast.Binary ast, dynamic context) {
127
+ _visitingRoot = false ;
100
128
_Mode mode = context;
101
129
var op;
102
130
switch (ast.operation) {
@@ -155,12 +183,14 @@ class _AstToIrVisitor implements compiler_ast.AstVisitor {
155
183
}
156
184
157
185
dynamic visitChain (compiler_ast.Chain ast, dynamic context) {
186
+ _visitingRoot = false ;
158
187
_Mode mode = context;
159
188
ensureStatementMode (mode, ast);
160
189
return visitAll (ast.expressions as List <compiler_ast.AST >, mode);
161
190
}
162
191
163
192
dynamic visitConditional (compiler_ast.Conditional ast, dynamic context) {
193
+ _visitingRoot = false ;
164
194
_Mode mode = context;
165
195
o.Expression value = ast.condition.visit (this , _Mode .Expression );
166
196
return convertToStatementIfNeeded (
@@ -171,13 +201,14 @@ class _AstToIrVisitor implements compiler_ast.AstVisitor {
171
201
172
202
dynamic visitEmptyExpr (compiler_ast.EmptyExpr ast, dynamic context) {
173
203
_Mode mode = context;
174
- o. LiteralExpr value = emptyIsTrue
204
+ final value = _isBoolType (_boundType)
175
205
? new o.LiteralExpr (true , o.BOOL_TYPE )
176
206
: new o.LiteralExpr ('' , o.STRING_TYPE );
177
207
return convertToStatementIfNeeded (mode, value);
178
208
}
179
209
180
210
dynamic visitPipe (compiler_ast.BindingPipe ast, dynamic context) {
211
+ _visitingRoot = false ;
181
212
_Mode mode = context;
182
213
var input = ast.exp.visit (this , _Mode .Expression );
183
214
var args = visitAll (ast.args as List <compiler_ast.AST >, _Mode .Expression )
@@ -187,6 +218,7 @@ class _AstToIrVisitor implements compiler_ast.AstVisitor {
187
218
}
188
219
189
220
dynamic visitFunctionCall (compiler_ast.FunctionCall ast, dynamic context) {
221
+ _visitingRoot = false ;
190
222
_Mode mode = context;
191
223
return convertToStatementIfNeeded (
192
224
mode,
@@ -195,6 +227,7 @@ class _AstToIrVisitor implements compiler_ast.AstVisitor {
195
227
}
196
228
197
229
dynamic visitIfNull (compiler_ast.IfNull ast, dynamic context) {
230
+ _visitingRoot = false ;
198
231
_Mode mode = context;
199
232
o.Expression value = ast.condition.visit (this , _Mode .Expression );
200
233
return convertToStatementIfNeeded (
@@ -203,6 +236,7 @@ class _AstToIrVisitor implements compiler_ast.AstVisitor {
203
236
204
237
dynamic visitImplicitReceiver (
205
238
compiler_ast.ImplicitReceiver ast, dynamic context) {
239
+ _visitingRoot = false ;
206
240
_Mode mode = context;
207
241
ensureExpressionMode (mode, ast);
208
242
return IMPLICIT_RECEIVER ;
@@ -211,7 +245,7 @@ class _AstToIrVisitor implements compiler_ast.AstVisitor {
211
245
/// Trim text in preserve whitespace mode if it contains \n preceding
212
246
/// interpolation.
213
247
String compressWhitespacePreceding (String value) {
214
- if (preserveWhitespace ||
248
+ if (_preserveWhitespace ||
215
249
value.contains ('\u 00A0' ) ||
216
250
value.contains (ngSpace) ||
217
251
! value.contains ('\n ' )) return replaceNgSpace (value);
@@ -221,14 +255,15 @@ class _AstToIrVisitor implements compiler_ast.AstVisitor {
221
255
/// Trim text in preserve whitespace mode if it contains \n following
222
256
/// interpolation.
223
257
String compressWhitespaceFollowing (String value) {
224
- if (preserveWhitespace ||
258
+ if (_preserveWhitespace ||
225
259
value.contains ('\u 00A0' ) ||
226
260
value.contains (ngSpace) ||
227
261
! value.contains ('\n ' )) return replaceNgSpace (value);
228
262
return replaceNgSpace (value.replaceAll ('\n ' , '' ).trimRight ());
229
263
}
230
264
231
265
dynamic visitInterpolation (compiler_ast.Interpolation ast, dynamic context) {
266
+ _visitingRoot = false ;
232
267
_Mode mode = context;
233
268
ensureExpressionMode (mode, ast);
234
269
@@ -267,6 +302,7 @@ class _AstToIrVisitor implements compiler_ast.AstVisitor {
267
302
}
268
303
269
304
dynamic visitKeyedRead (compiler_ast.KeyedRead ast, dynamic context) {
305
+ _visitingRoot = false ;
270
306
_Mode mode = context;
271
307
return convertToStatementIfNeeded (
272
308
mode,
@@ -276,6 +312,7 @@ class _AstToIrVisitor implements compiler_ast.AstVisitor {
276
312
}
277
313
278
314
dynamic visitKeyedWrite (compiler_ast.KeyedWrite ast, dynamic context) {
315
+ _visitingRoot = false ;
279
316
_Mode mode = context;
280
317
o.Expression obj = ast.obj.visit (this , _Mode .Expression );
281
318
o.Expression key = ast.key.visit (this , _Mode .Expression );
@@ -284,31 +321,41 @@ class _AstToIrVisitor implements compiler_ast.AstVisitor {
284
321
}
285
322
286
323
dynamic visitLiteralArray (compiler_ast.LiteralArray ast, dynamic context) {
324
+ final isRootExpression = _visitingRoot;
325
+ _visitingRoot = false ;
287
326
_Mode mode = context;
288
327
return convertToStatementIfNeeded (
289
- mode,
290
- _nameResolver.createLiteralList (
291
- visitAll (ast.expressions as List <compiler_ast.AST >, mode)
292
- as List <o.Expression >));
328
+ mode,
329
+ _nameResolver.createLiteralList (
330
+ visitAll (ast.expressions as List <compiler_ast.AST >, mode)
331
+ as List <o.Expression >,
332
+ type: isRootExpression ? _boundType : null ),
333
+ );
293
334
}
294
335
295
336
dynamic visitLiteralMap (compiler_ast.LiteralMap ast, dynamic context) {
337
+ final isRootExpression = _visitingRoot;
338
+ _visitingRoot = false ;
296
339
_Mode mode = context;
297
340
var parts = < List > [];
298
341
for (var i = 0 ; i < ast.keys.length; i++ ) {
299
342
parts.add ([ast.keys[i], ast.values[i].visit (this , _Mode .Expression )]);
300
343
}
301
344
return convertToStatementIfNeeded (
302
- mode, _nameResolver.createLiteralMap (parts));
345
+ mode,
346
+ _nameResolver.createLiteralMap (parts,
347
+ type: isRootExpression ? _boundType : null ));
303
348
}
304
349
305
350
dynamic visitLiteralPrimitive (
306
351
compiler_ast.LiteralPrimitive ast, dynamic context) {
352
+ _visitingRoot = false ;
307
353
_Mode mode = context;
308
354
return convertToStatementIfNeeded (mode, o.literal (ast.value));
309
355
}
310
356
311
357
dynamic visitMethodCall (compiler_ast.MethodCall ast, dynamic context) {
358
+ _visitingRoot = false ;
312
359
_Mode mode = context;
313
360
var args = visitAll (ast.args as List <compiler_ast.AST >, _Mode .Expression )
314
361
as List <o.Expression >;
@@ -328,12 +375,14 @@ class _AstToIrVisitor implements compiler_ast.AstVisitor {
328
375
}
329
376
330
377
dynamic visitPrefixNot (compiler_ast.PrefixNot ast, dynamic context) {
378
+ _visitingRoot = false ;
331
379
_Mode mode = context;
332
380
return convertToStatementIfNeeded (
333
381
mode, o.not (ast.expression.visit (this , _Mode .Expression )));
334
382
}
335
383
336
384
dynamic visitPropertyRead (compiler_ast.PropertyRead ast, dynamic context) {
385
+ _visitingRoot = false ;
337
386
_Mode mode = context;
338
387
var result;
339
388
var receiver = ast.receiver.visit (this , _Mode .Expression );
@@ -348,6 +397,7 @@ class _AstToIrVisitor implements compiler_ast.AstVisitor {
348
397
}
349
398
350
399
dynamic visitPropertyWrite (compiler_ast.PropertyWrite ast, dynamic context) {
400
+ _visitingRoot = false ;
351
401
_Mode mode = context;
352
402
o.Expression receiver = ast.receiver.visit (this , _Mode .Expression );
353
403
if (identical (receiver, IMPLICIT_RECEIVER )) {
@@ -363,6 +413,7 @@ class _AstToIrVisitor implements compiler_ast.AstVisitor {
363
413
364
414
dynamic visitSafePropertyRead (
365
415
compiler_ast.SafePropertyRead ast, dynamic context) {
416
+ _visitingRoot = false ;
366
417
_Mode mode = context;
367
418
var receiver = ast.receiver.visit (this , _Mode .Expression );
368
419
return convertToStatementIfNeeded (mode,
@@ -371,6 +422,7 @@ class _AstToIrVisitor implements compiler_ast.AstVisitor {
371
422
372
423
dynamic visitSafeMethodCall (
373
424
compiler_ast.SafeMethodCall ast, dynamic context) {
425
+ _visitingRoot = false ;
374
426
_Mode mode = context;
375
427
var receiver = ast.receiver.visit (this , _Mode .Expression );
376
428
var args = visitAll (ast.args as List <compiler_ast.AST >, _Mode .Expression );
@@ -382,6 +434,7 @@ class _AstToIrVisitor implements compiler_ast.AstVisitor {
382
434
}
383
435
384
436
dynamic visitStaticRead (compiler_ast.StaticRead ast, dynamic context) {
437
+ _visitingRoot = false ;
385
438
_Mode mode = context;
386
439
return convertToStatementIfNeeded (
387
440
mode, o.importExpr (ast.id.identifier, isConst: true ));
@@ -402,3 +455,12 @@ void flattenStatements(dynamic arg, List<o.Statement> output) {
402
455
output.add (arg);
403
456
}
404
457
}
458
+
459
+ bool _isBoolType (o.OutputType type) {
460
+ if (type == o.BOOL_TYPE ) return true ;
461
+ if (type is o.ExternalType ) {
462
+ String name = type.value.name;
463
+ return 'bool' == name.trim ();
464
+ }
465
+ return false ;
466
+ }
0 commit comments