OLD | NEW |
---|---|
1 // Copyright (c) 2015, the Dart project authors. Please see the AUTHORS file | 1 // Copyright (c) 2015, 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 import 'dart:collection' show HashMap, HashSet; | 5 import 'dart:collection' show HashMap, HashSet; |
6 | 6 |
7 import 'package:analyzer/analyzer.dart' hide ConstantEvaluator; | 7 import 'package:analyzer/analyzer.dart' hide ConstantEvaluator; |
8 import 'package:analyzer/dart/ast/ast.dart' hide ConstantEvaluator; | 8 import 'package:analyzer/dart/ast/ast.dart' hide ConstantEvaluator; |
9 import 'package:analyzer/dart/ast/token.dart' show Token, TokenType; | 9 import 'package:analyzer/dart/ast/token.dart' show Token, TokenType; |
10 import 'package:analyzer/dart/element/element.dart'; | 10 import 'package:analyzer/dart/element/element.dart'; |
(...skipping 63 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
74 Expression _cascadeTarget; | 74 Expression _cascadeTarget; |
75 | 75 |
76 /// The variable for the current catch clause | 76 /// The variable for the current catch clause |
77 SimpleIdentifier _catchParameter; | 77 SimpleIdentifier _catchParameter; |
78 | 78 |
79 /// In an async* function, this represents the stream controller parameter. | 79 /// In an async* function, this represents the stream controller parameter. |
80 JS.TemporaryId _asyncStarController; | 80 JS.TemporaryId _asyncStarController; |
81 | 81 |
82 final _privateNames = | 82 final _privateNames = |
83 new HashMap<LibraryElement, HashMap<String, JS.TemporaryId>>(); | 83 new HashMap<LibraryElement, HashMap<String, JS.TemporaryId>>(); |
84 final _temps = new HashMap<Element, JS.TemporaryId>(); | 84 final _initializingFormalTemps = |
85 new HashMap<ParameterElement, JS.TemporaryId>(); | |
85 | 86 |
86 final _dartxVar = new JS.Identifier('dartx'); | 87 final _dartxVar = new JS.Identifier('dartx'); |
87 final _runtimeLibVar = new JS.Identifier('dart'); | 88 final _runtimeLibVar = new JS.Identifier('dart'); |
88 final namedArgumentTemp = new JS.TemporaryId('opts'); | 89 final namedArgumentTemp = new JS.TemporaryId('opts'); |
89 | 90 |
90 final _hasDeferredSupertype = new HashSet<ClassElement>(); | 91 final _hasDeferredSupertype = new HashSet<ClassElement>(); |
91 | 92 |
92 /// The type provider from the current Analysis [context]. | 93 /// The type provider from the current Analysis [context]. |
93 final TypeProvider types; | 94 final TypeProvider types; |
94 | 95 |
(...skipping 1811 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
1906 var tearOff = element is MethodElement && !inInvocationContext(node); | 1907 var tearOff = element is MethodElement && !inInvocationContext(node); |
1907 var code = (tearOff) ? 'dart.bind(this, #)' : 'this.#'; | 1908 var code = (tearOff) ? 'dart.bind(this, #)' : 'this.#'; |
1908 return js.call(code, member); | 1909 return js.call(code, member); |
1909 } | 1910 } |
1910 | 1911 |
1911 if (element is ParameterElement) { | 1912 if (element is ParameterElement) { |
1912 return _emitParameter(element); | 1913 return _emitParameter(element); |
1913 } | 1914 } |
1914 | 1915 |
1915 if (element is TemporaryVariableElement) { | 1916 if (element is TemporaryVariableElement) { |
1916 if (name[0] == '#') { | 1917 return element.variable; |
vsm
2016/04/21 21:50:48
This doesn't match the return type of this functio
Jennifer Messerly
2016/04/21 21:53:25
JS.Expression visitSimpleIdentifier ... and we're
vsm
2016/04/21 22:06:22
Oh, I missed that TemporaryVariableElement is our
| |
1917 return new JS.InterpolatedExpression(name.substring(1)); | |
1918 } else { | |
1919 return _getTemp(element, name); | |
1920 } | |
1921 } | 1918 } |
1922 | 1919 |
1923 return new JS.Identifier(name); | 1920 return new JS.Identifier(name); |
1924 } | 1921 } |
1925 | 1922 |
1926 JS.Identifier _emitParameter(ParameterElement element, | 1923 JS.Identifier _emitParameter(ParameterElement element, |
1927 {bool declaration: false}) { | 1924 {bool declaration: false}) { |
1928 // initializing formal parameter, e.g. `Point(this._x)` | 1925 // initializing formal parameter, e.g. `Point(this._x)` |
1929 // TODO(jmesserly): type ref is not attached in this case. | 1926 // TODO(jmesserly): type ref is not attached in this case. |
1930 if (element.isInitializingFormal && element.isPrivate) { | 1927 if (element.isInitializingFormal && element.isPrivate) { |
1931 /// Rename private names so they don't shadow the private field symbol. | 1928 /// Rename private names so they don't shadow the private field symbol. |
1932 /// The renamer would handle this, but it would prefer to rename the | 1929 /// The renamer would handle this, but it would prefer to rename the |
1933 /// temporary used for the private symbol. Instead rename the parameter. | 1930 /// temporary used for the private symbol. Instead rename the parameter. |
1934 return _getTemp(element, '${element.name.substring(1)}'); | 1931 return _initializingFormalTemps.putIfAbsent( |
1932 element, () => new JS.TemporaryId(element.name.substring(1))); | |
1935 } | 1933 } |
1936 | 1934 |
1937 var type = declaration ? emitTypeRef(element.type) : null; | 1935 var type = declaration ? emitTypeRef(element.type) : null; |
1938 return new JS.Identifier(element.name, type: type); | 1936 return new JS.Identifier(element.name, type: type); |
1939 } | 1937 } |
1940 | 1938 |
1941 JS.TemporaryId _getTemp(Element key, String name) => | |
1942 _temps.putIfAbsent(key, () => new JS.TemporaryId(name)); | |
1943 | |
1944 List<Annotation> _parameterMetadata(FormalParameter p) => | 1939 List<Annotation> _parameterMetadata(FormalParameter p) => |
1945 (p is NormalFormalParameter) | 1940 (p is NormalFormalParameter) |
1946 ? p.metadata | 1941 ? p.metadata |
1947 : (p as DefaultFormalParameter).parameter.metadata; | 1942 : (p as DefaultFormalParameter).parameter.metadata; |
1948 | 1943 |
1949 JS.ArrayInitializer _emitTypeNames(List<DartType> types, | 1944 JS.ArrayInitializer _emitTypeNames(List<DartType> types, |
1950 [List<FormalParameter> parameters]) { | 1945 [List<FormalParameter> parameters]) { |
1951 var result = <JS.Expression>[]; | 1946 var result = <JS.Expression>[]; |
1952 for (int i = 0; i < types.length; ++i) { | 1947 for (int i = 0; i < types.length; ++i) { |
1953 var metadata = | 1948 var metadata = |
(...skipping 125 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
2079 Expression left, Expression right, String op, MethodElement element, | 2074 Expression left, Expression right, String op, MethodElement element, |
2080 {Expression context}) { | 2075 {Expression context}) { |
2081 if (op == '??') { | 2076 if (op == '??') { |
2082 // Desugar `l ??= r` as ((x) => x == null ? l = r : x)(l) | 2077 // Desugar `l ??= r` as ((x) => x == null ? l = r : x)(l) |
2083 // Note that if `x` contains subexpressions, we need to ensure those | 2078 // Note that if `x` contains subexpressions, we need to ensure those |
2084 // are also evaluated only once. This is similar to desguaring for | 2079 // are also evaluated only once. This is similar to desguaring for |
2085 // postfix expressions like `i++`. | 2080 // postfix expressions like `i++`. |
2086 | 2081 |
2087 // Handle the left hand side, to ensure each of its subexpressions are | 2082 // Handle the left hand side, to ensure each of its subexpressions are |
2088 // evaluated only once. | 2083 // evaluated only once. |
2089 var vars = <String, JS.Expression>{}; | 2084 var vars = <JS.MetaLetVariable, JS.Expression>{}; |
2090 var x = _bindLeftHandSide(vars, left, context: left); | 2085 var x = _bindLeftHandSide(vars, left, context: left); |
2091 // Capture the result of evaluating the left hand side in a temp. | 2086 // Capture the result of evaluating the left hand side in a temp. |
2092 var t = _bindValue(vars, 't', x, context: x); | 2087 var t = _bindValue(vars, 't', x, context: x); |
2093 return new JS.MetaLet(vars, [ | 2088 return new JS.MetaLet(vars, [ |
2094 js.call('# == null ? # : #', [_visit(t), _emitSet(x, right), _visit(t)]) | 2089 js.call('# == null ? # : #', [_visit(t), _emitSet(x, right), _visit(t)]) |
2095 ]); | 2090 ]); |
2096 } | 2091 } |
2097 | 2092 |
2098 // Desugar `x += y` as `x = x + y`, ensuring that if `x` has subexpressions | 2093 // Desugar `x += y` as `x = x + y`, ensuring that if `x` has subexpressions |
2099 // (for example, x is IndexExpression) we evaluate those once. | 2094 // (for example, x is IndexExpression) we evaluate those once. |
2100 var vars = <String, JS.Expression>{}; | 2095 var vars = <JS.MetaLetVariable, JS.Expression>{}; |
2101 var lhs = _bindLeftHandSide(vars, left, context: context); | 2096 var lhs = _bindLeftHandSide(vars, left, context: context); |
2102 var inc = AstBuilder.binaryExpression(lhs, op, right); | 2097 var inc = AstBuilder.binaryExpression(lhs, op, right); |
2103 inc.staticElement = element; | 2098 inc.staticElement = element; |
2104 inc.staticType = getStaticType(left); | 2099 inc.staticType = getStaticType(left); |
2105 return new JS.MetaLet(vars, [_emitSet(lhs, inc)]); | 2100 return new JS.MetaLet(vars, [_emitSet(lhs, inc)]); |
2106 } | 2101 } |
2107 | 2102 |
2108 JS.Expression _emitSet(Expression lhs, Expression rhs) { | 2103 JS.Expression _emitSet(Expression lhs, Expression rhs) { |
2109 if (lhs is IndexExpression) { | 2104 if (lhs is IndexExpression) { |
2110 var target = _getTarget(lhs); | 2105 var target = _getTarget(lhs); |
(...skipping 28 matching lines...) Expand all Loading... | |
2139 | 2134 |
2140 JS.Expression _emitNullSafeSet(PropertyAccess node, Expression right) { | 2135 JS.Expression _emitNullSafeSet(PropertyAccess node, Expression right) { |
2141 // Emit `obj?.prop = expr` as: | 2136 // Emit `obj?.prop = expr` as: |
2142 // | 2137 // |
2143 // (_ => _ == null ? null : _.prop = expr)(obj). | 2138 // (_ => _ == null ? null : _.prop = expr)(obj). |
2144 // | 2139 // |
2145 // We could use a helper, e.g.: `nullSafeSet(e1, _ => _.v = e2)` | 2140 // We could use a helper, e.g.: `nullSafeSet(e1, _ => _.v = e2)` |
2146 // | 2141 // |
2147 // However with MetaLet, we get clean code in statement or void context, | 2142 // However with MetaLet, we get clean code in statement or void context, |
2148 // or when one of the expressions is stateless, which seems common. | 2143 // or when one of the expressions is stateless, which seems common. |
2149 var vars = <String, JS.Expression>{}; | 2144 var vars = <JS.MetaLetVariable, JS.Expression>{}; |
2150 var left = _bindValue(vars, 'l', node.target); | 2145 var left = _bindValue(vars, 'l', node.target); |
2151 var body = js.call('# == null ? null : #', | 2146 var body = js.call('# == null ? null : #', |
2152 [_visit(left), _emitSet(_stripNullAwareOp(node, left), right)]); | 2147 [_visit(left), _emitSet(_stripNullAwareOp(node, left), right)]); |
2153 return new JS.MetaLet(vars, [body]); | 2148 return new JS.MetaLet(vars, [body]); |
2154 } | 2149 } |
2155 | 2150 |
2156 @override | 2151 @override |
2157 JS.Block visitExpressionFunctionBody(ExpressionFunctionBody node) { | 2152 JS.Block visitExpressionFunctionBody(ExpressionFunctionBody node) { |
2158 var savedFunction = _currentFunction; | 2153 var savedFunction = _currentFunction; |
2159 _currentFunction = node; | 2154 _currentFunction = node; |
(...skipping 555 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
2715 code = '${bang}dart.equals(#, #)'; | 2710 code = '${bang}dart.equals(#, #)'; |
2716 } | 2711 } |
2717 return js.call(code, [_visit(left), _visit(right)]); | 2712 return js.call(code, [_visit(left), _visit(right)]); |
2718 } | 2713 } |
2719 | 2714 |
2720 if (op.type.lexeme == '??') { | 2715 if (op.type.lexeme == '??') { |
2721 // TODO(jmesserly): leave RHS for debugging? | 2716 // TODO(jmesserly): leave RHS for debugging? |
2722 // This should be a hint or warning for dead code. | 2717 // This should be a hint or warning for dead code. |
2723 if (!isNullable(left)) return _visit(left); | 2718 if (!isNullable(left)) return _visit(left); |
2724 | 2719 |
2725 var vars = <String, JS.Expression>{}; | 2720 var vars = <JS.MetaLetVariable, JS.Expression>{}; |
2726 // Desugar `l ?? r` as `l != null ? l : r` | 2721 // Desugar `l ?? r` as `l != null ? l : r` |
2727 var l = _visit(_bindValue(vars, 'l', left, context: left)); | 2722 var l = _visit(_bindValue(vars, 'l', left, context: left)); |
2728 return new JS.MetaLet(vars, [ | 2723 return new JS.MetaLet(vars, [ |
2729 js.call('# != null ? # : #', [l, l, _visit(right)]) | 2724 js.call('# != null ? # : #', [l, l, _visit(right)]) |
2730 ]); | 2725 ]); |
2731 } | 2726 } |
2732 | 2727 |
2733 if (binaryOperationIsPrimitive(leftType, rightType) || | 2728 if (binaryOperationIsPrimitive(leftType, rightType) || |
2734 leftType == types.stringType && op.type == TokenType.PLUS) { | 2729 leftType == types.stringType && op.type == TokenType.PLUS) { |
2735 // special cases where we inline the operation | 2730 // special cases where we inline the operation |
(...skipping 28 matching lines...) Expand all Loading... | |
2764 if (_isNull(left) || _isNull(right)) return true; | 2759 if (_isNull(left) || _isNull(right)) return true; |
2765 | 2760 |
2766 var leftType = _canonicalizeNumTypes(getStaticType(left)); | 2761 var leftType = _canonicalizeNumTypes(getStaticType(left)); |
2767 var rightType = _canonicalizeNumTypes(getStaticType(right)); | 2762 var rightType = _canonicalizeNumTypes(getStaticType(right)); |
2768 return isPrimitiveType(leftType) && leftType == rightType; | 2763 return isPrimitiveType(leftType) && leftType == rightType; |
2769 } | 2764 } |
2770 | 2765 |
2771 bool _isNull(Expression expr) => expr is NullLiteral; | 2766 bool _isNull(Expression expr) => expr is NullLiteral; |
2772 | 2767 |
2773 SimpleIdentifier _createTemporary(String name, DartType type, | 2768 SimpleIdentifier _createTemporary(String name, DartType type, |
2774 {bool nullable: true}) { | 2769 {bool nullable: true, JS.Expression variable}) { |
2775 // We use an invalid source location to signal that this is a temporary. | 2770 // We use an invalid source location to signal that this is a temporary. |
2776 // See [_isTemporary]. | 2771 // See [_isTemporary]. |
2777 // TODO(jmesserly): alternatives are | 2772 // TODO(jmesserly): alternatives are |
2778 // * (ab)use Element.isSynthetic, which isn't currently used for | 2773 // * (ab)use Element.isSynthetic, which isn't currently used for |
2779 // LocalVariableElementImpl, so we could repurpose to mean "temp". | 2774 // LocalVariableElementImpl, so we could repurpose to mean "temp". |
2780 // * add a new property to LocalVariableElementImpl. | 2775 // * add a new property to LocalVariableElementImpl. |
2781 // * create a new subtype of LocalVariableElementImpl to mark a temp. | 2776 // * create a new subtype of LocalVariableElementImpl to mark a temp. |
2782 var id = | 2777 var id = |
2783 new SimpleIdentifier(new StringToken(TokenType.IDENTIFIER, name, -1)); | 2778 new SimpleIdentifier(new StringToken(TokenType.IDENTIFIER, name, -1)); |
2784 id.staticElement = new TemporaryVariableElement.forNode(id); | 2779 |
2780 variable ??= new JS.TemporaryId(name); | |
2781 | |
2782 id.staticElement = new TemporaryVariableElement.forNode(id, variable); | |
2785 id.staticType = type; | 2783 id.staticType = type; |
2786 DynamicInvoke.set(id, type.isDynamic); | 2784 DynamicInvoke.set(id, type.isDynamic); |
2787 addTemporaryVariable(id.staticElement, nullable: nullable); | 2785 addTemporaryVariable(id.staticElement, nullable: nullable); |
2788 return id; | 2786 return id; |
2789 } | 2787 } |
2790 | 2788 |
2791 JS.Expression _emitConst(JS.Expression expr()) { | 2789 JS.Expression _emitConst(JS.Expression expr()) { |
2792 // TODO(jmesserly): emit the constants at top level if possible. | 2790 // TODO(jmesserly): emit the constants at top level if possible. |
2793 // This wasn't quite working, so disabled for now. | 2791 // This wasn't quite working, so disabled for now. |
2794 return js.call('dart.const(#)', expr()); | 2792 return js.call('dart.const(#)', expr()); |
2795 } | 2793 } |
2796 | 2794 |
2797 /// Returns a new expression, which can be be used safely *once* on the | 2795 /// Returns a new expression, which can be be used safely *once* on the |
2798 /// left hand side, and *once* on the right side of an assignment. | 2796 /// left hand side, and *once* on the right side of an assignment. |
2799 /// For example: `expr1[expr2] += y` can be compiled as | 2797 /// For example: `expr1[expr2] += y` can be compiled as |
2800 /// `expr1[expr2] = expr1[expr2] + y`. | 2798 /// `expr1[expr2] = expr1[expr2] + y`. |
2801 /// | 2799 /// |
2802 /// The temporary scope will ensure `expr1` and `expr2` are only evaluated | 2800 /// The temporary scope will ensure `expr1` and `expr2` are only evaluated |
2803 /// once: `((x1, x2) => x1[x2] = x1[x2] + y)(expr1, expr2)`. | 2801 /// once: `((x1, x2) => x1[x2] = x1[x2] + y)(expr1, expr2)`. |
2804 /// | 2802 /// |
2805 /// If the expression does not end up using `x1` or `x2` more than once, or | 2803 /// If the expression does not end up using `x1` or `x2` more than once, or |
2806 /// if those expressions can be treated as stateless (e.g. they are | 2804 /// if those expressions can be treated as stateless (e.g. they are |
2807 /// non-mutated variables), then the resulting code will be simplified | 2805 /// non-mutated variables), then the resulting code will be simplified |
2808 /// automatically. | 2806 /// automatically. |
2809 /// | 2807 /// |
2810 /// [scope] can be mutated to contain any new temporaries that were created, | 2808 /// [scope] can be mutated to contain any new temporaries that were created, |
2811 /// unless [expr] is a SimpleIdentifier, in which case a temporary is not | 2809 /// unless [expr] is a SimpleIdentifier, in which case a temporary is not |
2812 /// needed. | 2810 /// needed. |
2813 Expression _bindLeftHandSide( | 2811 Expression _bindLeftHandSide( |
2814 Map<String, JS.Expression> scope, Expression expr, | 2812 Map<JS.MetaLetVariable, JS.Expression> scope, Expression expr, |
2815 {Expression context}) { | 2813 {Expression context}) { |
2816 Expression result; | 2814 Expression result; |
2817 if (expr is IndexExpression) { | 2815 if (expr is IndexExpression) { |
2818 IndexExpression index = expr; | 2816 IndexExpression index = expr; |
2819 result = new IndexExpression.forTarget( | 2817 result = new IndexExpression.forTarget( |
2820 _bindValue(scope, 'o', index.target, context: context), | 2818 _bindValue(scope, 'o', index.target, context: context), |
2821 index.leftBracket, | 2819 index.leftBracket, |
2822 _bindValue(scope, 'i', index.index, context: context), | 2820 _bindValue(scope, 'i', index.index, context: context), |
2823 index.rightBracket); | 2821 index.rightBracket); |
2824 } else if (expr is PropertyAccess) { | 2822 } else if (expr is PropertyAccess) { |
(...skipping 23 matching lines...) Expand all Loading... | |
2848 /// Creates a temporary to contain the value of [expr]. The temporary can be | 2846 /// Creates a temporary to contain the value of [expr]. The temporary can be |
2849 /// used multiple times in the resulting expression. For example: | 2847 /// used multiple times in the resulting expression. For example: |
2850 /// `expr ** 2` could be compiled as `expr * expr`. The temporary scope will | 2848 /// `expr ** 2` could be compiled as `expr * expr`. The temporary scope will |
2851 /// ensure `expr` is only evaluated once: `(x => x * x)(expr)`. | 2849 /// ensure `expr` is only evaluated once: `(x => x * x)(expr)`. |
2852 /// | 2850 /// |
2853 /// If the expression does not end up using `x` more than once, or if those | 2851 /// If the expression does not end up using `x` more than once, or if those |
2854 /// expressions can be treated as stateless (e.g. they are non-mutated | 2852 /// expressions can be treated as stateless (e.g. they are non-mutated |
2855 /// variables), then the resulting code will be simplified automatically. | 2853 /// variables), then the resulting code will be simplified automatically. |
2856 /// | 2854 /// |
2857 /// [scope] will be mutated to contain the new temporary's initialization. | 2855 /// [scope] will be mutated to contain the new temporary's initialization. |
2858 Expression _bindValue( | 2856 Expression _bindValue(Map<JS.MetaLetVariable, JS.Expression> scope, |
2859 Map<String, JS.Expression> scope, String name, Expression expr, | 2857 String name, Expression expr, |
2860 {Expression context}) { | 2858 {Expression context}) { |
2861 // No need to do anything for stateless expressions. | 2859 // No need to do anything for stateless expressions. |
2862 if (isStateless(_currentFunction, expr, context)) return expr; | 2860 if (isStateless(_currentFunction, expr, context)) return expr; |
2863 | 2861 |
2864 var t = _createTemporary('#$name', getStaticType(expr)); | 2862 var variable = new JS.MetaLetVariable(name); |
2865 scope[name] = _visit(expr); | 2863 var t = _createTemporary(name, getStaticType(expr), variable: variable); |
2864 scope[variable] = _visit(expr); | |
2866 return t; | 2865 return t; |
2867 } | 2866 } |
2868 | 2867 |
2869 /// Desugars postfix increment. | 2868 /// Desugars postfix increment. |
2870 /// | 2869 /// |
2871 /// In the general case [expr] can be one of [IndexExpression], | 2870 /// In the general case [expr] can be one of [IndexExpression], |
2872 /// [PrefixExpression] or [PropertyAccess] and we need to | 2871 /// [PrefixExpression] or [PropertyAccess] and we need to |
2873 /// ensure sub-expressions are evaluated once. | 2872 /// ensure sub-expressions are evaluated once. |
2874 /// | 2873 /// |
2875 /// We also need to ensure we can return the original value of the expression, | 2874 /// We also need to ensure we can return the original value of the expression, |
(...skipping 17 matching lines...) Expand all Loading... | |
2893 if (unaryOperationIsPrimitive(dispatchType)) { | 2892 if (unaryOperationIsPrimitive(dispatchType)) { |
2894 if (!isNullable(expr)) { | 2893 if (!isNullable(expr)) { |
2895 return js.call('#$op', _visit(expr)); | 2894 return js.call('#$op', _visit(expr)); |
2896 } | 2895 } |
2897 } | 2896 } |
2898 | 2897 |
2899 assert(op.lexeme == '++' || op.lexeme == '--'); | 2898 assert(op.lexeme == '++' || op.lexeme == '--'); |
2900 | 2899 |
2901 // Handle the left hand side, to ensure each of its subexpressions are | 2900 // Handle the left hand side, to ensure each of its subexpressions are |
2902 // evaluated only once. | 2901 // evaluated only once. |
2903 var vars = <String, JS.Expression>{}; | 2902 var vars = <JS.MetaLetVariable, JS.Expression>{}; |
2904 var left = _bindLeftHandSide(vars, expr, context: expr); | 2903 var left = _bindLeftHandSide(vars, expr, context: expr); |
2905 | 2904 |
2906 // Desugar `x++` as `(x1 = x0 + 1, x0)` where `x0` is the original value | 2905 // Desugar `x++` as `(x1 = x0 + 1, x0)` where `x0` is the original value |
2907 // and `x1` is the new value for `x`. | 2906 // and `x1` is the new value for `x`. |
2908 var x = _bindValue(vars, 'x', left, context: expr); | 2907 var x = _bindValue(vars, 'x', left, context: expr); |
2909 | 2908 |
2910 var one = AstBuilder.integerLiteral(1)..staticType = types.intType; | 2909 var one = AstBuilder.integerLiteral(1)..staticType = types.intType; |
2911 var increment = AstBuilder.binaryExpression(x, op.lexeme[0], one) | 2910 var increment = AstBuilder.binaryExpression(x, op.lexeme[0], one) |
2912 ..staticElement = node.staticElement | 2911 ..staticElement = node.staticElement |
2913 ..staticType = getStaticType(expr); | 2912 ..staticType = getStaticType(expr); |
2914 | 2913 |
2915 var body = <JS.Expression>[_emitSet(left, increment), _visit(x)]; | 2914 var body = <JS.Expression>[_emitSet(left, increment), _visit(x)]; |
2916 return new JS.MetaLet(vars, body, statelessResult: true); | 2915 return new JS.MetaLet(vars, body, statelessResult: true); |
2917 } | 2916 } |
2918 | 2917 |
2919 @override | 2918 @override |
2920 JS.Expression visitPrefixExpression(PrefixExpression node) { | 2919 JS.Expression visitPrefixExpression(PrefixExpression node) { |
2921 var op = node.operator; | 2920 var op = node.operator; |
2922 var expr = node.operand; | 2921 var expr = node.operand; |
2923 | 2922 |
2924 var dispatchType = getStaticType(expr); | 2923 var dispatchType = getStaticType(expr); |
2925 if (unaryOperationIsPrimitive(dispatchType)) { | 2924 if (unaryOperationIsPrimitive(dispatchType)) { |
2926 if (!isNullable(expr)) { | 2925 if (!isNullable(expr)) { |
2927 return js.call('$op#', _visit(expr)); | 2926 return js.call('$op#', _visit(expr)); |
2928 } else if (op.lexeme == '++' || op.lexeme == '--') { | 2927 } else if (op.lexeme == '++' || op.lexeme == '--') { |
2929 // We need a null check, so the increment must be expanded out. | 2928 // We need a null check, so the increment must be expanded out. |
2930 var vars = <String, JS.Expression>{}; | 2929 var vars = <JS.MetaLetVariable, JS.Expression>{}; |
2931 var x = _bindLeftHandSide(vars, expr, context: expr); | 2930 var x = _bindLeftHandSide(vars, expr, context: expr); |
2932 | 2931 |
2933 var one = AstBuilder.integerLiteral(1)..staticType = types.intType; | 2932 var one = AstBuilder.integerLiteral(1)..staticType = types.intType; |
2934 var increment = AstBuilder.binaryExpression(x, op.lexeme[0], one) | 2933 var increment = AstBuilder.binaryExpression(x, op.lexeme[0], one) |
2935 ..staticElement = node.staticElement | 2934 ..staticElement = node.staticElement |
2936 ..staticType = getStaticType(expr); | 2935 ..staticType = getStaticType(expr); |
2937 | 2936 |
2938 return new JS.MetaLet(vars, [_emitSet(x, increment)]); | 2937 return new JS.MetaLet(vars, [_emitSet(x, increment)]); |
2939 } else { | 2938 } else { |
2940 return js.call('$op#', notNull(expr)); | 2939 return js.call('$op#', notNull(expr)); |
(...skipping 12 matching lines...) Expand all Loading... | |
2953 return _emitSend(expr, op.lexeme[0], []); | 2952 return _emitSend(expr, op.lexeme[0], []); |
2954 } | 2953 } |
2955 | 2954 |
2956 // Cascades can contain [IndexExpression], [MethodInvocation] and | 2955 // Cascades can contain [IndexExpression], [MethodInvocation] and |
2957 // [PropertyAccess]. The code generation for those is handled in their | 2956 // [PropertyAccess]. The code generation for those is handled in their |
2958 // respective visit methods. | 2957 // respective visit methods. |
2959 @override | 2958 @override |
2960 JS.Node visitCascadeExpression(CascadeExpression node) { | 2959 JS.Node visitCascadeExpression(CascadeExpression node) { |
2961 var savedCascadeTemp = _cascadeTarget; | 2960 var savedCascadeTemp = _cascadeTarget; |
2962 | 2961 |
2963 var vars = <String, JS.Expression>{}; | 2962 var vars = <JS.MetaLetVariable, JS.Expression>{}; |
2964 _cascadeTarget = _bindValue(vars, '_', node.target, context: node); | 2963 _cascadeTarget = _bindValue(vars, '_', node.target, context: node); |
2965 var sections = _visitList(node.cascadeSections) as List<JS.Expression>; | 2964 var sections = _visitList(node.cascadeSections) as List<JS.Expression>; |
2966 sections.add(_visit(_cascadeTarget)); | 2965 sections.add(_visit(_cascadeTarget)); |
2967 var result = new JS.MetaLet(vars, sections, statelessResult: true); | 2966 var result = new JS.MetaLet(vars, sections, statelessResult: true); |
2968 _cascadeTarget = savedCascadeTemp; | 2967 _cascadeTarget = savedCascadeTemp; |
2969 return result; | 2968 return result; |
2970 } | 2969 } |
2971 | 2970 |
2972 @override | 2971 @override |
2973 visitParenthesizedExpression(ParenthesizedExpression node) => | 2972 visitParenthesizedExpression(ParenthesizedExpression node) => |
(...skipping 798 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
3772 | 3771 |
3773 // TODO(jacobr): we would like to do something like the following | 3772 // TODO(jacobr): we would like to do something like the following |
3774 // but we don't have summary support yet. | 3773 // but we don't have summary support yet. |
3775 // bool _supportJsExtensionMethod(AnnotatedNode node) => | 3774 // bool _supportJsExtensionMethod(AnnotatedNode node) => |
3776 // _getAnnotation(node, "SupportJsExtensionMethod") != null; | 3775 // _getAnnotation(node, "SupportJsExtensionMethod") != null; |
3777 | 3776 |
3778 /// A special kind of element created by the compiler, signifying a temporary | 3777 /// A special kind of element created by the compiler, signifying a temporary |
3779 /// variable. These objects use instance equality, and should be shared | 3778 /// variable. These objects use instance equality, and should be shared |
3780 /// everywhere in the tree where they are treated as the same variable. | 3779 /// everywhere in the tree where they are treated as the same variable. |
3781 class TemporaryVariableElement extends LocalVariableElementImpl { | 3780 class TemporaryVariableElement extends LocalVariableElementImpl { |
3782 TemporaryVariableElement.forNode(Identifier name) : super.forNode(name); | 3781 final JS.Expression variable; |
3782 TemporaryVariableElement.forNode(Identifier name, this.variable) | |
3783 : super.forNode(name); | |
3783 | 3784 |
3784 int get hashCode => identityHashCode(this); | 3785 int get hashCode => identityHashCode(this); |
3785 bool operator ==(Object other) => identical(this, other); | 3786 bool operator ==(Object other) => identical(this, other); |
3786 } | 3787 } |
3787 | 3788 |
3788 bool isLibraryPrefix(Expression node) => | 3789 bool isLibraryPrefix(Expression node) => |
3789 node is SimpleIdentifier && node.staticElement is PrefixElement; | 3790 node is SimpleIdentifier && node.staticElement is PrefixElement; |
3790 | 3791 |
3791 LibraryElement _getLibrary(AnalysisContext c, String uri) => | 3792 LibraryElement _getLibrary(AnalysisContext c, String uri) => |
3792 c.computeLibraryElement(c.sourceFactory.forUri(uri)); | 3793 c.computeLibraryElement(c.sourceFactory.forUri(uri)); |
3793 | 3794 |
3794 bool _isDartRuntime(LibraryElement l) => | 3795 bool _isDartRuntime(LibraryElement l) => |
3795 l.isInSdk && l.source.uri.toString() == 'dart:_runtime'; | 3796 l.isInSdk && l.source.uri.toString() == 'dart:_runtime'; |
OLD | NEW |