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

Unified Diff: pkg/front_end/lib/src/fasta/kernel/frontend_accessors.dart

Issue 2794013003: Re-duplicate frontend_accessors.dart. (Closed)
Patch Set: Created 3 years, 9 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 side-by-side diff with in-line comments
Download patch
« no previous file with comments | « pkg/front_end/lib/src/fasta/kernel/fasta_accessors.dart ('k') | pkg/front_end/lib/src/fasta/names.dart » ('j') | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: pkg/front_end/lib/src/fasta/kernel/frontend_accessors.dart
diff --git a/pkg/front_end/lib/src/fasta/kernel/frontend_accessors.dart b/pkg/front_end/lib/src/fasta/kernel/frontend_accessors.dart
new file mode 100644
index 0000000000000000000000000000000000000000..d1d7b2ed4da9479c46dc798b86192a0e764aa73c
--- /dev/null
+++ b/pkg/front_end/lib/src/fasta/kernel/frontend_accessors.dart
@@ -0,0 +1,509 @@
+// 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.
+
+/// A library to help transform compounds and null-aware accessors into
+/// let expressions.
+
+import 'package:kernel/ast.dart';
+
+final Name indexGetName = new Name("[]");
ahe 2017/04/04 09:18:50 We could export these from the kernel version.
Paul Berry 2017/04/04 16:21:10 Done.
Paul Berry 2017/04/04 17:45:20 But for some reason this caused test failures whic
+
+final Name indexSetName = new Name("[]=");
+
+/// An [Accessor] represents a subexpression for which we can't yet build a
+/// kernel [Expression] because we don't yet know the context in which it is
+/// used.
+///
+/// Once the context is known, an [Accessor] can be converted into an
+/// [Expression] by calling a "build" method.
+///
+/// For example, when building a kernel representation for `a[x] = b`, after
+/// parsing `a[x]` but before parsing `= b`, we don't yet know whether to
+/// generate an invocation of `operator[]` or `operator[]=`, so we generate an
+/// [Accessor] object. Later, after `= b` is parsed, [buildAssignment] will be
+/// called.
+abstract class Accessor {
+ final int offset;
+
+ // [builtBinary] and [builtGetter] capture the inner nodes. Used by
+ // dart2js+rasta for determining how subexpressions map to legacy dart2js Ast
+ // nodes. This will be removed once dart2js type analysis (aka inference) is
+ // reimplemented on kernel.
+ Expression builtBinary;
+ Expression builtGetter;
+
+ Accessor(this.offset);
+
+ /// Builds an [Expression] representing a read from the accessor.
+ Expression buildSimpleRead() {
+ return _finish(_makeSimpleRead());
+ }
+
+ /// Builds an [Expression] representing an assignment with the accessor on
+ /// the LHS and [value] on the RHS.
+ ///
+ /// 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));
+ }
+
+ /// Returns an [Expression] representing a null-aware assignment (`??=`) with
+ /// the accessor on the LHS and [value] on the RHS.
+ ///
+ /// The returned expression evaluates to the assigned value, unless
+ /// [voidContext] is true, in which case it may evaluate to anything.
+ ///
+ /// [type] is the static type of the RHS.
+ Expression buildNullAwareAssignment(Expression value, DartType type,
+ {bool voidContext: false}) {
+ if (voidContext) {
+ return _finish(new ConditionalExpression(buildIsNull(_makeRead()),
+ _makeWrite(value, false), new NullLiteral(), type));
+ }
+ var tmp = new VariableDeclaration.forValue(_makeRead());
+ return _finish(makeLet(
+ tmp,
+ new ConditionalExpression(buildIsNull(new VariableGet(tmp)),
+ _makeWrite(value, false), new VariableGet(tmp), type)));
+ }
+
+ /// Returns an [Expression] representing a compound assignment (e.g. `+=`)
+ /// with the accessor on the LHS and [value] on the RHS.
+ Expression buildCompoundAssignment(Name binaryOperator, Expression value,
+ {int offset: TreeNode.noOffset,
+ bool voidContext: false,
+ Procedure interfaceTarget}) {
+ return _finish(_makeWrite(
+ builtBinary = makeBinary(
+ _makeRead(), binaryOperator, interfaceTarget, value,
+ offset: offset),
+ voidContext));
+ }
+
+ /// Returns an [Expression] representing a pre-increment or pre-decrement
+ /// of the accessor.
+ Expression buildPrefixIncrement(Name binaryOperator,
+ {int offset: TreeNode.noOffset,
+ bool voidContext: false,
+ Procedure interfaceTarget}) {
+ return buildCompoundAssignment(binaryOperator, new IntLiteral(1),
+ offset: offset,
+ voidContext: voidContext,
+ interfaceTarget: interfaceTarget);
+ }
+
+ /// Returns an [Expression] representing a post-increment or post-decrement
+ /// of the accessor.
+ Expression buildPostfixIncrement(Name binaryOperator,
+ {int offset: TreeNode.noOffset,
+ bool voidContext: false,
+ Procedure interfaceTarget}) {
+ if (voidContext) {
+ return buildPrefixIncrement(binaryOperator,
+ offset: offset, voidContext: true, interfaceTarget: interfaceTarget);
+ }
+ var value = new VariableDeclaration.forValue(_makeRead());
+ valueAccess() => new VariableGet(value);
+ var dummy = new VariableDeclaration.forValue(_makeWrite(
+ builtBinary = makeBinary(
+ valueAccess(), binaryOperator, interfaceTarget, new IntLiteral(1),
+ offset: offset),
+ 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;
+
+ /// Returns an [Expression] representing a compile-time error.
+ ///
+ /// At runtime, an exception will be thrown.
+ makeInvalidRead() => new InvalidExpression();
+
+ /// Returns an [Expression] representing a compile-time error wrapping
+ /// [value].
+ ///
+ /// At runtime, [value] will be evaluated before throwing an exception.
+ makeInvalidWrite(Expression value) => wrapInvalid(value);
+}
+
+class VariableAccessor extends Accessor {
+ VariableDeclaration variable;
+ DartType promotedType;
+
+ VariableAccessor(this.variable, this.promotedType, int offset)
+ : super(offset);
+
+ _makeRead() => new VariableGet(variable, promotedType)..fileOffset = offset;
+
+ _makeWrite(Expression value, bool voidContext) {
+ return variable.isFinal || variable.isConst
+ ? makeInvalidWrite(value)
+ : new VariableSet(variable, value)..fileOffset = offset;
+ }
+}
+
+class PropertyAccessor extends Accessor {
+ VariableDeclaration _receiverVariable;
+ Expression receiver;
+ Name name;
+ Member getter, setter;
+
+ static Accessor make(
+ Expression receiver, Name name, Member getter, Member setter,
+ {int offset: TreeNode.noOffset}) {
+ if (receiver is ThisExpression) {
+ return new ThisPropertyAccessor(name, getter, setter, offset);
+ } else {
+ return new PropertyAccessor.internal(
+ receiver, name, getter, setter, offset);
+ }
+ }
+
+ PropertyAccessor.internal(
+ this.receiver, this.name, this.getter, this.setter, int offset)
+ : super(offset);
+
+ _makeSimpleRead() =>
+ new PropertyGet(receiver, name, getter)..fileOffset = offset;
+
+ _makeSimpleWrite(Expression value, bool voidContext) {
+ return new PropertySet(receiver, name, value, setter)..fileOffset = offset;
+ }
+
+ receiverAccess() {
+ _receiverVariable ??= new VariableDeclaration.forValue(receiver);
+ return new VariableGet(_receiverVariable)..fileOffset = offset;
+ }
+
+ _makeRead() => builtGetter = new PropertyGet(receiverAccess(), name, getter)
+ ..fileOffset = offset;
+
+ _makeWrite(Expression value, bool voidContext) {
+ return new PropertySet(receiverAccess(), name, value, setter)
+ ..fileOffset = offset;
+ }
+
+ _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, int offset)
+ : super(offset);
+
+ _makeRead() => builtGetter =
+ new PropertyGet(new ThisExpression(), name, getter)..fileOffset = offset;
+
+ _makeWrite(Expression value, bool voidContext) {
+ return new PropertySet(new ThisExpression(), name, value, setter)
+ ..fileOffset = offset;
+ }
+}
+
+class NullAwarePropertyAccessor extends Accessor {
+ VariableDeclaration receiver;
+ Name name;
+ Member getter, setter;
+ DartType type;
+
+ NullAwarePropertyAccessor(Expression receiver, this.name, this.getter,
+ this.setter, this.type, int offset)
+ : this.receiver = makeOrReuseVariable(receiver),
+ super(offset);
+
+ receiverAccess() => new VariableGet(receiver);
+
+ _makeRead() => builtGetter = 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, int offset)
+ : super(offset);
+
+ _makeRead() {
+ if (getter == null) return makeInvalidRead();
+ // TODO(ahe): Use [DirectPropertyGet] when possible.
+ return builtGetter = new SuperPropertyGet(name, getter)
+ ..fileOffset = offset;
+ }
+
+ _makeWrite(Expression value, bool voidContext) {
+ if (setter == null) return makeInvalidWrite(value);
+ // TODO(ahe): Use [DirectPropertySet] when possible.
+ return new SuperPropertySet(name, value, setter)..fileOffset = offset;
+ }
+}
+
+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,
+ {int offset: TreeNode.noOffset}) {
+ if (receiver is ThisExpression) {
+ return new ThisIndexAccessor(index, getter, setter, offset);
+ } else {
+ return new IndexAccessor.internal(
+ receiver, index, getter, setter, offset);
+ }
+ }
+
+ IndexAccessor.internal(
+ this.receiver, this.index, this.getter, this.setter, int offset)
+ : super(offset);
+
+ _makeSimpleRead() => new MethodInvocation(
+ receiver, indexGetName, new Arguments(<Expression>[index]), getter)
+ ..fileOffset = offset;
+
+ _makeSimpleWrite(Expression value, bool voidContext) {
+ if (!voidContext) return _makeWriteAndReturn(value);
+ return new MethodInvocation(receiver, indexSetName,
+ new Arguments(<Expression>[index, value]), setter)..fileOffset = offset;
+ }
+
+ 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)..fileOffset = offset;
+ }
+
+ indexAccess() {
+ indexVariable ??= new VariableDeclaration.forValue(index);
+ return new VariableGet(indexVariable)..fileOffset = offset;
+ }
+
+ _makeRead() {
+ return builtGetter = new MethodInvocation(
+ receiverAccess(),
+ indexGetName,
+ new Arguments(<Expression>[indexAccess()]),
+ getter)..fileOffset = offset;
+ }
+
+ _makeWrite(Expression value, bool voidContext) {
+ if (!voidContext) return _makeWriteAndReturn(value);
+ return new MethodInvocation(
+ receiverAccess(),
+ indexSetName,
+ new Arguments(<Expression>[indexAccess(), value]),
+ setter)..fileOffset = offset;
+ }
+
+ // TODO(dmitryas): remove this method after the "[]=" operator of the Context
+ // class is made to return a value.
+ _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(),
+ indexSetName,
+ new Arguments(
+ <Expression>[indexAccess(), new VariableGet(valueVariable)]),
+ setter)..fileOffset = offset);
+ 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, int offset)
+ : super(offset);
+
+ _makeSimpleRead() {
+ return new MethodInvocation(new ThisExpression(), indexGetName,
+ new Arguments(<Expression>[index]), getter);
+ }
+
+ _makeSimpleWrite(Expression value, bool voidContext) {
+ if (!voidContext) return _makeWriteAndReturn(value);
+ return new MethodInvocation(new ThisExpression(), indexSetName,
+ new Arguments(<Expression>[index, value]), setter);
+ }
+
+ indexAccess() {
+ indexVariable ??= new VariableDeclaration.forValue(index);
+ return new VariableGet(indexVariable);
+ }
+
+ _makeRead() => builtGetter = new MethodInvocation(new ThisExpression(),
+ indexGetName, new Arguments(<Expression>[indexAccess()]), getter);
+
+ _makeWrite(Expression value, bool voidContext) {
+ if (!voidContext) return _makeWriteAndReturn(value);
+ return new MethodInvocation(new ThisExpression(), indexSetName,
+ new Arguments(<Expression>[indexAccess(), value]), setter);
+ }
+
+ _makeWriteAndReturn(Expression value) {
+ var valueVariable = new VariableDeclaration.forValue(value);
+ var dummy = new VariableDeclaration.forValue(new MethodInvocation(
+ new ThisExpression(),
+ indexSetName,
+ 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, int offset)
+ : super(offset);
+
+ indexAccess() {
+ indexVariable ??= new VariableDeclaration.forValue(index);
+ return new VariableGet(indexVariable);
+ }
+
+ _makeSimpleRead() => new SuperMethodInvocation(
+ indexGetName, new Arguments(<Expression>[index]), getter);
+
+ _makeSimpleWrite(Expression value, bool voidContext) {
+ if (!voidContext) return _makeWriteAndReturn(value);
+ return new SuperMethodInvocation(
+ indexSetName, new Arguments(<Expression>[index, value]), setter);
+ }
+
+ _makeRead() {
+ return builtGetter = new SuperMethodInvocation(
+ indexGetName, new Arguments(<Expression>[indexAccess()]), getter);
+ }
+
+ _makeWrite(Expression value, bool voidContext) {
+ if (!voidContext) return _makeWriteAndReturn(value);
+ return new SuperMethodInvocation(indexSetName,
+ new Arguments(<Expression>[indexAccess(), value]), setter);
+ }
+
+ _makeWriteAndReturn(Expression value) {
+ var valueVariable = new VariableDeclaration.forValue(value);
+ var dummy = new VariableDeclaration.forValue(new SuperMethodInvocation(
+ indexSetName,
+ 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, int offset) : super(offset);
+
+ _makeRead() => builtGetter = readTarget == null
+ ? makeInvalidRead()
+ : new StaticGet(readTarget)..fileOffset = offset;
+
+ _makeWrite(Expression value, bool voidContext) {
+ return writeTarget == null
+ ? makeInvalidWrite(value)
+ : new StaticSet(writeTarget, value)..fileOffset = offset;
+ }
+}
+
+class ReadOnlyAccessor extends Accessor {
+ Expression expression;
+ VariableDeclaration value;
+
+ ReadOnlyAccessor(this.expression, int offset) : super(offset);
+
+ _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) {
ahe 2017/04/04 09:18:50 These helper methods could probably also be export
Paul Berry 2017/04/04 16:21:10 I'm going to leave these as is for now because I b
+ if (variable == null) return body;
+ return new Let(variable, body);
+}
+
+Expression makeBinary(
+ Expression left, Name operator, Procedure interfaceTarget, Expression right,
+ {int offset: TreeNode.noOffset}) {
+ return new MethodInvocation(
+ left, operator, new Arguments(<Expression>[right]), interfaceTarget)
+ ..fileOffset = offset;
+}
+
+final Name _equalOperator = new Name('==');
+
+Expression buildIsNull(Expression value, {int offset: TreeNode.noOffset}) {
+ return makeBinary(value, _equalOperator, null, new NullLiteral(),
+ offset: offset);
+}
+
+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());
+}
« no previous file with comments | « pkg/front_end/lib/src/fasta/kernel/fasta_accessors.dart ('k') | pkg/front_end/lib/src/fasta/names.dart » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698