Re-duplicate frontend_accessors.dart.

This was de-duped in 02573b3caa, however
there's a problem: In order to share type inference and error
detection logic between Fasta's AstBuilder and BodyBuilder classes,
Fasta's use of the accessors needs to be rewritten to make use of the
shadow hierarchy (see
pkg/front_end/lib/src/fasta/builder/shadow_ast.dart), which kernel
shouldn't have to depend on.

R=ahe@google.com

Review-Url: https://codereview.chromium.org/2794013003 .
This commit is contained in:
Paul Berry
2017-04-04 10:48:47 -07:00
parent 1a8ef13fd1
commit 80101ac407
5 changed files with 549 additions and 28 deletions
@@ -4,7 +4,6 @@
library kernel.analyzer.ast_from_analyzer;
import 'package:kernel/ast.dart' as ast;
import 'package:kernel/frontend/accessors.dart';
import 'package:kernel/frontend/super_initializers.dart';
import 'package:kernel/log.dart';
import 'package:kernel/type_algebra.dart';
@@ -18,6 +17,7 @@ import 'package:analyzer/dart/ast/standard_resolution_map.dart';
import 'package:analyzer/src/generated/parser.dart';
import 'package:analyzer/src/dart/element/member.dart';
import 'package:analyzer/src/error/codes.dart';
import 'package:front_end/src/fasta/kernel/frontend_accessors.dart';
/// Provides reference-level access to libraries, classes, and members.
///
@@ -484,7 +484,8 @@ class TypeScope extends ReferenceScope {
positionalParameters: positional,
namedParameters: named,
requiredParameterCount: requiredParameterCount,
returnType: returnType)..fileOffset = element.nameOffset;
returnType: returnType)
..fileOffset = element.nameOffset;
}
}
@@ -655,8 +656,8 @@ class ExpressionScope extends TypeScope {
ast.VariableDeclaration getVariableReference(LocalElement element) {
return localVariables.putIfAbsent(element, () {
return new ast.VariableDeclaration(element.name,
isFinal: isFinal(element),
isConst: isConst(element))..fileOffset = element.nameOffset;
isFinal: isFinal(element), isConst: isConst(element))
..fileOffset = element.nameOffset;
});
}
@@ -1279,7 +1280,8 @@ class StatementBuilder extends GeneralizingAstVisitor<ast.Statement> {
variable,
scope.buildExpression(node.iterable),
makeBreakTarget(body, continueNode),
isAsync: node.awaitKeyword != null)..fileOffset = node.offset;
isAsync: node.awaitKeyword != null)
..fileOffset = node.offset;
return makeBreakTarget(loop, breakNode);
}
@@ -1357,7 +1359,8 @@ class StatementBuilder extends GeneralizingAstVisitor<ast.Statement> {
typeParameters: scope.buildOptionalTypeParameterList(
expression.typeParameters,
strongModeOnly: true),
returnType: declaration.returnType))..fileOffset = node.offset;
returnType: declaration.returnType))
..fileOffset = node.offset;
}
@override
@@ -2001,7 +2004,8 @@ class ExpressionBuilder
new ast.VariableGet(receiver),
scope.buildName(node.methodName),
buildArgumentsForInvocation(node),
element)..fileOffset = node.methodName.offset,
element)
..fileOffset = node.methodName.offset,
scope.buildType(node.staticType)));
} else {
return buildDecomposableMethodInvocation(
@@ -2637,7 +2641,8 @@ class ClassBodyBuilder extends GeneralizingAstVisitor<Null> {
new ast.FieldInitializer(
nameField, new ast.VariableGet(nameParameter)),
new ast.SuperInitializer(superConstructor, new ast.Arguments.empty())
])..fileOffset = element.nameOffset;
])
..fileOffset = element.nameOffset;
classNode.addMember(constructor);
int index = 0;
@@ -2650,7 +2655,8 @@ class ClassBodyBuilder extends GeneralizingAstVisitor<Null> {
new ast.IntLiteral(index),
new ast.StringLiteral('${classNode.name}.${field.name.name}')
]),
isConst: true)..parent = field;
isConst: true)
..parent = field;
field.type = classNode.rawType;
classNode.addMember(field);
++index;
@@ -2666,7 +2672,8 @@ class ClassBodyBuilder extends GeneralizingAstVisitor<Null> {
valuesField.initializer = new ast.ListLiteral(
enumConstantFields.map(_makeStaticGet).toList(),
isConst: true,
typeArgument: enumType)..parent = valuesField;
typeArgument: enumType)
..parent = valuesField;
classNode.addMember(valuesField);
// Add the 'toString()' method.
@@ -2784,7 +2791,8 @@ class MemberBodyBuilder extends GeneralizingAstVisitor<Null> {
addAnnotations(node.metadata);
ast.Constructor constructor = currentMember;
constructor.function = scope.buildFunctionNode(node.parameters, node.body,
inferredReturnType: const ast.VoidType())..parent = constructor;
inferredReturnType: const ast.VoidType())
..parent = constructor;
handleNativeBody(node.body);
if (node.body is EmptyFunctionBody && !constructor.isExternal) {
var function = constructor.function;
@@ -2902,9 +2910,8 @@ class MemberBodyBuilder extends GeneralizingAstVisitor<Null> {
if (constructorsField == null) {
ast.ListLiteral literal = new ast.ListLiteral(<ast.Expression>[]);
constructorsField = new ast.Field(constructors,
isStatic: true,
initializer: literal,
fileUri: classNode.fileUri)..fileOffset = classNode.fileOffset;
isStatic: true, initializer: literal, fileUri: classNode.fileUri)
..fileOffset = classNode.fileOffset;
classNode.addMember(constructorsField);
}
ast.ListLiteral literal = constructorsField.initializer;
@@ -2933,7 +2940,8 @@ class MemberBodyBuilder extends GeneralizingAstVisitor<Null> {
resolutionMap.elementDeclaredByMethodDeclaration(node).returnType),
typeParameters: scope.buildOptionalTypeParameterList(
node.typeParameters,
strongModeOnly: true))..parent = procedure;
strongModeOnly: true))
..parent = procedure;
handleNativeBody(node.body);
}
@@ -2961,7 +2969,8 @@ class MemberBodyBuilder extends GeneralizingAstVisitor<Null> {
returnType: node.returnType,
typeParameters: scope.buildOptionalTypeParameterList(
function.typeParameters,
strongModeOnly: true))..parent = procedure;
strongModeOnly: true))
..parent = procedure;
handleNativeBody(function.body);
}
@@ -21,8 +21,7 @@ import 'package:kernel/class_hierarchy.dart' show ClassHierarchy;
import 'package:kernel/core_types.dart' show CoreTypes;
import 'package:kernel/frontend/accessors.dart'
show buildIsNull, makeBinary, makeLet;
import 'frontend_accessors.dart' show buildIsNull, makeBinary, makeLet;
import '../parser/dart_vm_native.dart' show skipNativeClause;
@@ -957,7 +956,8 @@ class BodyBuilder extends ScopeListener<JumpTarget> implements BuilderHelper {
initializer: initializer,
type: currentLocalVariableType ?? const DynamicType(),
isFinal: isFinal,
isConst: isConst)..fileEqualsOffset = equalsCharOffset);
isConst: isConst)
..fileEqualsOffset = equalsCharOffset);
}
@override
@@ -1413,7 +1413,8 @@ class BodyBuilder extends ScopeListener<JumpTarget> implements BuilderHelper {
type: type,
initializer: name.initializer,
isFinal: isFinal,
isConst: isConst)..fileOffset = name.fileOffset;
isConst: isConst)
..fileOffset = name.fileOffset;
} else {
addCompileTimeError(
name.fileOffset, "'${name.name}' isn't a field in this class.");
@@ -1423,7 +1424,8 @@ class BodyBuilder extends ScopeListener<JumpTarget> implements BuilderHelper {
type: type ?? const DynamicType(),
initializer: name.initializer,
isFinal: isFinal,
isConst: isConst)..fileOffset = name.fileOffset;
isConst: isConst)
..fileOffset = name.fileOffset;
push(variable);
}
@@ -2016,7 +2018,8 @@ class BodyBuilder extends ScopeListener<JumpTarget> implements BuilderHelper {
"Expected lvalue, but got ${lvalue}", forToken.next.next.charOffset));
}
Statement result = new ForInStatement(variable, expression, body,
isAsync: awaitToken != null)..fileOffset = body.fileOffset;
isAsync: awaitToken != null)
..fileOffset = body.fileOffset;
if (breakTarget.hasUsers) {
result = new LabeledStatement(result);
breakTarget.resolveBreaks(result);
@@ -2174,7 +2177,8 @@ class BodyBuilder extends ScopeListener<JumpTarget> implements BuilderHelper {
expressionOffsets.add(expression.fileOffset);
}
push(new SwitchCase(expressions, expressionOffsets, block,
isDefault: defaultKeyword != null)..fileOffset = firstToken.charOffset);
isDefault: defaultKeyword != null)
..fileOffset = firstToken.charOffset);
push(labels);
}
@@ -4,10 +4,9 @@
library fasta.fasta_accessors;
export 'package:kernel/frontend/accessors.dart' show wrapInvalid;
export 'frontend_accessors.dart' show wrapInvalid;
import 'package:kernel/frontend/accessors.dart'
show Accessor, buildIsNull, makeLet;
import 'frontend_accessors.dart' show Accessor, buildIsNull, makeLet;
import 'package:kernel/ast.dart';
@@ -15,7 +14,7 @@ import '../errors.dart' show internalError;
import '../scope.dart' show AccessErrorBuilder, ProblemBuilder;
import 'package:kernel/frontend/accessors.dart' as kernel
import 'frontend_accessors.dart' as kernel
show
IndexAccessor,
NullAwarePropertyAccessor,
@@ -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("[]");
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) {
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());
}
+1 -1
View File
@@ -6,7 +6,7 @@ library front_end.src.fasta.names;
import 'package:kernel/ast.dart' show Name;
export 'package:kernel/frontend/accessors.dart' show indexGetName, indexSetName;
export 'kernel/frontend_accessors.dart' show indexGetName, indexSetName;
final Name callName = new Name("call");