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

Side by Side Diff: lib/src/compiler/code_generator.dart

Issue 1910233002: fixes #516, nested cascade code generation (Closed) Base URL: git@github.com:dart-lang/dev_compiler.git@master
Patch Set: Created 4 years, 8 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
« no previous file with comments | « no previous file | lib/src/compiler/js_metalet.dart » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
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
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
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
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
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
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
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
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
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
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
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';
OLDNEW
« no previous file with comments | « no previous file | lib/src/compiler/js_metalet.dart » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698