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

Side by Side Diff: sdk/lib/_internal/compiler/implementation/cps_ir/cps_ir_builder.dart

Issue 574683002: Use ConstExp for storing constants. (Closed) Base URL: https://dart.googlecode.com/svn/branches/bleeding_edge/dart
Patch Set: Remove ConstExpBuilder. Created 6 years, 3 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
OLDNEW
1 // Copyright (c) 2013, the Dart project authors. Please see the AUTHORS file 1 // Copyright (c) 2013, the Dart project authors. Please see the AUTHORS file
2 // for details. All rights reserved. Use of this source code is governed by a 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. 3 // BSD-style license that can be found in the LICENSE file.
4 4
5 library dart2js.ir_builder; 5 library dart2js.ir_builder;
6 6
7 import 'cps_ir_nodes.dart' as ir; 7 import 'cps_ir_nodes.dart' as ir;
8 import '../elements/elements.dart'; 8 import '../elements/elements.dart';
9 import '../dart2jslib.dart'; 9 import '../dart2jslib.dart';
10 import '../dart_types.dart'; 10 import '../dart_types.dart';
(...skipping 309 matching lines...) Expand 10 before | Expand all | Expand 10 after
320 } 320 }
321 321
322 ir.Primitive continueWithExpression(ir.Expression build(ir.Continuation k)) { 322 ir.Primitive continueWithExpression(ir.Expression build(ir.Continuation k)) {
323 ir.Parameter v = new ir.Parameter(null); 323 ir.Parameter v = new ir.Parameter(null);
324 ir.Continuation k = new ir.Continuation([v]); 324 ir.Continuation k = new ir.Continuation([v]);
325 ir.Expression expression = build(k); 325 ir.Expression expression = build(k);
326 add(new ir.LetCont(k, expression)); 326 add(new ir.LetCont(k, expression));
327 return v; 327 return v;
328 } 328 }
329 329
330 ir.Constant makeConst(ConstExp exp, Constant value) { 330 ir.Constant makeConst(ConstExp exp) {
331 return new ir.Constant(exp, value); 331 return new ir.Constant(exp);
332 } 332 }
333 333
334 ir.Constant makePrimConst(PrimitiveConstant value) { 334 ir.Constant makePrimConst(PrimitiveConstant value) {
335 return makeConst(new PrimitiveConstExp(value), value); 335 return makeConst(new PrimitiveConstExp(value));
336 } 336 }
337 337
338 // TODO(johnniwinther): Build constants directly through [ConstExp] when these 338 // TODO(johnniwinther): Build constants directly through [ConstExp] when these
339 // are created from analyzer2dart. 339 // are created from analyzer2dart.
340 ir.Node buildPrimConst(PrimitiveConstant constant) { 340 ir.Node buildPrimConst(PrimitiveConstant constant) {
341 assert(isOpen); 341 assert(isOpen);
342 ir.Node prim = makePrimConst(constant); 342 ir.Node prim = makePrimConst(constant);
343 add(new ir.LetPrim(prim)); 343 add(new ir.LetPrim(prim));
344 return prim; 344 return prim;
345 } 345 }
(...skipping 117 matching lines...) Expand 10 before | Expand all | Expand 10 after
463 // assigned in the delimited subexpression to their reaching definition --- 463 // assigned in the delimited subexpression to their reaching definition ---
464 // that is, the definition in effect at the hole in 'current'. These are 464 // that is, the definition in effect at the hole in 'current'. These are
465 // used to determine if a join-point continuation needs to be passed 465 // used to determine if a join-point continuation needs to be passed
466 // arguments, and what the arguments are. 466 // arguments, and what the arguments are.
467 467
468 /// A stack of collectors for breaks. 468 /// A stack of collectors for breaks.
469 final List<JumpCollector> breakCollectors; 469 final List<JumpCollector> breakCollectors;
470 /// A stack of collectors for continues. 470 /// A stack of collectors for continues.
471 final List<JumpCollector> continueCollectors; 471 final List<JumpCollector> continueCollectors;
472 472
473 ConstExpBuilder constantBuilder;
474
475 final List<ConstDeclaration> localConstants; 473 final List<ConstDeclaration> localConstants;
476 474
477 FunctionElement currentFunction; 475 FunctionElement currentFunction;
478 final DetectClosureVariables closureLocals; 476 final DetectClosureVariables closureLocals;
479 477
480 /// Construct a top-level visitor. 478 /// Construct a top-level visitor.
481 IrBuilderVisitor(TreeElements elements, this.compiler, this.sourceFile) 479 IrBuilderVisitor(TreeElements elements, this.compiler, this.sourceFile)
482 : breakCollectors = <JumpCollector>[], 480 : breakCollectors = <JumpCollector>[],
483 continueCollectors = <JumpCollector>[], 481 continueCollectors = <JumpCollector>[],
484 localConstants = <ConstDeclaration>[], 482 localConstants = <ConstDeclaration>[],
485 closureLocals = new DetectClosureVariables(elements), 483 closureLocals = new DetectClosureVariables(elements),
486 super(elements) { 484 super(elements) {
487 constantSystem = compiler.backend.constantSystem; 485 constantSystem = compiler.backend.constantSystem;
488 constantBuilder = new ConstExpBuilder(this);
489 } 486 }
490 487
491 /// Construct a delimited visitor for visiting a subtree. 488 /// Construct a delimited visitor for visiting a subtree.
492 /// 489 ///
493 /// The delimited visitor has its own compile-time environment mapping 490 /// The delimited visitor has its own compile-time environment mapping
494 /// local variables to their values, which is initially a copy of the parent 491 /// local variables to their values, which is initially a copy of the parent
495 /// environment. It has its own context for building an IR expression, so 492 /// environment. It has its own context for building an IR expression, so
496 /// the built expression is not plugged into the parent's context. 493 /// the built expression is not plugged into the parent's context.
497 IrBuilderVisitor.delimited(IrBuilderVisitor parent) 494 IrBuilderVisitor.delimited(IrBuilderVisitor parent)
498 : compiler = parent.compiler, 495 : compiler = parent.compiler,
499 sourceFile = parent.sourceFile, 496 sourceFile = parent.sourceFile,
500 breakCollectors = parent.breakCollectors, 497 breakCollectors = parent.breakCollectors,
501 continueCollectors = parent.continueCollectors, 498 continueCollectors = parent.continueCollectors,
502 constantBuilder = parent.constantBuilder,
503 localConstants = parent.localConstants, 499 localConstants = parent.localConstants,
504 currentFunction = parent.currentFunction, 500 currentFunction = parent.currentFunction,
505 closureLocals = parent.closureLocals, 501 closureLocals = parent.closureLocals,
506 super(parent.elements) { 502 super(parent.elements) {
507 constantSystem = parent.constantSystem; 503 constantSystem = parent.constantSystem;
508 returnContinuation = parent.returnContinuation; 504 returnContinuation = parent.returnContinuation;
509 environment = new Environment.from(parent.environment); 505 environment = new Environment.from(parent.environment);
510 } 506 }
511 507
512 /// Construct a visitor for a recursive continuation. 508 /// Construct a visitor for a recursive continuation.
513 /// 509 ///
514 /// The recursive continuation builder has fresh parameters (i.e. SSA phis) 510 /// The recursive continuation builder has fresh parameters (i.e. SSA phis)
515 /// for all the local variables in the parent, because the invocation sites 511 /// for all the local variables in the parent, because the invocation sites
516 /// of the continuation are not all known when the builder is created. The 512 /// of the continuation are not all known when the builder is created. The
517 /// recursive invocations will be passed values for all the local variables, 513 /// recursive invocations will be passed values for all the local variables,
518 /// which may be eliminated later if they are redundant---if they take on 514 /// which may be eliminated later if they are redundant---if they take on
519 /// the same value at all invocation sites. 515 /// the same value at all invocation sites.
520 IrBuilderVisitor.recursive(IrBuilderVisitor parent) 516 IrBuilderVisitor.recursive(IrBuilderVisitor parent)
521 : compiler = parent.compiler, 517 : compiler = parent.compiler,
522 sourceFile = parent.sourceFile, 518 sourceFile = parent.sourceFile,
523 breakCollectors = parent.breakCollectors, 519 breakCollectors = parent.breakCollectors,
524 continueCollectors = parent.continueCollectors, 520 continueCollectors = parent.continueCollectors,
525 constantBuilder = parent.constantBuilder,
526 localConstants = parent.localConstants, 521 localConstants = parent.localConstants,
527 currentFunction = parent.currentFunction, 522 currentFunction = parent.currentFunction,
528 closureLocals = parent.closureLocals, 523 closureLocals = parent.closureLocals,
529 super(parent.elements) { 524 super(parent.elements) {
530 constantSystem = parent.constantSystem; 525 constantSystem = parent.constantSystem;
531 returnContinuation = parent.returnContinuation; 526 returnContinuation = parent.returnContinuation;
532 parent.environment.index2variable.forEach(createParameter); 527 parent.environment.index2variable.forEach(createParameter);
533 } 528 }
534 529
535 /** 530 /**
(...skipping 18 matching lines...) Expand all
554 _root = _current = null; 549 _root = _current = null;
555 550
556 FunctionSignature signature = element.functionSignature; 551 FunctionSignature signature = element.functionSignature;
557 signature.orderedForEachParameter((ParameterElement parameterElement) { 552 signature.orderedForEachParameter((ParameterElement parameterElement) {
558 createParameter(parameterElement, 553 createParameter(parameterElement,
559 isClosureVariable: isClosureVariable(parameterElement)); 554 isClosureVariable: isClosureVariable(parameterElement));
560 }); 555 });
561 556
562 List<ConstExp> defaults = new List<ConstExp>(); 557 List<ConstExp> defaults = new List<ConstExp>();
563 signature.orderedOptionalParameters.forEach((ParameterElement element) { 558 signature.orderedOptionalParameters.forEach((ParameterElement element) {
564 if (element.initializer != null) { 559 defaults.add(getConstantForVariable(element));
565 defaults.add(constantBuilder.visit(element.initializer));
566 } else {
567 defaults.add(new PrimitiveConstExp(constantSystem.createNull()));
568 }
569 }); 560 });
570 561
571 visit(function.body); 562 visit(function.body);
572 return buildFunctionDefinition(element, localConstants, defaults); 563 return buildFunctionDefinition(element, localConstants, defaults);
573 } 564 }
574 565
575 ir.Primitive visit(ast.Node node) => node.accept(this); 566 ir.Primitive visit(ast.Node node) => node.accept(this);
576 567
577 // ==== Statements ==== 568 // ==== Statements ====
578 // Build(Block(stamements), C) = C' 569 // Build(Block(stamements), C) = C'
(...skipping 464 matching lines...) Expand 10 before | Expand all | Expand 10 after
1043 return null; 1034 return null;
1044 } 1035 }
1045 1036
1046 ir.Primitive visitVariableDefinitions(ast.VariableDefinitions node) { 1037 ir.Primitive visitVariableDefinitions(ast.VariableDefinitions node) {
1047 assert(isOpen); 1038 assert(isOpen);
1048 if (node.modifiers.isConst) { 1039 if (node.modifiers.isConst) {
1049 for (ast.SendSet definition in node.definitions.nodes) { 1040 for (ast.SendSet definition in node.definitions.nodes) {
1050 assert(!definition.arguments.isEmpty); 1041 assert(!definition.arguments.isEmpty);
1051 assert(definition.arguments.tail.isEmpty); 1042 assert(definition.arguments.tail.isEmpty);
1052 VariableElement element = elements[definition]; 1043 VariableElement element = elements[definition];
1053 ConstExp value = constantBuilder.visit(definition.arguments.head); 1044 ConstExp value = getConstantForVariable(element);
1054 localConstants.add(new ConstDeclaration(element, value)); 1045 localConstants.add(new ConstDeclaration(element, value));
1055 } 1046 }
1056 } else { 1047 } else {
1057 for (ast.Node definition in node.definitions.nodes) { 1048 for (ast.Node definition in node.definitions.nodes) {
1058 Element element = elements[definition]; 1049 Element element = elements[definition];
1059 ir.Primitive initialValue; 1050 ir.Primitive initialValue;
1060 // Definitions are either SendSets if there is an initializer, or 1051 // Definitions are either SendSets if there is an initializer, or
1061 // Identifiers if there is no initializer. 1052 // Identifiers if there is no initializer.
1062 if (definition is ast.SendSet) { 1053 if (definition is ast.SendSet) {
1063 assert(!definition.arguments.isEmpty); 1054 assert(!definition.arguments.isEmpty);
(...skipping 100 matching lines...) Expand 10 before | Expand all | Expand 10 after
1164 ir.Primitive visitLiteralNull(ast.LiteralNull node) { 1155 ir.Primitive visitLiteralNull(ast.LiteralNull node) {
1165 assert(isOpen); 1156 assert(isOpen);
1166 return translateConstant(node); 1157 return translateConstant(node);
1167 } 1158 }
1168 1159
1169 ir.Primitive visitLiteralString(ast.LiteralString node) { 1160 ir.Primitive visitLiteralString(ast.LiteralString node) {
1170 assert(isOpen); 1161 assert(isOpen);
1171 return translateConstant(node); 1162 return translateConstant(node);
1172 } 1163 }
1173 1164
1174 Constant getConstantForNode(ast.Node node) { 1165 ConstExp getConstantForNode(ast.Node node) {
1175 Constant constant = 1166 ConstExp constant =
1176 compiler.backend.constantCompilerTask.compileNode(node, elements); 1167 compiler.backend.constantCompilerTask.compileNode(node, elements);
1177 assert(invariant(node, constant != null, 1168 assert(invariant(node, constant != null,
1178 message: 'No constant computed for $node')); 1169 message: 'No constant computed for $node'));
1179 return constant; 1170 return constant;
1180 } 1171 }
1181 1172
1173 ConstExp getConstantForVariable(VariableElement element) {
1174 ConstExp constant =
1175 compiler.backend.constants.getConstantForVariable(element);
1176 assert(invariant(element, constant != null,
1177 message: 'No constant computed for $element'));
1178 return constant;
1179 }
1180
1182 ir.Primitive visitLiteralList(ast.LiteralList node) { 1181 ir.Primitive visitLiteralList(ast.LiteralList node) {
1183 assert(isOpen); 1182 assert(isOpen);
1184 if (node.isConst) { 1183 if (node.isConst) {
1185 return translateConstant(node); 1184 return translateConstant(node);
1186 } 1185 }
1187 List<ir.Primitive> values = node.elements.nodes.mapToList(visit); 1186 List<ir.Primitive> values = node.elements.nodes.mapToList(visit);
1188 GenericType type = elements.getType(node); 1187 GenericType type = elements.getType(node);
1189 ir.Primitive result = new ir.LiteralList(type, values); 1188 ir.Primitive result = new ir.LiteralList(type, values);
1190 add(new ir.LetPrim(result)); 1189 add(new ir.LetPrim(result));
1191 return result; 1190 return result;
(...skipping 534 matching lines...) Expand 10 before | Expand all | Expand 10 after
1726 var it = node.parts.iterator; 1725 var it = node.parts.iterator;
1727 while (it.moveNext()) { 1726 while (it.moveNext()) {
1728 ast.StringInterpolationPart part = it.current; 1727 ast.StringInterpolationPart part = it.current;
1729 arguments.add(visit(part.expression)); 1728 arguments.add(visit(part.expression));
1730 arguments.add(visitLiteralString(part.string)); 1729 arguments.add(visitLiteralString(part.string));
1731 } 1730 }
1732 return continueWithExpression( 1731 return continueWithExpression(
1733 (k) => new ir.ConcatenateStrings(k, arguments)); 1732 (k) => new ir.ConcatenateStrings(k, arguments));
1734 } 1733 }
1735 1734
1736 ir.Primitive translateConstant(ast.Node node, [Constant value]) { 1735 ir.Primitive translateConstant(ast.Node node, [ConstExp constant]) {
1737 assert(isOpen); 1736 assert(isOpen);
1738 if (value == null) { 1737 if (constant == null) {
1739 value = getConstantForNode(node); 1738 constant = getConstantForNode(node);
1740 } 1739 }
1741 ir.Primitive primitive = makeConst(constantBuilder.visit(node), value); 1740 ir.Primitive primitive = makeConst(constant);
1742 add(new ir.LetPrim(primitive)); 1741 add(new ir.LetPrim(primitive));
1743 return primitive; 1742 return primitive;
1744 } 1743 }
1745 1744
1746 ir.FunctionDefinition makeSubFunction(ast.FunctionExpression node) { 1745 ir.FunctionDefinition makeSubFunction(ast.FunctionExpression node) {
1747 return new IrBuilderVisitor(elements, compiler, sourceFile) 1746 return new IrBuilderVisitor(elements, compiler, sourceFile)
1748 .buildFunctionInternal(elements[node]); 1747 .buildFunctionInternal(elements[node]);
1749 } 1748 }
1750 1749
1751 ir.Primitive visitFunctionExpression(ast.FunctionExpression node) { 1750 ir.Primitive visitFunctionExpression(ast.FunctionExpression node) {
(...skipping 33 matching lines...) Expand 10 before | Expand all | Expand 10 after
1785 } 1784 }
1786 rethrow; 1785 rethrow;
1787 } 1786 }
1788 } 1787 }
1789 1788
1790 void internalError(String reason, {ast.Node node}) { 1789 void internalError(String reason, {ast.Node node}) {
1791 giveup(node); 1790 giveup(node);
1792 } 1791 }
1793 } 1792 }
1794 1793
1795 /// Translates constant expressions from the AST to the [ConstExp] language.
1796 class ConstExpBuilder extends ast.Visitor<ConstExp> {
1797 final IrBuilderVisitor parent;
1798 final TreeElements elements;
1799 final ConstantSystem constantSystem;
1800 final ConstantCompiler constantCompiler;
1801
1802 ConstExpBuilder(IrBuilderVisitor parent)
1803 : this.parent = parent,
1804 this.elements = parent.elements,
1805 this.constantSystem = parent.constantSystem,
1806 this.constantCompiler = parent.compiler.backend.constantCompilerTask;
1807
1808 Constant computeConstant(ast.Node node) {
1809 return constantCompiler.compileNode(node, elements);
1810 }
1811
1812 /// True if the given constant is small enough that inlining it is likely
1813 /// to be profitable. Always false for non-primitive constants.
1814 bool isSmallConstant(Constant constant) {
1815 if (constant is BoolConstant || constant is NullConstant) {
1816 return true;
1817 }
1818 if (constant is IntConstant) {
1819 return -10 < constant.value && constant.value < 100;
1820 }
1821 if (constant is DoubleConstant) {
1822 return constant.isZero || constant.isOne;
1823 }
1824 if (constant is StringConstant) {
1825 ast.DartString string = constant.value;
1826 if (string is ast.LiteralDartString) {
1827 return string.length < 4;
1828 }
1829 if (string is ast.SourceBasedDartString) {
1830 return string.length < 4;
1831 }
1832 }
1833 return false;
1834 }
1835
1836 ConstExp visit(ast.Node node) => node.accept(this);
1837
1838 ConstExp visitStringJuxtaposition(ast.StringJuxtaposition node) {
1839 ConstExp first = visit(node.first);
1840 ConstExp second = visit(node.second);
1841 return new ConcatenateConstExp([first, second]);
1842 }
1843
1844 ConstExp visitStringInterpolation(ast.StringInterpolation node) {
1845 List<ConstExp> arguments = <ConstExp>[];
1846 arguments.add(visitLiteralString(node.string));
1847 var it = node.parts.iterator;
1848 while (it.moveNext()) {
1849 ast.StringInterpolationPart part = it.current;
1850 arguments.add(visit(part.expression));
1851 arguments.add(visitLiteralString(part.string));
1852 }
1853 return new ConcatenateConstExp(arguments);
1854 }
1855
1856 ConstExp visitNewExpression(ast.NewExpression node) {
1857 FunctionElement element = elements[node.send];
1858 if (Elements.isUnresolved(element)) {
1859 throw parent.giveup(node, 'const NewExpression: unresolved constructor');
1860 }
1861 Selector selector = elements.getSelector(node.send);
1862 ast.Node selectorNode = node.send.selector;
1863 GenericType type = elements.getType(node);
1864 List<ConstExp> args = node.send.arguments.mapToList(visit, growable:false);
1865 return new ConstructorConstExp(type, element, selector, args);
1866 }
1867
1868 ConstExp visitNamedArgument(ast.NamedArgument node) {
1869 return visit(node.expression);
1870 }
1871
1872 ConstExp visitSend(ast.Send node) {
1873 Element element = elements[node];
1874 if (node.isOperator) {
1875 return new PrimitiveConstExp(computeConstant(node));
1876 }
1877 if (Elements.isStaticOrTopLevelFunction(element)) {
1878 return new FunctionConstExp(element);
1879 }
1880 if (Elements.isLocal(element) ||
1881 Elements.isStaticOrTopLevelField(element)) {
1882 // If the constant is small, inline it instead of using the declared const
1883 Constant value = constantCompiler.getConstantForVariable(element);
1884 if (isSmallConstant(value))
1885 return new PrimitiveConstExp(value);
1886 else
1887 return new VariableConstExp(element);
1888 }
1889 DartType type = elements.getTypeLiteralType(node);
1890 if (type != null) {
1891 return new TypeConstExp(type);
1892 }
1893 throw "Unexpected constant Send: $node";
1894 }
1895
1896 ConstExp visitParenthesizedExpression(ast.ParenthesizedExpression node) {
1897 return visit(node.expression);
1898 }
1899
1900 ConstExp visitLiteralList(ast.LiteralList node) {
1901 List<ConstExp> values = node.elements.nodes.mapToList(visit);
1902 GenericType type = elements.getType(node);
1903 return new ListConstExp(type, values);
1904 }
1905
1906 ConstExp visitLiteralMap(ast.LiteralMap node) {
1907 List<ConstExp> keys = new List<ConstExp>();
1908 List<ConstExp> values = new List<ConstExp>();
1909 node.entries.nodes.forEach((ast.LiteralMapEntry node) {
1910 keys.add(visit(node.key));
1911 values.add(visit(node.value));
1912 });
1913 GenericType type = elements.getType(node);
1914 return new MapConstExp(type, keys, values);
1915 }
1916
1917 ConstExp visitLiteralSymbol(ast.LiteralSymbol node) {
1918 return new SymbolConstExp(node.slowNameString);
1919 }
1920
1921 ConstExp visitLiteralInt(ast.LiteralInt node) {
1922 return new PrimitiveConstExp(constantSystem.createInt(node.value));
1923 }
1924
1925 ConstExp visitLiteralDouble(ast.LiteralDouble node) {
1926 return new PrimitiveConstExp(constantSystem.createDouble(node.value));
1927 }
1928
1929 ConstExp visitLiteralString(ast.LiteralString node) {
1930 return new PrimitiveConstExp(constantSystem.createString(node.dartString));
1931 }
1932
1933 ConstExp visitLiteralBool(ast.LiteralBool node) {
1934 return new PrimitiveConstExp(constantSystem.createBool(node.value));
1935 }
1936
1937 ConstExp visitLiteralNull(ast.LiteralNull node) {
1938 return new PrimitiveConstExp(constantSystem.createNull());
1939 }
1940
1941 ConstExp visitConditional(ast.Conditional node) {
1942 BoolConstant condition = computeConstant(node.condition);
1943 return visit(condition.isTrue ? node.thenExpression : node.elseExpression);
1944 }
1945
1946 ConstExp visitNode(ast.Node node) {
1947 throw "Unexpected constant: $node";
1948 }
1949
1950 }
1951
1952 /// Classifies local variables and local functions as 'closure variables'. 1794 /// Classifies local variables and local functions as 'closure variables'.
1953 /// A closure variable is one that is accessed from an inner function nested 1795 /// A closure variable is one that is accessed from an inner function nested
1954 /// one or more levels inside the one that declares it. 1796 /// one or more levels inside the one that declares it.
1955 class DetectClosureVariables extends ast.Visitor { 1797 class DetectClosureVariables extends ast.Visitor {
1956 final TreeElements elements; 1798 final TreeElements elements;
1957 DetectClosureVariables(this.elements); 1799 DetectClosureVariables(this.elements);
1958 1800
1959 FunctionElement currentFunction; 1801 FunctionElement currentFunction;
1960 Set<Local> usedFromClosure = new Set<Local>(); 1802 Set<Local> usedFromClosure = new Set<Local>();
1961 Set<FunctionElement> recursiveFunctions = new Set<FunctionElement>(); 1803 Set<FunctionElement> recursiveFunctions = new Set<FunctionElement>();
(...skipping 22 matching lines...) Expand all
1984 } 1826 }
1985 1827
1986 visitFunctionExpression(ast.FunctionExpression node) { 1828 visitFunctionExpression(ast.FunctionExpression node) {
1987 FunctionElement oldFunction = currentFunction; 1829 FunctionElement oldFunction = currentFunction;
1988 currentFunction = elements[node]; 1830 currentFunction = elements[node];
1989 visit(node.body); 1831 visit(node.body);
1990 currentFunction = oldFunction; 1832 currentFunction = oldFunction;
1991 } 1833 }
1992 1834
1993 } 1835 }
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698