Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(74)

Side by Side Diff: lib/dartdoc/frog/analyze.dart

Issue 10696191: Frog removed from dartdoc. (Closed) Base URL: https://dart.googlecode.com/svn/branches/bleeding_edge/dart
Patch Set: Created 8 years, 5 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
« no previous file with comments | « no previous file | lib/dartdoc/frog/analyze_frame.dart » ('j') | tools/create_sdk.py » ('J')
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
(Empty)
1 // Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
2 // for details. All rights reserved. Use of this source code is governed by a
3 // BSD-style license that can be found in the LICENSE file.
4
5 /**
6 * A simple code analyzer for Dart.
7 *
8 * Currently used to ensure all concrete generic types are visited.
9 * Also performs all static type checks - so these don't need to be
10 * done in later phases.
11 *
12 * Ultimately, this should include abstract interpreter work. This will
13 * result in an interesting split beteen this class and MethodGenerator
14 * which should be turned into nothing more than a code generator.
15 */
16 // TODO(jimhug): This class shares too much code with MethodGenerator.
17 class MethodAnalyzer implements TreeVisitor {
18 MethodMember method;
19 Statement body;
20
21 CallFrame _frame;
22
23 /**
24 * Track whether or not [body] refers to any type parameters from the
25 * enclosing type to advise future code generation and analysis.
26 */
27 bool hasTypeParams = false;
28
29 MethodAnalyzer(this.method, this.body);
30
31 // TODO(jimhug): Type issue with requiring CallFrame here...
32 void analyze(CallFrame context) {
33 var thisValue;
34 // TODO(jimhug): Move Constructor analysis to here and below.
35
36 if (context != null) {
37 thisValue = context.thisValue;
38 } else {
39 thisValue = new PureStaticValue(method.declaringType, null);
40 }
41 var values = [];
42 for (var p in method.parameters) {
43 values.add(new PureStaticValue(p.type, null));
44 }
45 var args = new Arguments(null, values);
46
47 _frame = new CallFrame(this, method, thisValue, args, context);
48 _bindArguments(_frame.args);
49
50 // Visit the super or this call in a constructor, if any.
51 final declaredInitializers = method.definition.dynamic.initializers;
52 if (declaredInitializers != null) {
53 for (var init in declaredInitializers) {
54 if (init is CallExpression) {
55 visitCallExpression(init, true);
56 }
57 }
58 }
59
60 if (body != null) body.visit(this);
61 }
62
63 /* Checks whether or not a particular TypeReference Node includes references
64 * to type parameters. */
65 bool _hasTypeParams(node) {
66 if (node is NameTypeReference) {
67 var name = node.name.name;
68 return (method.declaringType.lookupTypeParam(name) != null);
69 } else if (node is GenericTypeReference) {
70 for (var typeArg in node.typeArguments) {
71 if (_hasTypeParams(typeArg)) return true;
72 }
73 return false;
74 } else {
75 // TODO(jimhug): Do we need to include FunctionTypeReference here?
76 return false;
77 }
78 }
79
80 Type resolveType(TypeReference node, bool typeErrors,
81 bool allowTypeParams) {
82 if (!hasTypeParams && _hasTypeParams(node)) {
83 hasTypeParams = true;
84 }
85 return method.resolveType(node, typeErrors, allowTypeParams);
86 }
87
88
89 Value makeNeutral(Value inValue, SourceSpan span) {
90 return new PureStaticValue(inValue.type, span);
91 }
92
93 void _bindArguments(Arguments args) {
94 for (int i = 0; i < method.parameters.length; i++) {
95 var p = method.parameters[i];
96 Value currentArg = null;
97 if (i < args.bareCount) {
98 currentArg = args.values[i];
99 } else {
100 // Handle named or missing arguments
101 currentArg = args.getValue(p.name);
102 if (currentArg === null) {
103 // TODO(jmesserly): this path won't work if we ever get here, because
104 // Paramter.genValue assumes it has a MethodGenerator.
105
106 // Ensure default value for param has been generated
107 p.genValue(method, _frame); // TODO(jimhug): Needed here?
108 if (p.value === null) {
109 world.warning('missing argument at call - does not match');
110 }
111 currentArg = p.value;
112 }
113 }
114
115 currentArg = makeNeutral(currentArg, p.definition.span);
116
117 // TODO(jimhug): Add checks for constructor initializers.
118 _frame.declareParameter(p, currentArg);
119 // TODO(jimhug): Add type check?
120 }
121 }
122
123 visitBool(Expression node) {
124 return visitTypedValue(node, world.boolType);
125 }
126
127 visitValue(Expression node) {
128 if (node == null) return null;
129
130 var value = node.visit(this);
131 value.checkFirstClass(node.span);
132 return value;
133 }
134
135 /**
136 * Visit [node] and ensure statically or with an runtime check that it has
137 * the expected type (if specified).
138 */
139 visitTypedValue(Expression node, Type expectedType) {
140 final val = visitValue(node);
141 return val === null ? null : val.convertTo(_frame, expectedType);
142 }
143
144 visitVoid(Expression node) {
145 // TODO(jimhug): Add some helpful diagnostics for silly void uses.
146 return visitValue(node);
147 }
148
149
150 Arguments _visitArgs(List<ArgumentNode> arguments) {
151 var args = [];
152 bool seenLabel = false;
153 for (var arg in arguments) {
154 if (arg.label != null) {
155 seenLabel = true;
156 } else if (seenLabel) {
157 // TODO(jimhug): Move this into parser?
158 world.error('bare argument cannot follow named arguments', arg.span);
159 }
160 args.add(visitValue(arg.value));
161 }
162
163 return new Arguments(arguments, args);
164 }
165
166 MethodMember _makeLambdaMethod(String name, FunctionDefinition func) {
167 var meth = new MethodMember.lambda(name, method.declaringType, func);
168 meth.enclosingElement = method;
169 meth._methodData = new MethodData(meth, _frame);
170 meth.resolve();
171 return meth;
172 }
173
174 void _pushBlock(Node node) {
175 _frame.pushBlock(node);
176 }
177 void _popBlock(Node node) {
178 _frame.popBlock(node);
179 }
180
181 Member _resolveBare(String name, Node node) {
182 var type = _frame.method.declaringType;
183 var member = type.getMember(name);
184 if (member == null || member.declaringType != type) {
185 var libMember = _frame.library.lookup(name, node.span);
186 if (libMember !== null) return libMember;
187 }
188
189 if (member !== null && !member.isStatic && _frame.isStatic) {
190 world.error('cannot refer to instance member from static method',
191 node.span);
192 }
193 return member;
194 }
195
196 // ******************* Statements *******************
197
198 void visitDietStatement(DietStatement node) {
199 var parser = new Parser(node.span.file, startOffset: node.span.start);
200 parser.block().visit(this);
201 }
202
203 void visitVariableDefinition(VariableDefinition node) {
204 var isFinal = false;
205 // TODO(jimhug): Clean this up and share modifier parsing somewhere.
206 if (node.modifiers != null && node.modifiers[0].kind == TokenKind.FINAL) {
207 isFinal = true;
208 }
209 var type = resolveType(node.type, false, true);
210 for (int i=0; i < node.names.length; i++) {
211 final name = node.names[i].name;
212 var value = visitValue(node.values[i]);
213 _frame.create(name, type, node.names[i], isFinal, value);
214 }
215 }
216
217 void visitFunctionDefinition(FunctionDefinition node) {
218 var meth = _makeLambdaMethod(node.name.name, node);
219 // TODO(jimhug): Better FunctionValue that tracks actual function
220 var funcValue = _frame.create(meth.name, meth.functionType,
221 method.definition, true, null);
222
223 meth.methodData.analyze();
224 }
225
226
227 void visitReturnStatement(ReturnStatement node) {
228 if (node.value == null) {
229 _frame.returns(Value.fromNull(node.span));
230 } else {
231 _frame.returns(visitValue(node.value));
232 }
233 }
234
235 void visitThrowStatement(ThrowStatement node) {
236 // Dart allows throwing anything, just like JS
237 if (node.value != null) {
238 var value = visitValue(node.value);
239 } else {
240 // skip
241 }
242 }
243
244 void visitAssertStatement(AssertStatement node) {
245 // be sure to walk test for static checking even is asserts disabled
246 var test = visitValue(node.test); // TODO(jimhug): check bool or callable.
247 }
248
249 void visitBreakStatement(BreakStatement node) {
250 }
251
252 void visitContinueStatement(ContinueStatement node) {
253 }
254
255 void visitIfStatement(IfStatement node) {
256 var test = visitBool(node.test);
257 node.trueBranch.visit(this);
258 if (node.falseBranch != null) {
259 node.falseBranch.visit(this);
260 }
261 }
262
263 void visitWhileStatement(WhileStatement node) {
264 var test = visitBool(node.test);
265 node.body.visit(this);
266 }
267
268 void visitDoStatement(DoStatement node) {
269 node.body.visit(this);
270 var test = visitBool(node.test);
271 }
272
273 void visitForStatement(ForStatement node) {
274 _pushBlock(node);
275 if (node.init != null) node.init.visit(this);
276
277 if (node.test != null) {
278 var test = visitBool(node.test);
279 }
280 for (var s in node.step) {
281 var sv = visitVoid(s);
282 }
283
284 _pushBlock(node.body);
285 node.body.visit(this);
286 _popBlock(node.body);
287
288
289 _popBlock(node);
290 }
291
292 void visitForInStatement(ForInStatement node) {
293 // TODO(jimhug): visitValue and other cleanups here.
294 var itemType = resolveType(node.item.type, false, true);
295 var list = node.list.visit(this);
296 _visitForInBody(node, itemType, list);
297 }
298
299
300 bool _isFinal(typeRef) {
301 if (typeRef is GenericTypeReference) {
302 typeRef = typeRef.baseType;
303 } else if (typeRef is SimpleTypeReference) {
304 return false;
305 }
306 return typeRef != null && typeRef.isFinal;
307 }
308
309 void _visitForInBody(ForInStatement node, Type itemType, Value list) {
310 // TODO(jimhug): Check that itemType matches list members...
311 _pushBlock(node);
312
313 bool isFinal = _isFinal(node.item.type);
314 var itemName = node.item.name.name;
315 var item =
316 _frame.create(itemName, itemType, node.item.name, isFinal, null);
317
318 var iterator =
319 list.invoke(_frame, 'iterator', node.list, Arguments.EMPTY);
320
321 node.body.visit(this);
322 _popBlock(node);
323 }
324
325 _createDI(DeclaredIdentifier di) {
326 _frame.create(di.name.name, resolveType(di.type, false, true), di.name,
327 true, null);
328 }
329
330 void visitTryStatement(TryStatement node) {
331 _pushBlock(node.body);
332 node.body.visit(this);
333 _popBlock(node.body);
334 if (node.catches.length > 0) {
335 for (int i = 0; i < node.catches.length; i++) {
336 var catch_ = node.catches[i];
337 _pushBlock(catch_);
338 _createDI(catch_.exception);
339 if (catch_.trace !== null) {
340 _createDI(catch_.trace);
341 }
342 catch_.body.visit(this);
343 _popBlock(catch_);
344 }
345 }
346
347 if (node.finallyBlock != null) {
348 node.finallyBlock.visit(this);
349 }
350 }
351
352 void visitSwitchStatement(SwitchStatement node) {
353 var test = visitValue(node.test);
354 for (var case_ in node.cases) {
355 _pushBlock(case_);
356
357 for (int i=0; i < case_.cases.length; i++) {
358 var expr = case_.cases[i];
359 if (expr == null) {
360 //skip
361 } else {
362 var value = visitValue(expr);
363 }
364 }
365 _visitAllStatements(case_.statements);
366 _popBlock(case_);
367 }
368 }
369
370 _visitAllStatements(statementList) {
371 for (int i = 0; i < statementList.length; i++) {
372 var stmt = statementList[i];
373 stmt.visit(this);
374 }
375 }
376
377 void visitBlockStatement(BlockStatement node) {
378 _pushBlock(node);
379 _visitAllStatements(node.body);
380 _popBlock(node);
381 }
382
383 void visitLabeledStatement(LabeledStatement node) {
384 node.body.visit(this);
385 }
386
387 void visitExpressionStatement(ExpressionStatement node) {
388 var value = visitVoid(node.body);
389 }
390
391 void visitEmptyStatement(EmptyStatement node) {
392 }
393
394
395
396 // ******************* Expressions *******************
397 visitLambdaExpression(LambdaExpression node) {
398 var name = (node.func.name != null) ? node.func.name.name : '';
399
400 MethodMember meth = _makeLambdaMethod(name, node.func);
401 // TODO(jimhug): Worry about proper scope for recursive lambda.
402 meth.methodData.analyze();
403
404 return _frame._makeValue(world.functionType, node);
405 }
406
407 analyzeInitializerConstructorCall(CallExpression node,
408 Expression receiver,
409 String name) {
410 var type = _frame.method.declaringType;
411 if (receiver is SuperExpression) {
412 type = type.parent;
413 }
414 var member = type.getConstructor(name == null ? '' : name);
415 if (member !== null) {
416 return member.invoke(_frame, node, _frame.makeThisValue(node),
417 _visitArgs(node.arguments));
418 } else {
419 String constructorName = name == null ? '' : '.$name';
420 world.warning('cannot find constructor "${type.name}$constructorName"',
421 node.span);
422 return _frame._makeValue(world.varType, node);
423 }
424 }
425
426 bool isThisOrSuper(Expression node) {
427 return node is ThisExpression || node is SuperExpression;
428 }
429
430 Value visitCallExpression(CallExpression node,
431 [bool visitingInitializers = false]) {
432 var target;
433 var position = node.target;
434 var name = ':call';
435 if (node.target is DotExpression) {
436 DotExpression dot = node.target;
437 target = dot.self.visit(this);
438 name = dot.name.name;
439 if (isThisOrSuper(dot.self) && visitingInitializers) {
440 return analyzeInitializerConstructorCall(node, dot.self, name);
441 } else {
442 position = dot.name;
443 }
444 } else if (isThisOrSuper(node.target) && visitingInitializers) {
445 return analyzeInitializerConstructorCall(node, node.target, null);
446 } else if (node.target is VarExpression) {
447 VarExpression varExpr = node.target;
448 name = varExpr.name.name;
449 // First check in block scopes.
450 target = _frame.lookup(name);
451 if (target != null) {
452 return target.get(position).invoke(_frame, ':call', node,
453 _visitArgs(node.arguments));
454 }
455
456 var member = _resolveBare(name, varExpr.name);
457 if (member !== null) {
458 return member.invoke(_frame, node, _frame.makeThisValue(node),
459 _visitArgs(node.arguments));
460 } else {
461 world.warning('cannot find "$name"', node.span);
462 return _frame._makeValue(world.varType, node);
463 }
464 } else {
465 target = node.target.visit(this);
466 }
467
468 return target.invoke(_frame, name, position, _visitArgs(node.arguments));
469 }
470
471 Value visitIndexExpression(IndexExpression node) {
472 var target = visitValue(node.target);
473 var index = visitValue(node.index);
474
475 return target.invoke(_frame, ':index', node,
476 new Arguments(null, [index]));
477 }
478
479
480 Value visitBinaryExpression(BinaryExpression node, [bool isVoid = false]) {
481 final kind = node.op.kind;
482
483 if (kind == TokenKind.AND || kind == TokenKind.OR) {
484 var xb = visitBool(node.x);
485 var yb = visitBool(node.y);
486 return xb.binop(kind, yb, _frame, node);
487 }
488
489 final assignKind = TokenKind.kindFromAssign(node.op.kind);
490 if (assignKind == -1) {
491 final x = visitValue(node.x);
492 final y = visitValue(node.y);
493 return x.binop(kind, y, _frame, node);
494 } else {
495 return _visitAssign(assignKind, node.x, node.y, node);
496 }
497 }
498
499 /**
500 * Visits an assignment expression.
501 */
502 Value _visitAssign(int kind, Expression xn, Expression yn, Node position) {
503 if (xn is VarExpression) {
504 return _visitVarAssign(kind, xn, yn, position);
505 } else if (xn is IndexExpression) {
506 return _visitIndexAssign(kind, xn, yn, position);
507 } else if (xn is DotExpression) {
508 return _visitDotAssign(kind, xn, yn, position);
509 } else {
510 world.error('illegal lhs', xn.span);
511 }
512 }
513
514 _visitVarAssign(int kind, VarExpression xn, Expression yn, Node node) {
515 final value = visitValue(yn);
516 final name = xn.name.name;
517
518 // First check in block scopes.
519 var slot = _frame.lookup(name);
520 if (slot != null) {
521 slot.set(value);
522 } else {
523 var member = _resolveBare(name, xn.name);
524 if (member !== null) {
525 member._set(_frame, node, _frame.makeThisValue(node), value);
526 } else {
527 world.warning('cannot find "$name"', node.span);
528 }
529 }
530 return _frame._makeValue(value.type, node);
531 }
532
533 _visitIndexAssign(int kind, IndexExpression xn, Expression yn,
534 Node position) {
535 var target = visitValue(xn.target);
536 var index = visitValue(xn.index);
537 var y = visitValue(yn);
538
539 return target.setIndex(_frame, index, position, y, kind: kind);
540 }
541
542 _visitDotAssign(int kind, DotExpression xn, Expression yn, Node position) {
543 // This is not visitValue because types members are assignable.
544 var target = xn.self.visit(this);
545 var y = visitValue(yn);
546
547 return target.set_(_frame, xn.name.name, xn.name, y, kind: kind);
548 }
549
550 visitUnaryExpression(UnaryExpression node) {
551 var value = visitValue(node.self);
552 switch (node.op.kind) {
553 case TokenKind.INCR:
554 case TokenKind.DECR:
555 return value.binop(TokenKind.ADD,
556 _frame._makeValue(world.intType, node), _frame, node);
557 }
558 return value.unop(node.op.kind, _frame, node);
559 }
560
561 visitDeclaredIdentifier(DeclaredIdentifier node) {
562 world.error('Expected expression', node.span);
563 }
564
565 visitAwaitExpression(AwaitExpression node) {
566 world.internalError(
567 'Await expressions should have been eliminated before code generation',
568 node.span);
569 }
570
571 Value visitPostfixExpression(PostfixExpression node,
572 [bool isVoid = false]) {
573 var value = visitValue(node.body);
574
575 return _frame._makeValue(value.type, node);
576 }
577
578 Value visitNewExpression(NewExpression node) {
579 var typeRef = node.type;
580
581 var constructorName = '';
582 if (node.name != null) {
583 constructorName = node.name.name;
584 }
585
586 // Named constructors and library prefixes, oh my!
587 // At last, we can collapse the ambiguous wave function...
588 if (constructorName == '' && typeRef is NameTypeReference &&
589 typeRef.names != null) {
590
591 // Pull off the last name from the type, guess it's the constructor name.
592 var names = new List.from(typeRef.names);
593 constructorName = names.removeLast().name;
594 if (names.length == 0) names = null;
595
596 typeRef = new NameTypeReference(
597 typeRef.isFinal, typeRef.name, names, typeRef.span);
598 }
599
600 var type = resolveType(typeRef, true, true);
601 if (type.isTop) {
602 type = type.library.findTypeByName(constructorName);
603 if (type == null) {
604 world.error('cannot resolve type $constructorName', node.span);
605 }
606 constructorName = '';
607 }
608
609 if (type is ParameterType) {
610 world.error('cannot instantiate a type parameter', node.span);
611 return _frame._makeValue(world.varType, node);
612 }
613
614 var m = type.getConstructor(constructorName);
615 if (m == null) {
616 var name = type.jsname;
617 if (type.isVar) {
618 name = typeRef.name.name;
619 }
620 world.warning('no matching constructor for $name', node.span);
621 return _frame._makeValue(type, node);
622 }
623
624 if (node.isConst) {
625 if (!m.isConst) {
626 world.error('can\'t use const on a non-const constructor', node.span);
627 }
628 for (var arg in node.arguments) {
629 // TODO(jimhug): Remove this double walk of arguments.
630 if (!visitValue(arg.value).isConst) {
631 world.error('const constructor expects const arguments', arg.span);
632 }
633 }
634 }
635
636
637 var args = _visitArgs(node.arguments);
638 var target = new TypeValue(type, typeRef.span);
639 return new PureStaticValue(type, node.span, node.isConst);
640 }
641
642 Value visitListExpression(ListExpression node) {
643 var argValues = [];
644 var listType = world.listType;
645 var type = world.varType;
646 if (node.itemType != null) {
647 type = resolveType(node.itemType, true, !node.isConst);
648 if (node.isConst && (type is ParameterType || type.hasTypeParams)) {
649 world.error('type parameter cannot be used in const list literals');
650 }
651 listType = listType.getOrMakeConcreteType([type]);
652 }
653 for (var item in node.values) {
654 var arg = visitTypedValue(item, type);
655 argValues.add(arg);
656 // TODO(jimhug): Reenable these checks here - and remove from MethodGen
657 //if (node.isConst && !arg.isConst) {
658 // world.error('const list can only contain const values', arg.span);
659 //}
660 }
661
662 world.listFactoryType.markUsed();
663
664 return new PureStaticValue(listType, node.span, node.isConst);
665 }
666
667
668 Value visitMapExpression(MapExpression node) {
669 var values = <Value>[];
670 var valueType = world.varType, keyType = world.stringType;
671 var mapType = world.mapType; // TODO(jimhug): immutable type?
672 if (node.valueType !== null) {
673 if (node.keyType !== null) {
674 keyType = method.resolveType(node.keyType, true, !node.isConst);
675 // TODO(jimhug): Would be nice to allow arbitrary keys here (this is
676 // currently not allowed by the spec).
677 if (!keyType.isString) {
678 world.error('the key type of a map literal must be "String"',
679 keyType.span);
680 }
681 if (node.isConst &&
682 (keyType is ParameterType || keyType.hasTypeParams)) {
683 world.error('type parameter cannot be used in const map literals');
684 }
685 }
686
687 valueType = resolveType(node.valueType, true, !node.isConst);
688 if (node.isConst &&
689 (valueType is ParameterType || valueType.hasTypeParams)) {
690 world.error('type parameter cannot be used in const map literals');
691 }
692
693 mapType = mapType.getOrMakeConcreteType([keyType, valueType]);
694 }
695
696 for (int i = 0; i < node.items.length; i += 2) {
697 var key = visitTypedValue(node.items[i], keyType);
698 // TODO(jimhug): Reenable these checks here - and remove from MethodGen
699 //if (node.isConst && !key.isConst) {
700 // world.error('const map can only contain const keys', key.span);
701 //}
702 values.add(key);
703
704 var value = visitTypedValue(node.items[i + 1], valueType);
705 if (node.isConst && !value.isConst) {
706 world.error('const map can only contain const values', value.span);
707 }
708 values.add(value);
709 }
710
711 return new PureStaticValue(mapType, node.span, node.isConst);
712 }
713
714
715 Value visitConditionalExpression(ConditionalExpression node) {
716 var test = visitBool(node.test);
717 var trueBranch = visitValue(node.trueBranch);
718 var falseBranch = visitValue(node.falseBranch);
719
720 // TODO(jimhug): Should be unioning values, not just types.
721 return _frame._makeValue(Type.union(trueBranch.type, falseBranch.type),
722 node);
723 }
724
725 Value visitIsExpression(IsExpression node) {
726 var value = visitValue(node.x);
727 var type = resolveType(node.type, false, true);
728 return _frame._makeValue(world.boolType, node);
729 }
730
731 Value visitParenExpression(ParenExpression node) {
732 return visitValue(node.body);
733 }
734
735 Value visitDotExpression(DotExpression node) {
736 // Types are legal targets of .
737 var target = node.self.visit(this);
738 return target.get_(_frame, node.name.name, node);
739 }
740
741
742 Value visitVarExpression(VarExpression node) {
743 final name = node.name.name;
744
745 // First check in block scopes.
746 var slot = _frame.lookup(name);
747 if (slot != null) {
748 return slot.get(node);
749 }
750
751 var member = _resolveBare(name, node.name);
752 if (member !== null) {
753 if (member is TypeMember) {
754 return new PureStaticValue(member.dynamic.type, node.span, true,
755 true);
756 } else {
757 return member._get(_frame, node, _frame.makeThisValue(node));
758 }
759 } else {
760 world.warning('cannot find "$name"', node.span);
761 return _frame._makeValue(world.varType, node);
762 }
763 }
764
765 Value visitThisExpression(ThisExpression node) {
766 return _frame.makeThisValue(node);
767 }
768
769 Value visitSuperExpression(SuperExpression node) {
770 return _frame.makeSuperValue(node);
771 }
772
773 Value visitLiteralExpression(LiteralExpression node) {
774 return new PureStaticValue(node.value.type, node.span, true);
775 }
776
777 Value visitStringConcatExpression(StringConcatExpression node) {
778 bool isConst = true;
779 node.strings.forEach((each) {
780 if (!visitValue(each).isConst) isConst = false;
781 });
782 return new PureStaticValue(world.stringType, node.span, isConst);
783 }
784
785 Value visitStringInterpExpression(StringInterpExpression node) {
786 bool isConst = true;
787 node.pieces.forEach((each) {
788 if (!visitValue(each).isConst) isConst = false;
789 });
790 return new PureStaticValue(world.stringType, node.span, isConst);
791 }
792 }
793
OLDNEW
« no previous file with comments | « no previous file | lib/dartdoc/frog/analyze_frame.dart » ('j') | tools/create_sdk.py » ('J')

Powered by Google App Engine
This is Rietveld 408576698