Index: pkg/fasta/lib/src/kernel/frontend_accessors.dart |
diff --git a/pkg/fasta/lib/src/kernel/frontend_accessors.dart b/pkg/fasta/lib/src/kernel/frontend_accessors.dart |
new file mode 100644 |
index 0000000000000000000000000000000000000000..86a44b09d0e3a4af9734e923a63970021d180828 |
--- /dev/null |
+++ b/pkg/fasta/lib/src/kernel/frontend_accessors.dart |
@@ -0,0 +1,429 @@ |
+// Copyright (c) 2016, the Dart project authors. Please see the AUTHORS file |
+// for details. All rights reserved. Use of this source code is governed by a |
+// BSD-style license that can be found in the LICENSE file. |
+ |
+// Note: copied from package:kernel at revision 7346348. |
+ |
+/// A library to help transform compounds and null-aware accessors into |
+/// let expressions. |
+library kernel.frontend.accessors; |
+ |
+import 'package:kernel/ast.dart'; |
+ |
+abstract class Accessor { |
+ Expression buildSimpleRead() { |
+ return _finish(_makeSimpleRead()); |
+ } |
+ |
+ /// Returns an assignment to the accessor. |
+ /// |
+ /// The returned expression evaluates to the assigned value, unless |
+ /// [voidContext] is true, in which case it may evaluate to anything. |
+ Expression buildAssignment(Expression value, {bool voidContext: false}) { |
+ return _finish(_makeSimpleWrite(value, voidContext)); |
+ } |
+ |
+ Expression buildNullAwareAssignment(Expression value, DartType type, |
+ {bool voidContext: false}) { |
+ if (voidContext) { |
+ return _finish(new ConditionalExpression(buildIsNull(_makeRead()), |
+ _makeWrite(value, voidContext), new NullLiteral(), type)); |
+ } |
+ var tmp = new VariableDeclaration.forValue(_makeRead()); |
+ return _finish(makeLet( |
+ tmp, |
+ new ConditionalExpression(buildIsNull(new VariableGet(tmp)), |
+ _makeWrite(value, voidContext), new VariableGet(tmp), type))); |
+ } |
+ |
+ Expression buildCompoundAssignment(Name binaryOperator, Expression value, |
+ {bool voidContext: false, Procedure interfaceTarget}) { |
+ return _finish(_makeWrite( |
+ makeBinary(_makeRead(), binaryOperator, interfaceTarget, value), |
+ voidContext)); |
+ } |
+ |
+ Expression buildPrefixIncrement(Name binaryOperator, |
+ {bool voidContext: false, Procedure interfaceTarget}) { |
+ return buildCompoundAssignment(binaryOperator, new IntLiteral(1), |
+ voidContext: voidContext, interfaceTarget: interfaceTarget); |
+ } |
+ |
+ Expression buildPostfixIncrement(Name binaryOperator, |
+ {bool voidContext: false, Procedure interfaceTarget}) { |
+ if (voidContext) { |
+ return buildPrefixIncrement(binaryOperator, |
+ voidContext: true, interfaceTarget: interfaceTarget); |
+ } |
+ var value = new VariableDeclaration.forValue(_makeRead()); |
+ valueAccess() => new VariableGet(value); |
+ var dummy = new VariableDeclaration.forValue(_makeWrite( |
+ makeBinary( |
+ valueAccess(), binaryOperator, interfaceTarget, new IntLiteral(1)), |
+ true)); |
+ return _finish(makeLet(value, makeLet(dummy, valueAccess()))); |
+ } |
+ |
+ Expression _makeSimpleRead() => _makeRead(); |
+ |
+ Expression _makeSimpleWrite(Expression value, bool voidContext) { |
+ return _makeWrite(value, voidContext); |
+ } |
+ |
+ Expression _makeRead(); |
+ |
+ Expression _makeWrite(Expression value, bool voidContext); |
+ |
+ Expression _finish(Expression body) => body; |
+ |
+ makeInvalidRead() => new InvalidExpression(); |
+ |
+ makeInvalidWrite(Expression value) => wrapInvalid(value); |
+} |
+ |
+class VariableAccessor extends Accessor { |
+ VariableDeclaration variable; |
+ DartType promotedType; |
+ |
+ VariableAccessor(this.variable, [this.promotedType]); |
+ |
+ VariableAccessor.internal(this.variable, this.promotedType); |
+ |
+ _makeRead() => new VariableGet(variable, promotedType); |
+ |
+ _makeWrite(Expression value, bool voidContext) { |
+ return variable.isFinal || variable.isConst |
+ ? makeInvalidWrite(value) |
+ : new VariableSet(variable, value); |
+ } |
+} |
+ |
+class PropertyAccessor extends Accessor { |
+ VariableDeclaration _receiverVariable; |
+ Expression receiver; |
+ Name name; |
+ Member getter, setter; |
+ |
+ static Accessor make( |
+ Expression receiver, Name name, Member getter, Member setter) { |
+ if (receiver is ThisExpression) { |
+ return new ThisPropertyAccessor(name, getter, setter); |
+ } else { |
+ return new PropertyAccessor.internal(receiver, name, getter, setter); |
+ } |
+ } |
+ |
+ PropertyAccessor.internal( |
+ this.receiver, this.name, this.getter, this.setter); |
+ |
+ _makeSimpleRead() => new PropertyGet(receiver, name, getter); |
+ _makeSimpleWrite(Expression value, bool voidContext) { |
+ return new PropertySet(receiver, name, value, setter); |
+ } |
+ |
+ receiverAccess() { |
+ _receiverVariable ??= new VariableDeclaration.forValue(receiver); |
+ return new VariableGet(_receiverVariable); |
+ } |
+ |
+ _makeRead() => new PropertyGet(receiverAccess(), name, getter); |
+ |
+ _makeWrite(Expression value, bool voidContext) { |
+ return new PropertySet(receiverAccess(), name, value, setter); |
+ } |
+ |
+ _finish(Expression body) => makeLet(_receiverVariable, body); |
+} |
+ |
+/// Special case of [PropertyAccessor] to avoid creating an indirect access to |
+/// 'this'. |
+class ThisPropertyAccessor extends Accessor { |
+ Name name; |
+ Member getter, setter; |
+ |
+ ThisPropertyAccessor(this.name, this.getter, this.setter); |
+ |
+ _makeRead() => new PropertyGet(new ThisExpression(), name, getter); |
+ |
+ _makeWrite(Expression value, bool voidContext) { |
+ return new PropertySet(new ThisExpression(), name, value, setter); |
+ } |
+} |
+ |
+class NullAwarePropertyAccessor extends Accessor { |
+ VariableDeclaration receiver; |
+ Name name; |
+ Member getter, setter; |
+ DartType type; |
+ |
+ NullAwarePropertyAccessor( |
+ Expression receiver, this.name, this.getter, this.setter, this.type) |
+ : this.receiver = makeOrReuseVariable(receiver); |
+ |
+ receiverAccess() => new VariableGet(receiver); |
+ |
+ _makeRead() => new PropertyGet(receiverAccess(), name, getter); |
+ |
+ _makeWrite(Expression value, bool voidContext) { |
+ return new PropertySet(receiverAccess(), name, value, setter); |
+ } |
+ |
+ _finish(Expression body) => makeLet( |
+ receiver, |
+ new ConditionalExpression( |
+ buildIsNull(receiverAccess()), new NullLiteral(), body, type)); |
+} |
+ |
+class SuperPropertyAccessor extends Accessor { |
+ Name name; |
+ Member getter, setter; |
+ |
+ SuperPropertyAccessor(this.name, this.getter, this.setter); |
+ |
+ _makeRead() { |
+ if (getter == null) return makeInvalidRead(); |
+ // TODO(ahe): Use [DirectPropertyGet] when possible. |
+ Expression result = new DirectPropertyGet(new ThisExpression(), getter); |
+ result = new SuperPropertyGet(name, getter); |
+ return result; |
+ } |
+ |
+ _makeWrite(Expression value, bool voidContext) { |
+ if (setter == null) return makeInvalidWrite(value); |
+ // TODO(ahe): Use [DirectPropertySet] when possible. |
+ Expression result = |
+ new DirectPropertySet(new ThisExpression(), setter, value); |
+ result = new SuperPropertySet(name, value, setter); |
+ return result; |
+ } |
+} |
+ |
+final Name _indexGet = new Name('[]'); |
+final Name _indexSet = new Name('[]='); |
+ |
+class IndexAccessor extends Accessor { |
+ Expression receiver; |
+ Expression index; |
+ VariableDeclaration receiverVariable; |
+ VariableDeclaration indexVariable; |
+ Procedure getter, setter; |
+ |
+ static Accessor make(Expression receiver, Expression index, Procedure getter, |
+ Procedure setter) { |
+ if (receiver is ThisExpression) { |
+ return new ThisIndexAccessor(index, getter, setter); |
+ } else { |
+ return new IndexAccessor.internal(receiver, index, getter, setter); |
+ } |
+ } |
+ |
+ IndexAccessor.internal(this.receiver, this.index, this.getter, this.setter); |
+ |
+ _makeSimpleRead() => new MethodInvocation( |
+ receiver, _indexGet, new Arguments(<Expression>[index]), getter); |
+ |
+ _makeSimpleWrite(Expression value, bool voidContext) { |
+ if (!voidContext) return _makeWriteAndReturn(value); |
+ return new MethodInvocation( |
+ receiver, _indexSet, new Arguments(<Expression>[index, value]), setter); |
+ } |
+ |
+ receiverAccess() { |
+ // We cannot reuse the receiver if it is a variable since it might be |
+ // reassigned in the index expression. |
+ receiverVariable ??= new VariableDeclaration.forValue(receiver); |
+ return new VariableGet(receiverVariable); |
+ } |
+ |
+ indexAccess() { |
+ indexVariable ??= new VariableDeclaration.forValue(index); |
+ return new VariableGet(indexVariable); |
+ } |
+ |
+ _makeRead() { |
+ return new MethodInvocation(receiverAccess(), _indexGet, |
+ new Arguments(<Expression>[indexAccess()]), getter); |
+ } |
+ |
+ _makeWrite(Expression value, bool voidContext) { |
+ if (!voidContext) return _makeWriteAndReturn(value); |
+ return new MethodInvocation(receiverAccess(), _indexSet, |
+ new Arguments(<Expression>[indexAccess(), value]), setter); |
+ } |
+ |
+ _makeWriteAndReturn(Expression value) { |
+ // The call to []= does not return the value like direct-style assignments |
+ // do. We need to bind the value in a let. |
+ var valueVariable = new VariableDeclaration.forValue(value); |
+ var dummy = new VariableDeclaration.forValue(new MethodInvocation( |
+ receiverAccess(), |
+ _indexSet, |
+ new Arguments( |
+ <Expression>[indexAccess(), new VariableGet(valueVariable)]), |
+ setter)); |
+ return makeLet( |
+ valueVariable, makeLet(dummy, new VariableGet(valueVariable))); |
+ } |
+ |
+ Expression _finish(Expression body) { |
+ return makeLet(receiverVariable, makeLet(indexVariable, body)); |
+ } |
+} |
+ |
+/// Special case of [IndexAccessor] to avoid creating an indirect access to |
+/// 'this'. |
+class ThisIndexAccessor extends Accessor { |
+ Expression index; |
+ VariableDeclaration indexVariable; |
+ Procedure getter, setter; |
+ |
+ ThisIndexAccessor(this.index, this.getter, this.setter); |
+ |
+ _makeSimpleRead() { |
+ return new MethodInvocation(new ThisExpression(), _indexGet, |
+ new Arguments(<Expression>[index]), getter); |
+ } |
+ |
+ _makeSimpleWrite(Expression value, bool voidContext) { |
+ if (!voidContext) return _makeWriteAndReturn(value); |
+ return new MethodInvocation(new ThisExpression(), _indexSet, |
+ new Arguments(<Expression>[index, value]), setter); |
+ } |
+ |
+ indexAccess() { |
+ indexVariable ??= new VariableDeclaration.forValue(index); |
+ return new VariableGet(indexVariable); |
+ } |
+ |
+ _makeRead() => new MethodInvocation(new ThisExpression(), _indexGet, |
+ new Arguments(<Expression>[indexAccess()]), getter); |
+ |
+ _makeWrite(Expression value, bool voidContext) { |
+ if (!voidContext) return _makeWriteAndReturn(value); |
+ return new MethodInvocation(new ThisExpression(), _indexSet, |
+ new Arguments(<Expression>[indexAccess(), value]), setter); |
+ } |
+ |
+ _makeWriteAndReturn(Expression value) { |
+ var valueVariable = new VariableDeclaration.forValue(value); |
+ var dummy = new VariableDeclaration.forValue(new MethodInvocation( |
+ new ThisExpression(), |
+ _indexSet, |
+ new Arguments( |
+ <Expression>[indexAccess(), new VariableGet(valueVariable)]), |
+ setter)); |
+ return makeLet( |
+ valueVariable, makeLet(dummy, new VariableGet(valueVariable))); |
+ } |
+ |
+ Expression _finish(Expression body) => makeLet(indexVariable, body); |
+} |
+ |
+class SuperIndexAccessor extends Accessor { |
+ Expression index; |
+ VariableDeclaration indexVariable; |
+ Member getter, setter; |
+ |
+ SuperIndexAccessor(this.index, this.getter, this.setter); |
+ |
+ indexAccess() { |
+ indexVariable ??= new VariableDeclaration.forValue(index); |
+ return new VariableGet(indexVariable); |
+ } |
+ |
+ _makeSimpleRead() => new SuperMethodInvocation( |
+ _indexGet, new Arguments(<Expression>[index]), getter); |
+ |
+ _makeSimpleWrite(Expression value, bool voidContext) { |
+ if (!voidContext) return _makeWriteAndReturn(value); |
+ return new SuperMethodInvocation( |
+ _indexSet, new Arguments(<Expression>[index, value]), setter); |
+ } |
+ |
+ _makeRead() { |
+ return new SuperMethodInvocation( |
+ _indexGet, new Arguments(<Expression>[indexAccess()]), getter); |
+ } |
+ |
+ _makeWrite(Expression value, bool voidContext) { |
+ if (!voidContext) return _makeWriteAndReturn(value); |
+ return new SuperMethodInvocation( |
+ _indexSet, new Arguments(<Expression>[indexAccess(), value]), setter); |
+ } |
+ |
+ _makeWriteAndReturn(Expression value) { |
+ var valueVariable = new VariableDeclaration.forValue(value); |
+ var dummy = new VariableDeclaration.forValue(new SuperMethodInvocation( |
+ _indexSet, |
+ new Arguments( |
+ <Expression>[indexAccess(), new VariableGet(valueVariable)]), |
+ setter)); |
+ return makeLet( |
+ valueVariable, makeLet(dummy, new VariableGet(valueVariable))); |
+ } |
+ |
+ Expression _finish(Expression body) { |
+ return makeLet(indexVariable, body); |
+ } |
+} |
+ |
+class StaticAccessor extends Accessor { |
+ Member readTarget; |
+ Member writeTarget; |
+ |
+ StaticAccessor(this.readTarget, this.writeTarget); |
+ |
+ _makeRead() => |
+ readTarget == null ? makeInvalidRead() : new StaticGet(readTarget); |
+ |
+ _makeWrite(Expression value, bool voidContext) { |
+ return writeTarget == null |
+ ? makeInvalidWrite(value) |
+ : new StaticSet(writeTarget, value); |
+ } |
+} |
+ |
+class ReadOnlyAccessor extends Accessor { |
+ Expression expression; |
+ VariableDeclaration value; |
+ |
+ ReadOnlyAccessor(this.expression); |
+ |
+ _makeSimpleRead() => expression; |
+ |
+ _makeRead() { |
+ value ??= new VariableDeclaration.forValue(expression); |
+ return new VariableGet(value); |
+ } |
+ |
+ _makeWrite(Expression value, bool voidContext) => makeInvalidWrite(value); |
+ |
+ Expression _finish(Expression body) => makeLet(value, body); |
+} |
+ |
+Expression makeLet(VariableDeclaration variable, Expression body) { |
+ if (variable == null) return body; |
+ return new Let(variable, body); |
+} |
+ |
+Expression makeBinary(Expression left, Name operator, Procedure interfaceTarget, |
+ Expression right) { |
+ return new MethodInvocation( |
+ left, operator, new Arguments(<Expression>[right]), interfaceTarget); |
+} |
+ |
+final Name _equalOperator = new Name('=='); |
+ |
+Expression buildIsNull(Expression value) { |
+ return makeBinary(value, _equalOperator, null, new NullLiteral()); |
+} |
+ |
+VariableDeclaration makeOrReuseVariable(Expression value) { |
+ // TODO: Devise a way to remember if a variable declaration was reused |
+ // or is fresh (hence needs a let binding). |
+ return new VariableDeclaration.forValue(value); |
+} |
+ |
+Expression wrapInvalid(Expression e) { |
+ return new Let(new VariableDeclaration.forValue(e), new InvalidExpression()); |
+} |