| OLD | NEW |
| 1 // Copyright (c) 2016, the Dart project authors. Please see the AUTHORS file | 1 // Copyright (c) 2016, 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 library kernel.analyzer.ast_from_analyzer; | 4 library kernel.analyzer.ast_from_analyzer; |
| 5 | 5 |
| 6 import '../ast.dart' as ast; | 6 import '../ast.dart' as ast; |
| 7 import '../frontend/accessors.dart'; | 7 import '../frontend/accessors.dart'; |
| 8 import '../frontend/super_initializers.dart'; | 8 import '../frontend/super_initializers.dart'; |
| 9 import '../log.dart'; | 9 import '../log.dart'; |
| 10 import '../type_algebra.dart'; | 10 import '../type_algebra.dart'; |
| (...skipping 506 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 517 } | 517 } |
| 518 | 518 |
| 519 ast.Statement buildMandatoryFunctionBody(FunctionBody body) { | 519 ast.Statement buildMandatoryFunctionBody(FunctionBody body) { |
| 520 try { | 520 try { |
| 521 if (body is BlockFunctionBody) { | 521 if (body is BlockFunctionBody) { |
| 522 return buildStatement(body.block); | 522 return buildStatement(body.block); |
| 523 } else if (body is ExpressionFunctionBody) { | 523 } else if (body is ExpressionFunctionBody) { |
| 524 if (bodyHasVoidReturn(body)) { | 524 if (bodyHasVoidReturn(body)) { |
| 525 return new ast.ExpressionStatement(buildExpression(body.expression)); | 525 return new ast.ExpressionStatement(buildExpression(body.expression)); |
| 526 } else { | 526 } else { |
| 527 return new ast.ReturnStatement(buildExpression(body.expression)); | 527 return new ast.ReturnStatement(buildExpression(body.expression)) |
| 528 ..fileOffset = body.expression.offset; |
| 528 } | 529 } |
| 529 } else { | 530 } else { |
| 530 return internalError('Missing function body'); | 531 return internalError('Missing function body'); |
| 531 } | 532 } |
| 532 } on _CompilationError catch (e) { | 533 } on _CompilationError catch (e) { |
| 533 return new ast.ExpressionStatement(buildThrowCompileTimeError(e.message)); | 534 return new ast.ExpressionStatement(buildThrowCompileTimeError(e.message)); |
| 534 } | 535 } |
| 535 } | 536 } |
| 536 | 537 |
| 537 ast.AsyncMarker getAsyncMarker({bool isAsync: false, bool isStar: false}) { | 538 ast.AsyncMarker getAsyncMarker({bool isAsync: false, bool isStar: false}) { |
| (...skipping 119 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 657 return buildType(element.type); | 658 return buildType(element.type); |
| 658 } else if (element is VariableElement) { | 659 } else if (element is VariableElement) { |
| 659 return buildType(element.type); | 660 return buildType(element.type); |
| 660 } else { | 661 } else { |
| 661 log.severe('Unexpected variable element: $element'); | 662 log.severe('Unexpected variable element: $element'); |
| 662 return const ast.DynamicType(); | 663 return const ast.DynamicType(); |
| 663 } | 664 } |
| 664 } | 665 } |
| 665 | 666 |
| 666 ast.VariableDeclaration makeVariableDeclaration(LocalElement element, | 667 ast.VariableDeclaration makeVariableDeclaration(LocalElement element, |
| 667 {ast.DartType type, ast.Expression initializer}) { | 668 {ast.DartType type, ast.Expression initializer, int equalsOffset}) { |
| 668 var declaration = getVariableReference(element); | 669 var declaration = getVariableReference(element); |
| 670 if (equalsOffset != null) declaration.fileEqualsOffset = equalsOffset; |
| 669 declaration.type = type ?? getInferredVariableType(element); | 671 declaration.type = type ?? getInferredVariableType(element); |
| 670 if (initializer != null) { | 672 if (initializer != null) { |
| 671 declaration.initializer = initializer..parent = declaration; | 673 declaration.initializer = initializer..parent = declaration; |
| 672 } | 674 } |
| 673 return declaration; | 675 return declaration; |
| 674 } | 676 } |
| 675 | 677 |
| 676 /// Returns true if [arguments] can be accepted by [target] | 678 /// Returns true if [arguments] can be accepted by [target] |
| 677 /// (not taking type checks into account). | 679 /// (not taking type checks into account). |
| 678 bool areArgumentsCompatible( | 680 bool areArgumentsCompatible( |
| (...skipping 275 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 954 LabeledStatement labeled = node; | 956 LabeledStatement labeled = node; |
| 955 node = labeled.statement; | 957 node = labeled.statement; |
| 956 } | 958 } |
| 957 if (node is VariableDeclarationStatement) { | 959 if (node is VariableDeclarationStatement) { |
| 958 VariableDeclarationList list = node.variables; | 960 VariableDeclarationList list = node.variables; |
| 959 ast.DartType type = scope.buildOptionalTypeAnnotation(list.type); | 961 ast.DartType type = scope.buildOptionalTypeAnnotation(list.type); |
| 960 for (VariableDeclaration decl in list.variables) { | 962 for (VariableDeclaration decl in list.variables) { |
| 961 LocalElement local = decl.element as dynamic; // Cross cast. | 963 LocalElement local = decl.element as dynamic; // Cross cast. |
| 962 output.add(scope.makeVariableDeclaration(local, | 964 output.add(scope.makeVariableDeclaration(local, |
| 963 type: type, | 965 type: type, |
| 964 initializer: scope.buildOptionalExpression(decl.initializer))); | 966 initializer: scope.buildOptionalExpression(decl.initializer), |
| 967 equalsOffset: decl.equals?.offset)); |
| 965 } | 968 } |
| 966 } else { | 969 } else { |
| 967 output.add(build(node)); | 970 output.add(build(node)); |
| 968 } | 971 } |
| 969 } | 972 } |
| 970 | 973 |
| 971 ast.Statement makeBreakTarget(ast.Statement node, LabelStack stackNode) { | 974 ast.Statement makeBreakTarget(ast.Statement node, LabelStack stackNode) { |
| 972 if (stackNode.jumps.isEmpty) return node; | 975 if (stackNode.jumps.isEmpty) return node; |
| 973 var labeled = new ast.LabeledStatement(node); | 976 var labeled = new ast.LabeledStatement(node); |
| 974 for (var jump in stackNode.jumps) { | 977 for (var jump in stackNode.jumps) { |
| (...skipping 193 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1168 ast.Statement visitForStatement(ForStatement node) { | 1171 ast.Statement visitForStatement(ForStatement node) { |
| 1169 List<ast.VariableDeclaration> variables = <ast.VariableDeclaration>[]; | 1172 List<ast.VariableDeclaration> variables = <ast.VariableDeclaration>[]; |
| 1170 ast.Expression initialExpression; | 1173 ast.Expression initialExpression; |
| 1171 if (node.variables != null) { | 1174 if (node.variables != null) { |
| 1172 VariableDeclarationList list = node.variables; | 1175 VariableDeclarationList list = node.variables; |
| 1173 var type = scope.buildOptionalTypeAnnotation(list.type); | 1176 var type = scope.buildOptionalTypeAnnotation(list.type); |
| 1174 for (var variable in list.variables) { | 1177 for (var variable in list.variables) { |
| 1175 LocalElement local = variable.element as dynamic; // Cross cast. | 1178 LocalElement local = variable.element as dynamic; // Cross cast. |
| 1176 variables.add(scope.makeVariableDeclaration(local, | 1179 variables.add(scope.makeVariableDeclaration(local, |
| 1177 initializer: scope.buildOptionalExpression(variable.initializer), | 1180 initializer: scope.buildOptionalExpression(variable.initializer), |
| 1178 type: type)); | 1181 type: type, |
| 1182 equalsOffset: variable.equals?.offset)); |
| 1179 } | 1183 } |
| 1180 } else if (node.initialization != null) { | 1184 } else if (node.initialization != null) { |
| 1181 initialExpression = scope.buildExpression(node.initialization); | 1185 initialExpression = scope.buildExpression(node.initialization); |
| 1182 } | 1186 } |
| 1183 var breakNode = new LabelStack.unlabeled(breakStack); | 1187 var breakNode = new LabelStack.unlabeled(breakStack); |
| 1184 var continueNode = new LabelStack.unlabeled(continueStack); | 1188 var continueNode = new LabelStack.unlabeled(continueStack); |
| 1185 addLoopLabels(node, continueNode); | 1189 addLoopLabels(node, continueNode); |
| 1186 var body = buildInScope(node.body, breakNode, continueNode); | 1190 var body = buildInScope(node.body, breakNode, continueNode); |
| 1187 var loop = new ast.ForStatement( | 1191 var loop = new ast.ForStatement( |
| 1188 variables, | 1192 variables, |
| (...skipping 168 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1357 extends GeneralizingAstVisitor /* <ast.Expression | Accessor> */ { | 1361 extends GeneralizingAstVisitor /* <ast.Expression | Accessor> */ { |
| 1358 final ExpressionScope scope; | 1362 final ExpressionScope scope; |
| 1359 ast.VariableDeclaration cascadeReceiver; | 1363 ast.VariableDeclaration cascadeReceiver; |
| 1360 ExpressionBuilder(this.scope); | 1364 ExpressionBuilder(this.scope); |
| 1361 | 1365 |
| 1362 ast.Expression build(Expression node) { | 1366 ast.Expression build(Expression node) { |
| 1363 var result = node.accept(this); | 1367 var result = node.accept(this); |
| 1364 if (result is Accessor) { | 1368 if (result is Accessor) { |
| 1365 result = result.buildSimpleRead(); | 1369 result = result.buildSimpleRead(); |
| 1366 } | 1370 } |
| 1367 return result..fileOffset = _getOffset(node); | 1371 // For some method invocations we have already set a file offset to |
| 1372 // override the default behavior of _getOffset. |
| 1373 if (node is! MethodInvocation || result.fileOffset < 0) { |
| 1374 result.fileOffset = _getOffset(node); |
| 1375 } |
| 1376 return result; |
| 1368 } | 1377 } |
| 1369 | 1378 |
| 1370 int _getOffset(AstNode node) { | 1379 int _getOffset(AstNode node) { |
| 1371 if (node is MethodInvocation) { | 1380 if (node is MethodInvocation) { |
| 1372 return node.methodName.offset; | 1381 return node.methodName.offset; |
| 1373 } else if (node is InstanceCreationExpression) { | 1382 } else if (node is InstanceCreationExpression) { |
| 1374 return node.constructorName.offset; | 1383 return node.constructorName.offset; |
| 1375 } else if (node is BinaryExpression) { | 1384 } else if (node is BinaryExpression) { |
| 1376 return node.operator.offset; | 1385 return node.operator.offset; |
| 1377 } else if (node is PrefixedIdentifier) { | 1386 } else if (node is PrefixedIdentifier) { |
| 1378 return node.identifier.offset; | 1387 return node.identifier.offset; |
| 1379 } else if (node is AssignmentExpression) { | 1388 } else if (node is AssignmentExpression) { |
| 1380 return _getOffset(node.leftHandSide); | 1389 return _getOffset(node.leftHandSide); |
| 1381 } else if (node is PropertyAccess) { | 1390 } else if (node is PropertyAccess) { |
| 1382 return node.propertyName.offset; | 1391 return node.propertyName.offset; |
| 1383 } else if (node is IsExpression) { | 1392 } else if (node is IsExpression) { |
| 1384 return node.isOperator.offset; | 1393 return node.isOperator.offset; |
| 1394 } else if (node is AsExpression) { |
| 1395 return node.asOperator.offset; |
| 1385 } else if (node is StringLiteral) { | 1396 } else if (node is StringLiteral) { |
| 1386 // Use a catch-all for StringInterpolation and AdjacentStrings: | 1397 // Use a catch-all for StringInterpolation and AdjacentStrings: |
| 1387 // the debugger stops at the end. | 1398 // the debugger stops at the end. |
| 1388 return node.end; | 1399 return node.end; |
| 1400 } else if (node is IndexExpression) { |
| 1401 return node.leftBracket.offset; |
| 1389 } | 1402 } |
| 1390 return node.offset; | 1403 return node.offset; |
| 1391 } | 1404 } |
| 1392 | 1405 |
| 1393 Accessor buildLeftHandValue(Expression node) { | 1406 Accessor buildLeftHandValue(Expression node) { |
| 1394 var result = node.accept(this); | 1407 var result = node.accept(this); |
| 1395 if (result is Accessor) { | 1408 if (result is Accessor) { |
| 1396 return result; | 1409 return result; |
| 1397 } else { | 1410 } else { |
| 1398 return new ReadOnlyAccessor(result); | 1411 return new ReadOnlyAccessor(result); |
| (...skipping 460 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1859 scope.areArgumentsCompatible(element, arguments)) { | 1872 scope.areArgumentsCompatible(element, arguments)) { |
| 1860 return new ast.ConstructorInvocation(constructor, arguments, | 1873 return new ast.ConstructorInvocation(constructor, arguments, |
| 1861 isConst: node.isConst); | 1874 isConst: node.isConst); |
| 1862 } else { | 1875 } else { |
| 1863 return noSuchMethodError(); | 1876 return noSuchMethodError(); |
| 1864 } | 1877 } |
| 1865 } | 1878 } |
| 1866 | 1879 |
| 1867 ast.Expression visitIsExpression(IsExpression node) { | 1880 ast.Expression visitIsExpression(IsExpression node) { |
| 1868 if (node.notOperator != null) { | 1881 if (node.notOperator != null) { |
| 1882 // Put offset on the IsExpression for "is!" cases: |
| 1883 // As it is wrapped in a not, it won't get an offset otherwise. |
| 1869 return new ast.Not(new ast.IsExpression( | 1884 return new ast.Not(new ast.IsExpression( |
| 1870 build(node.expression), scope.buildTypeAnnotation(node.type))); | 1885 build(node.expression), scope.buildTypeAnnotation(node.type)) |
| 1886 ..fileOffset = _getOffset(node)); |
| 1871 } else { | 1887 } else { |
| 1872 return new ast.IsExpression( | 1888 return new ast.IsExpression( |
| 1873 build(node.expression), scope.buildTypeAnnotation(node.type)); | 1889 build(node.expression), scope.buildTypeAnnotation(node.type)); |
| 1874 } | 1890 } |
| 1875 } | 1891 } |
| 1876 | 1892 |
| 1877 /// Emit a method invocation, either as a direct call `o.f(x)` or decomposed | 1893 /// Emit a method invocation, either as a direct call `o.f(x)` or decomposed |
| 1878 /// into a getter and function invocation `o.f.call(x)`. | 1894 /// into a getter and function invocation `o.f.call(x)`. |
| 1879 ast.Expression buildDecomposableMethodInvocation(ast.Expression receiver, | 1895 ast.Expression buildDecomposableMethodInvocation(ast.Expression receiver, |
| 1880 ast.Name name, ast.Arguments arguments, Element targetElement) { | 1896 ast.Name name, ast.Arguments arguments, Element targetElement) { |
| (...skipping 28 matching lines...) Expand all Loading... |
| 1909 scope.buildName(node.methodName), | 1925 scope.buildName(node.methodName), |
| 1910 buildArgumentsForInvocation(node), | 1926 buildArgumentsForInvocation(node), |
| 1911 element); | 1927 element); |
| 1912 } else if (target is SuperExpression) { | 1928 } else if (target is SuperExpression) { |
| 1913 scope.addTransformerFlag(TransformerFlag.superCalls); | 1929 scope.addTransformerFlag(TransformerFlag.superCalls); |
| 1914 return new ast.SuperMethodInvocation( | 1930 return new ast.SuperMethodInvocation( |
| 1915 scope.buildName(node.methodName), | 1931 scope.buildName(node.methodName), |
| 1916 buildArgumentsForInvocation(node), | 1932 buildArgumentsForInvocation(node), |
| 1917 scope.resolveConcreteMethod(element)); | 1933 scope.resolveConcreteMethod(element)); |
| 1918 } else if (isLocal(element)) { | 1934 } else if (isLocal(element)) { |
| 1935 // Set the offset directly: Normally the offset is at the start of the |
| 1936 // method, but in this case, because we insert a '.call', we want it at |
| 1937 // the end instead. |
| 1919 return new ast.MethodInvocation( | 1938 return new ast.MethodInvocation( |
| 1920 new ast.VariableGet(scope.getVariableReference(element)), | 1939 new ast.VariableGet(scope.getVariableReference(element)), |
| 1921 callName, | 1940 callName, |
| 1922 buildArgumentsForInvocation(node), | 1941 buildArgumentsForInvocation(node), |
| 1923 scope.resolveInterfaceFunctionCall(element)); | 1942 scope.resolveInterfaceFunctionCall(element)) |
| 1943 ..fileOffset = node.methodName.end; |
| 1924 } else if (isStaticMethod(element)) { | 1944 } else if (isStaticMethod(element)) { |
| 1925 var method = scope.resolveConcreteMethod(element); | 1945 var method = scope.resolveConcreteMethod(element); |
| 1926 var arguments = buildArgumentsForInvocation(node); | 1946 var arguments = buildArgumentsForInvocation(node); |
| 1927 if (method == null || !scope.areArgumentsCompatible(element, arguments)) { | 1947 if (method == null || !scope.areArgumentsCompatible(element, arguments)) { |
| 1928 return scope.buildThrowNoSuchMethodError( | 1948 return scope.buildThrowNoSuchMethodError( |
| 1929 new ast.NullLiteral(), node.methodName.name, arguments, | 1949 new ast.NullLiteral(), node.methodName.name, arguments, |
| 1930 candidateTarget: element); | 1950 candidateTarget: element); |
| 1931 } | 1951 } |
| 1932 return new ast.StaticInvocation(method, arguments); | 1952 return new ast.StaticInvocation(method, arguments); |
| 1933 } else if (isStaticVariableOrGetter(element)) { | 1953 } else if (isStaticVariableOrGetter(element)) { |
| 1934 var method = scope.resolveConcreteGet(element, null); | 1954 var method = scope.resolveConcreteGet(element, null); |
| 1935 if (method == null) { | 1955 if (method == null) { |
| 1936 return scope.buildThrowNoSuchMethodError( | 1956 return scope.buildThrowNoSuchMethodError( |
| 1937 new ast.NullLiteral(), node.methodName.name, new ast.Arguments([]), | 1957 new ast.NullLiteral(), node.methodName.name, new ast.Arguments([]), |
| 1938 candidateTarget: element); | 1958 candidateTarget: element); |
| 1939 } | 1959 } |
| 1960 // TODO(jensj): We probably want this at the end too. |
| 1940 return new ast.MethodInvocation( | 1961 return new ast.MethodInvocation( |
| 1941 new ast.StaticGet(method), | 1962 new ast.StaticGet(method), |
| 1942 callName, | 1963 callName, |
| 1943 buildArgumentsForInvocation(node), | 1964 buildArgumentsForInvocation(node), |
| 1944 scope.resolveInterfaceFunctionCall(element)); | 1965 scope.resolveInterfaceFunctionCall(element)); |
| 1945 } else if (target == null && !scope.allowThis || | 1966 } else if (target == null && !scope.allowThis || |
| 1946 target is Identifier && target.staticElement is ClassElement || | 1967 target is Identifier && target.staticElement is ClassElement || |
| 1947 target is Identifier && target.staticElement is PrefixElement) { | 1968 target is Identifier && target.staticElement is PrefixElement) { |
| 1948 return scope.buildThrowNoSuchMethodError(new ast.NullLiteral(), | 1969 return scope.buildThrowNoSuchMethodError(new ast.NullLiteral(), |
| 1949 node.methodName.name, buildArgumentsForInvocation(node), | 1970 node.methodName.name, buildArgumentsForInvocation(node), |
| (...skipping 43 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1993 } | 2014 } |
| 1994 | 2015 |
| 1995 ast.Expression visitPostfixExpression(PostfixExpression node) { | 2016 ast.Expression visitPostfixExpression(PostfixExpression node) { |
| 1996 String operator = node.operator.value(); | 2017 String operator = node.operator.value(); |
| 1997 switch (operator) { | 2018 switch (operator) { |
| 1998 case '++': | 2019 case '++': |
| 1999 case '--': | 2020 case '--': |
| 2000 var leftHand = buildLeftHandValue(node.operand); | 2021 var leftHand = buildLeftHandValue(node.operand); |
| 2001 var binaryOperator = new ast.Name(operator[0]); | 2022 var binaryOperator = new ast.Name(operator[0]); |
| 2002 return leftHand.buildPostfixIncrement(binaryOperator, | 2023 return leftHand.buildPostfixIncrement(binaryOperator, |
| 2003 offset: node.offset, | 2024 offset: node.operator.offset, |
| 2004 voidContext: isInVoidContext(node), | 2025 voidContext: isInVoidContext(node), |
| 2005 interfaceTarget: scope.resolveInterfaceMethod(node.staticElement)); | 2026 interfaceTarget: scope.resolveInterfaceMethod(node.staticElement)); |
| 2006 | 2027 |
| 2007 default: | 2028 default: |
| 2008 return scope.internalError('Invalid postfix operator $operator'); | 2029 return scope.internalError('Invalid postfix operator $operator'); |
| 2009 } | 2030 } |
| 2010 } | 2031 } |
| 2011 | 2032 |
| 2012 ast.Expression visitPrefixExpression(PrefixExpression node) { | 2033 ast.Expression visitPrefixExpression(PrefixExpression node) { |
| 2013 String operator = node.operator.value(); | 2034 String operator = node.operator.value(); |
| (...skipping 1025 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 3039 if (list[i - 1].compareTo(item) == 0) { | 3060 if (list[i - 1].compareTo(item) == 0) { |
| 3040 ++deleted; | 3061 ++deleted; |
| 3041 } else if (deleted > 0) { | 3062 } else if (deleted > 0) { |
| 3042 list[i - deleted] = item; | 3063 list[i - deleted] = item; |
| 3043 } | 3064 } |
| 3044 } | 3065 } |
| 3045 if (deleted > 0) { | 3066 if (deleted > 0) { |
| 3046 list.length -= deleted; | 3067 list.length -= deleted; |
| 3047 } | 3068 } |
| 3048 } | 3069 } |
| OLD | NEW |