Chromium Code Reviews| Index: pkg/fasta/lib/src/kernel/builder_accessors.dart |
| diff --git a/pkg/fasta/lib/src/kernel/builder_accessors.dart b/pkg/fasta/lib/src/kernel/builder_accessors.dart |
| new file mode 100644 |
| index 0000000000000000000000000000000000000000..97a4e6d801dd20abf63f68d9ff913039225fe765 |
| --- /dev/null |
| +++ b/pkg/fasta/lib/src/kernel/builder_accessors.dart |
| @@ -0,0 +1,731 @@ |
| +// 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. |
| + |
| +library fasta.builder_accessors; |
| + |
| +export 'frontend_accessors.dart' show |
| + wrapInvalid; |
| + |
| +import 'frontend_accessors.dart' show |
| + Accessor; |
| + |
| +import 'package:kernel/ast.dart'; |
| + |
| +import 'package:kernel/core_types.dart' show |
| + CoreTypes; |
| + |
| +import '../errors.dart' show |
| + internalError; |
| + |
| +import 'frontend_accessors.dart' as kernel show |
| + IndexAccessor, |
| + NullAwarePropertyAccessor, |
| + PropertyAccessor, |
| + StaticAccessor, |
| + SuperPropertyAccessor, |
| + ThisIndexAccessor, |
| + ThisPropertyAccessor, |
| + VariableAccessor; |
| + |
| +import 'frontend_accessors.dart' show |
| + buildIsNull, |
| + makeLet; |
| + |
| +import 'kernel_builder.dart' show |
| + Builder, |
| + KernelClassBuilder, |
| + PrefixBuilder, |
| + TypeDeclarationBuilder; |
| + |
| +abstract class BuilderHelper { |
| + Uri get uri; |
| + |
| + CoreTypes get coreTypes; |
| + |
| + Constructor lookupConstructor(Name name, {bool isSuper}); |
| + |
| + Expression toSuperMethodInvocation(MethodInvocation node); |
| + |
| + Expression toValue(node); |
| + |
| + Member lookupSuperMember(Name name, {bool isSetter: false}); |
| + |
| + builderToFirstExpression(Builder builder, String name, int charOffset); |
| + |
| + finishSend(Object receiver, Arguments arguments, int charOffset); |
| + |
| + Expression buildCompileTimeError(error, [int charOffset]); |
| + |
| + Initializer buildCompileTimeErrorIntializer(error, [int charOffset]); |
| + |
| + Expression buildStaticInvocation(Procedure target, Arguments arguments); |
| + |
| + Expression buildProblemExpression(Builder builder, String name); |
| +} |
| + |
| +abstract class BuilderAccessor implements Accessor { |
| + BuilderHelper get helper; |
| + |
| + int get charOffset; |
| + |
| + String get plainNameForRead; |
| + |
| + Uri get uri => helper.uri; |
| + |
| + CoreTypes get coreTypes => helper.coreTypes; |
| + |
| + String get plainNameForWrite => plainNameForRead; |
| + |
| + Expression buildForEffect() => buildSimpleRead(); |
| + |
| + Initializer buildFieldInitializer( |
| + Map<String, FieldInitializer> initializers) { |
| + // TODO(ahe): This error message is really bad. |
| + return helper.buildCompileTimeErrorIntializer( |
| + "Can't use $plainNameForRead here.", charOffset); |
| + } |
| + |
| + Expression makeInvalidRead() { |
| + return throwNoSuchMethodError(plainNameForRead, new Arguments.empty(), uri, |
| + charOffset, coreTypes, isGetter: true); |
| + } |
| + |
| + Expression makeInvalidWrite(Expression value) { |
| + return throwNoSuchMethodError(plainNameForWrite, |
| + new Arguments(<Expression>[value]), uri, charOffset, coreTypes, |
| + isSetter: true); |
| + } |
| + |
| + Expression doInvocation(int charOffset, Arguments arguments); |
| + |
| + buildPropertyAccess(IncompleteSend send, bool isNullAware) { |
| + if (send is SendAccessor) { |
| + return buildMethodInvocation(buildSimpleRead(), send.name, send.arguments, |
| + charOffset, isNullAware: isNullAware); |
| + } else { |
| + return PropertyAccessor.make(helper, charOffset, buildSimpleRead(), |
| + send.name, null, null, isNullAware); |
| + } |
| + } |
| + |
| + Expression buildThrowNoSuchMethodError(Arguments arguments) { |
| + bool isGetter = false; |
| + if (arguments == null) { |
| + arguments = new Arguments.empty(); |
| + isGetter = true; |
| + } |
| + return throwNoSuchMethodError(plainNameForWrite, arguments, uri, charOffset, |
| + coreTypes, isGetter: isGetter); |
| + } |
| + |
| + bool get isThisPropertyAccessor => false; |
| +} |
| + |
| +abstract class CompileTimeErrorAccessor implements Accessor { |
| + Expression buildError(); |
| + |
| + Name get name => internalError("Unsupported operation."); |
| + |
| + String get plainNameForRead => name.name; |
| + |
| + withReceiver(Object receiver, {bool isNullAware}) => this; |
| + |
| + Initializer buildFieldInitializer( |
| + Map<String, FieldInitializer> initializers) { |
| + return new LocalInitializer(new VariableDeclaration.forValue(buildError())); |
| + } |
| + |
| + doInvocation(int charOffset, Arguments arguments) => this; |
| + |
| + buildPropertyAccess(IncompleteSend send, bool isNullAware) => this; |
| + |
| + buildThrowNoSuchMethodError(Arguments arguments) => this; |
| + |
| + Expression buildAssignment(Expression value, {bool voidContext: false}) { |
| + return buildError(); |
| + } |
| + |
| + Expression buildCompoundAssignment(Name binaryOperator, Expression value, |
| + {bool voidContext: false, Procedure interfaceTarget}) { |
| + return buildError(); |
| + } |
| + |
| + Expression buildPrefixIncrement(Name binaryOperator, |
| + {bool voidContext: false, Procedure interfaceTarget}) { |
| + return buildError(); |
| + } |
| + |
| + Expression buildPostfixIncrement(Name binaryOperator, |
| + {bool voidContext: false, Procedure interfaceTarget}) { |
| + return buildError(); |
| + } |
| + |
| + Expression buildNullAwareAssignment(Expression value, DartType type, |
| + {bool voidContext: false}) { |
| + return buildError(); |
| + } |
| + |
| + Expression buildSimpleRead() => buildError(); |
| + |
| + Expression makeInvalidRead() => buildError(); |
| + |
| + Expression makeInvalidWrite(Expression value) => buildError(); |
| +} |
| + |
| +class ThisAccessor extends BuilderAccessor { |
| + final BuilderHelper helper; |
| + |
| + final int charOffset; |
| + |
| + final bool isInitializer; |
| + |
| + final bool isSuper; |
| + |
| + ThisAccessor(this.helper, this.charOffset, this.isInitializer, |
| + {this.isSuper: false}); |
| + |
| + String get plainNameForRead => internalError(isSuper ? "super" : "this"); |
| + |
| + Expression buildSimpleRead() { |
| + if (!isSuper) { |
| + return new ThisExpression(); |
| + } else { |
| + return helper.buildCompileTimeError( |
| + "Can't use `super` as an expression.", charOffset); |
| + } |
| + } |
| + |
| + Initializer buildFieldInitializer( |
| + Map<String, FieldInitializer> initializers) { |
| + String keyword = isSuper ? "super" : "this"; |
| + return helper.buildCompileTimeErrorIntializer( |
| + "Can't use '$keyword' here, did you mean '$keyword()'?", charOffset); |
| + } |
| + |
| + buildPropertyAccess(IncompleteSend send, bool isNullAware) { |
| + if (isInitializer && send is SendAccessor) { |
| + return buildConstructorInitializer( |
| + send.charOffset, send.name, send.arguments); |
| + } |
| + if (send is SendAccessor) { |
| + // Notice that 'this' or 'super' can't be null. So we can ignore the |
| + // value of [isNullAware]. |
| + MethodInvocation result = buildMethodInvocation(new ThisExpression(), |
| + send.name, send.arguments, charOffset); |
| + return isSuper ? helper.toSuperMethodInvocation(result) : result; |
| + } else { |
| + if (isSuper) { |
| + Member getter = helper.lookupSuperMember(send.name); |
| + Member setter = helper.lookupSuperMember(send.name, isSetter: true); |
| + return new SuperPropertyAccessor(helper, charOffset, send.name, getter, |
| + setter); |
| + } else { |
| + return new ThisPropertyAccessor(helper, charOffset, send.name, null, |
| + null); |
| + } |
| + } |
| + } |
| + |
| + doInvocation(int charOffset, Arguments arguments) { |
| + if (isInitializer) { |
| + return buildConstructorInitializer(charOffset, new Name(""), arguments); |
| + } else { |
| + return buildMethodInvocation(new ThisExpression(), new Name("call"), |
| + arguments, charOffset); |
| + } |
| + } |
| + |
| + Initializer buildConstructorInitializer(int charOffset, Name name, |
| + Arguments arguments) { |
| + Constructor constructor = helper.lookupConstructor(name, isSuper: isSuper); |
| + Initializer result; |
| + if (constructor == null) { |
| + result = new LocalInitializer( |
| + new VariableDeclaration.forValue( |
| + throwNoSuchMethodError( |
| + name.name, arguments, uri, charOffset, coreTypes, |
| + isSuper: isSuper))); |
| + } else if (isSuper) { |
| + result = new SuperInitializer(constructor, arguments); |
| + } else { |
| + result = new RedirectingInitializer(constructor, arguments); |
| + } |
| + return result |
| + ..fileOffset = charOffset; |
| + } |
| + |
| + Expression buildAssignment(Expression value, {bool voidContext: false}) { |
| + return internalError(""); |
| + } |
| + |
| + Expression buildNullAwareAssignment(Expression value, DartType type, |
| + {bool voidContext: false}) { |
| + return internalError(""); |
| + } |
| + |
| + Expression buildCompoundAssignment(Name binaryOperator, Expression value, |
| + {bool voidContext: false, Procedure interfaceTarget}) { |
| + return internalError(""); |
| + } |
| + |
| + Expression buildPrefixIncrement(Name binaryOperator, |
| + {bool voidContext: false, Procedure interfaceTarget}) { |
| + return internalError(""); |
| + } |
| + |
| + Expression buildPostfixIncrement(Name binaryOperator, |
| + {bool voidContext: false, Procedure interfaceTarget}) { |
| + return internalError(""); |
| + } |
| + |
| + toString() => "ThisAccessor($charOffset${isSuper ? ', super' : ''})"; |
| +} |
| + |
| +abstract class IncompleteSend extends BuilderAccessor { |
| + final BuilderHelper helper; |
| + |
| + final int charOffset; |
| + |
| + final Name name; |
| + |
| + IncompleteSend(this.helper, this.charOffset, this.name); |
| + |
| + withReceiver(Object receiver, {bool isNullAware}); |
| +} |
| + |
| +class IncompleteError extends IncompleteSend with CompileTimeErrorAccessor { |
| + final Object error; |
| + |
| + IncompleteError(BuilderHelper helper, int charOffset, this.error) |
| + : super(helper, charOffset, null); |
| + |
| + Expression buildError() { |
| + return helper.buildCompileTimeError(error, charOffset); |
| + } |
| +} |
| + |
| +class SendAccessor extends IncompleteSend { |
| + final Arguments arguments; |
| + |
| + SendAccessor(BuilderHelper helper, int charOffset, Name name, this.arguments) |
| + : super(helper, charOffset, name) { |
| + assert(arguments != null); |
| + } |
| + |
| + String get plainNameForRead => name.name; |
| + |
| + Expression buildSimpleRead() { |
| + return internalError("Unhandled"); |
| + } |
| + |
| + Expression buildAssignment(Expression value, {bool voidContext: false}) { |
| + return internalError("Unhandled"); |
| + } |
| + |
| + withReceiver(Object receiver, {bool isNullAware: false}) { |
| + if (receiver is TypeDeclarationBuilder) { |
| + /// For reasons beyond comprehension, `SomeType?.toString` is the same as |
| + /// `SomeType.toString`, not `(SomeType).toString`. WTAF!?! |
| + // |
| + isNullAware = false; |
| + } |
| + if (receiver is BuilderAccessor) { |
| + return receiver.buildPropertyAccess(this, isNullAware); |
| + } |
| + if (receiver is PrefixBuilder) { |
| + PrefixBuilder prefix = receiver; |
| + receiver = helper.builderToFirstExpression( |
| + prefix.exports[name.name], "${prefix.name}.${name.name}", charOffset); |
| + return helper.finishSend(receiver, arguments, charOffset); |
| + } |
| + Expression result; |
| + if (receiver is KernelClassBuilder) { |
| + Builder builder = receiver.findStaticBuilder(name.name); |
| + if (builder == null) { |
| + return buildThrowNoSuchMethodError(arguments); |
| + } |
| + if (builder.hasProblem) { |
| + result = helper.buildProblemExpression(builder, name.name); |
| + } else { |
| + Member target = builder.target; |
| + if (target != null) { |
| + if (target is Field) { |
| + result = buildMethodInvocation(new StaticGet(target), |
| + new Name("call"), arguments, charOffset, |
| + isNullAware: isNullAware); |
| + } else { |
| + result = helper.buildStaticInvocation(target, arguments); |
| + } |
| + } else { |
| + result = buildThrowNoSuchMethodError(arguments); |
| + } |
| + } |
| + } else { |
| + result = buildMethodInvocation(helper.toValue(receiver), name, |
| + arguments, charOffset, isNullAware: isNullAware); |
| + } |
| + return result..fileOffset = charOffset; |
| + } |
| + |
| + Expression buildNullAwareAssignment(Expression value, DartType type, |
| + {bool voidContext: false}) { |
| + return internalError(""); |
| + } |
| + |
| + Expression buildCompoundAssignment(Name binaryOperator, Expression value, |
| + {bool voidContext: false, Procedure interfaceTarget}) { |
| + return internalError(""); |
| + } |
| + |
| + Expression buildPrefixIncrement(Name binaryOperator, |
| + {bool voidContext: false, Procedure interfaceTarget}) { |
| + return internalError("Unhandled"); |
| + } |
| + |
| + Expression buildPostfixIncrement(Name binaryOperator, |
| + {bool voidContext: false, Procedure interfaceTarget}) { |
| + return internalError("Unhandled"); |
| + } |
| + |
| + Expression doInvocation(int charOffset, Arguments arguments) { |
| + return internalError("Unhandled"); |
| + } |
| + |
| + toString() => "SendAccessor($charOffset, $name, $arguments)"; |
| +} |
| + |
| +class IncompletePropertyAccessor extends IncompleteSend { |
| + IncompletePropertyAccessor(BuilderHelper helper, int charOffset, Name name) |
| + : super(helper, charOffset, name); |
| + |
| + String get plainNameForRead => name.name; |
| + |
| + Expression buildSimpleRead() => internalError("Unhandled"); |
| + |
| + Expression buildAssignment(Expression value, {bool voidContext: false}) { |
| + return internalError("Unhandled"); |
| + } |
| + |
| + withReceiver(Object receiver, {bool isNullAware: false}) { |
| + if (receiver is TypeDeclarationBuilder) { |
| + /// For reasons beyond comprehension, `SomeType?.toString` is the same as |
| + /// `SomeType.toString`, not `(SomeType).toString`. WTAF!?! |
|
asgerf
2017/01/13 18:39:07
I agree, but let's not write comments like this.
ahe
2017/01/16 08:32:09
Done.
|
| + // |
| + isNullAware = false; |
| + } |
| + if (receiver is BuilderAccessor) { |
| + return receiver.buildPropertyAccess(this, isNullAware); |
| + } |
| + if (receiver is PrefixBuilder) { |
| + PrefixBuilder prefix = receiver; |
| + return helper.builderToFirstExpression( |
| + prefix.exports[name.name], name.name, charOffset); |
| + } |
| + if (receiver is KernelClassBuilder) { |
| + Builder builder = receiver.findStaticBuilder(name.name); |
| + Member getter = builder?.target; |
| + Member setter; |
| + if (builder == null) { |
| + builder = receiver.findStaticBuilder(name.name, isSetter: true); |
| + if (builder == null) { |
| + return buildThrowNoSuchMethodError(null); |
| + } |
| + } |
| + if (builder.hasProblem) { |
| + return helper.buildProblemExpression(builder, name.name) |
| + ..fileOffset = charOffset; |
| + } |
| + if (getter is Field) { |
| + if (!getter.isFinal && !getter.isConst) { |
| + setter = getter; |
| + } |
| + } else if (getter is Procedure) { |
| + if (getter.isGetter) { |
| + builder = receiver.findStaticBuilder(name.name, isSetter: true); |
| + if (builder != null && !builder.hasProblem) { |
| + setter = builder.target; |
| + } |
| + } |
| + } |
| + if (getter == null) { |
| + return internalError("no getter for $name"); |
| + } |
| + return new StaticAccessor(helper, charOffset, getter, setter); |
| + } |
| + return PropertyAccessor.make(helper, charOffset, helper.toValue(receiver), |
| + name, null, null, isNullAware); |
| + } |
| + |
| + Expression buildNullAwareAssignment(Expression value, DartType type, |
| + {bool voidContext: false}) { |
| + return internalError("Unhandled"); |
| + } |
| + |
| + Expression buildCompoundAssignment(Name binaryOperator, Expression value, |
| + {bool voidContext: false, Procedure interfaceTarget}) { |
| + return internalError("Unhandled"); |
| + } |
| + |
| + Expression buildPrefixIncrement(Name binaryOperator, |
| + {bool voidContext: false, Procedure interfaceTarget}) { |
| + return internalError("Unhandled"); |
| + } |
| + |
| + Expression buildPostfixIncrement(Name binaryOperator, |
| + {bool voidContext: false, Procedure interfaceTarget}) { |
| + return internalError("Unhandled"); |
| + } |
| + |
| + Expression doInvocation(int charOffset, Arguments arguments) { |
| + return internalError("Unhandled"); |
| + } |
| + |
| + toString() => "IncompletePropertyAccessor($charOffset, $name)"; |
| +} |
| + |
| +class IndexAccessor extends kernel.IndexAccessor with BuilderAccessor { |
| + final BuilderHelper helper; |
| + |
| + final int charOffset; |
| + |
| + IndexAccessor.internal(this.helper, this.charOffset, Expression receiver, |
| + Expression index, Procedure getter, Procedure setter) |
| + : super.internal(receiver, index, getter, setter); |
| + |
| + String get plainNameForRead => "[]"; |
| + |
| + String get plainNameForWrite => "[]="; |
| + |
| + Expression doInvocation(int charOffset, Arguments arguments) { |
| + return buildMethodInvocation(buildSimpleRead(), new Name("call"), arguments, |
| + charOffset); |
| + } |
| + |
| + toString() => "IndexAccessor()"; |
| + |
| + static BuilderAccessor make(BuilderHelper helper, int charOffset, |
| + Expression receiver, Expression index, Procedure getter, |
| + Procedure setter) { |
| + if (receiver is ThisExpression) { |
| + return new ThisIndexAccessor(helper, charOffset, index, getter, setter); |
| + } else { |
| + return new IndexAccessor.internal(helper, charOffset, receiver, index, |
| + getter, setter); |
| + } |
| + } |
| +} |
| + |
| +class PropertyAccessor extends kernel.PropertyAccessor with BuilderAccessor { |
| + final BuilderHelper helper; |
| + |
| + final int charOffset; |
| + |
| + PropertyAccessor.internal(this.helper, this.charOffset, Expression receiver, |
| + Name name, Member getter, Member setter) |
| + : super.internal(receiver, name, getter, setter); |
| + |
| + String get plainNameForRead => name.name; |
| + |
| + bool get isThisPropertyAccessor => receiver is ThisExpression; |
| + |
| + Expression doInvocation(int charOffset, Arguments arguments) { |
| + return buildMethodInvocation(receiver, name, arguments, charOffset); |
| + } |
| + |
| + toString() => "PropertyAccessor()"; |
| + |
| + static BuilderAccessor make(BuilderHelper helper, int charOffset, |
| + Expression receiver, Name name, Member getter, Member setter, |
| + bool isNullAware) { |
| + if (receiver is ThisExpression) { |
| + return new ThisPropertyAccessor(helper, charOffset, name, getter, setter); |
| + } else { |
| + return isNullAware |
| + ? new NullAwarePropertyAccessor(helper, charOffset, receiver, name, |
| + getter, setter, null) |
| + : new PropertyAccessor.internal(helper, charOffset, receiver, name, |
| + getter, setter); |
| + } |
| + } |
| +} |
| + |
| +class StaticAccessor extends kernel.StaticAccessor with BuilderAccessor { |
| + final BuilderHelper helper; |
| + |
| + final int charOffset; |
| + |
| + StaticAccessor(this.helper, this.charOffset, Member readTarget, |
| + Member writeTarget) |
| + : super(readTarget, writeTarget) { |
| + assert(readTarget != null || writeTarget != null); |
| + } |
| + |
| + String get plainNameForRead => (readTarget ?? writeTarget).name.name; |
| + |
| + Expression doInvocation(int charOffset, Arguments arguments) { |
| + if (readTarget == null || isFieldOrGetter(readTarget)) { |
| + return buildMethodInvocation(buildSimpleRead(), new Name("call"), |
| + arguments, charOffset); |
| + } else { |
| + return helper.buildStaticInvocation(readTarget, arguments) |
| + ..fileOffset = charOffset; |
| + } |
| + } |
| + |
| + toString() => "StaticAccessor()"; |
| +} |
| + |
| +class SuperPropertyAccessor extends kernel.SuperPropertyAccessor |
| + with BuilderAccessor { |
| + final BuilderHelper helper; |
| + |
| + final int charOffset; |
| + |
| + SuperPropertyAccessor(this.helper, this.charOffset, Name name, Member getter, |
| + Member setter) |
| + : super(name, getter, setter); |
| + |
| + String get plainNameForRead => name.name; |
| + |
| + Expression doInvocation(int charOffset, Arguments arguments) { |
| + if (getter == null || isFieldOrGetter(getter)) { |
| + return buildMethodInvocation(buildSimpleRead(), new Name("call"), |
| + arguments, charOffset); |
| + } else { |
| + return new DirectMethodInvocation(new ThisExpression(), getter, arguments) |
| + ..fileOffset = charOffset; |
| + } |
| + } |
| + |
| + toString() => "SuperPropertyAccessor()"; |
| +} |
| + |
| +class ThisIndexAccessor extends kernel.ThisIndexAccessor with BuilderAccessor { |
| + final BuilderHelper helper; |
| + |
| + final int charOffset; |
| + |
| + ThisIndexAccessor(this.helper, this.charOffset, Expression index, |
| + Procedure getter, Procedure setter) |
| + : super(index, getter, setter); |
| + |
| + String get plainNameForRead => "[]"; |
| + |
| + String get plainNameForWrite => "[]="; |
| + |
| + Expression doInvocation(int charOffset, Arguments arguments) { |
| + return buildMethodInvocation(buildSimpleRead(), new Name("call"), arguments, |
| + charOffset); |
| + } |
| + |
| + toString() => "ThisIndexAccessor()"; |
| +} |
| + |
| +class ThisPropertyAccessor extends kernel.ThisPropertyAccessor |
| + with BuilderAccessor { |
| + final BuilderHelper helper; |
| + |
| + final int charOffset; |
| + |
| + ThisPropertyAccessor(this.helper, this.charOffset, Name name, Member getter, |
| + Member setter) |
| + : super(name, getter, setter); |
| + |
| + String get plainNameForRead => name.name; |
| + |
| + bool get isThisPropertyAccessor => true; |
| + |
| + Expression doInvocation(int charOffset, Arguments arguments) { |
| + Member interfaceTarget = getter; |
| + if (interfaceTarget is Field) { |
| + // TODO(ahe): In strong mode we should probably rewrite this to |
| + // `this.name.call(arguments)`. |
| + interfaceTarget = null; |
| + } |
| + return buildMethodInvocation(new ThisExpression(), name, arguments, |
| + charOffset); |
| + } |
| + |
| + toString() => "ThisPropertyAccessor()"; |
| +} |
| + |
| +class NullAwarePropertyAccessor extends kernel.NullAwarePropertyAccessor |
| + with BuilderAccessor { |
| + final BuilderHelper helper; |
| + |
| + final int charOffset; |
| + |
| + NullAwarePropertyAccessor(this.helper, this.charOffset, Expression receiver, |
| + Name name, Member getter, Member setter, DartType type) |
| + : super(receiver, name, getter, setter, type); |
| + |
| + String get plainNameForRead => name.name; |
| + |
| + Expression doInvocation(int charOffset, Arguments arguments) { |
| + return internalError("Not implemented yet."); |
| + } |
| + |
| + toString() => "NullAwarePropertyAccessor()"; |
| +} |
| + |
| + |
| +class VariableAccessor extends kernel.VariableAccessor |
| + with BuilderAccessor { |
| + final BuilderHelper helper; |
| + |
| + final int charOffset; |
| + |
| + VariableAccessor(this.helper, this.charOffset, VariableDeclaration variable, |
| + [DartType promotedType]) |
| + : super.internal(variable, promotedType); |
| + |
| + String get plainNameForRead => variable.name; |
| + |
| + Expression doInvocation(int charOffset, Arguments arguments) { |
| + return buildMethodInvocation(buildSimpleRead(), new Name("call"), arguments, |
| + charOffset); |
| + } |
| + |
| + toString() => "VariableAccessor()"; |
| +} |
| + |
| +Expression throwNoSuchMethodError(String name, Arguments arguments, Uri uri, |
| + int charOffset, CoreTypes coreTypes, |
| + {bool isSuper: false, isGetter: false, isSetter: false}) { |
| + print("$uri:$charOffset: method not found: '$name'."); |
| + Constructor constructor = coreTypes.getCoreClass( |
| + "dart:core", "NoSuchMethodError").constructors.first; |
| + return new Throw(new ConstructorInvocation( |
| + constructor, |
| + new Arguments(<Expression>[ |
| + new NullLiteral(), |
| + new SymbolLiteral(name), |
| + new ListLiteral(arguments.positional), |
| + new MapLiteral(arguments.named.map((arg) { |
| + return new MapEntry(new SymbolLiteral(arg.name), arg.value); |
| + }).toList()), |
| + new NullLiteral()]))); |
| +} |
| + |
| +bool isFieldOrGetter(Member member) { |
| + return member is Field || (member is Procedure && member.isGetter); |
| +} |
| + |
| +Expression buildMethodInvocation(Expression receiver, Name name, |
| + Arguments arguments, int charOffset, {bool isNullAware: false}) { |
| + if (isNullAware) { |
| + VariableDeclaration variable = new VariableDeclaration.forValue(receiver); |
| + return makeLet( |
| + variable, |
| + new ConditionalExpression( |
| + buildIsNull(new VariableGet(variable)), |
| + new NullLiteral(), |
| + new MethodInvocation(new VariableGet(variable), name, arguments) |
| + ..fileOffset = charOffset, |
| + const DynamicType())); |
| + } else { |
| + return new MethodInvocation(receiver, name, arguments) |
| + ..fileOffset = charOffset; |
| + } |
| +} |