blob: 237d8e7bce891a986d52a8dcd981ebeea1d7bfce [file] [log] [blame]
// Copyright (c) 2017, 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.
/// Algorithm to serialize expressions into the format used by summaries.
library summary.src.expression_serializer;
import 'package:front_end/src/fasta/scanner/token_constants.dart';
import 'model.dart';
/// Translate a parser binary operation into an operation in the summary format.
UnlinkedExprOperation _binaryOpFor(int operatorKind) {
switch (operatorKind) {
case AMPERSAND_TOKEN:
return UnlinkedExprOperation.bitAnd;
case AMPERSAND_AMPERSAND_TOKEN:
return UnlinkedExprOperation.and;
case BANG_EQ_TOKEN:
return UnlinkedExprOperation.notEqual;
case BAR_TOKEN:
return UnlinkedExprOperation.bitOr;
case BAR_BAR_TOKEN:
return UnlinkedExprOperation.or;
case CARET_TOKEN:
return UnlinkedExprOperation.bitXor;
case EQ_EQ_TOKEN:
return UnlinkedExprOperation.equal;
case GT_TOKEN:
return UnlinkedExprOperation.greater;
case GT_EQ_TOKEN:
return UnlinkedExprOperation.greaterEqual;
case GT_GT_TOKEN:
return UnlinkedExprOperation.bitShiftRight;
case LT_TOKEN:
return UnlinkedExprOperation.less;
case LT_EQ_TOKEN:
return UnlinkedExprOperation.lessEqual;
case LT_LT_TOKEN:
return UnlinkedExprOperation.bitShiftLeft;
case MINUS_TOKEN:
return UnlinkedExprOperation.subtract;
case PERCENT_TOKEN:
return UnlinkedExprOperation.modulo;
case PERIOD_TOKEN:
return UnlinkedExprOperation.extractProperty;
case PLUS_TOKEN:
return UnlinkedExprOperation.add;
case QUESTION_QUESTION_TOKEN:
return UnlinkedExprOperation.ifNull;
case SLASH_TOKEN:
return UnlinkedExprOperation.divide;
case STAR_TOKEN:
return UnlinkedExprOperation.multiply;
case TILDE_SLASH_TOKEN:
return UnlinkedExprOperation.floorDivide;
default:
throw "Unhandled openratorKind $operatorKind";
}
}
/// Translate a parser unary operation into an operation in the summary format.
UnlinkedExprOperation _unaryOpFor(int operatorKind) {
switch (operatorKind) {
case BANG_TOKEN:
return UnlinkedExprOperation.not;
case MINUS_TOKEN:
return UnlinkedExprOperation.negate;
default:
throw "Unhandled operator kind $operatorKind";
}
}
/// Visitor over the minimal expression AST to convert them into stack-like
/// expressions used in the summary format.
class Serializer extends RecursiveVisitor {
UnlinkedExprBuilder expression;
final Scope scope;
final bool forConst;
Serializer(this.scope, this.forConst);
handleAs(As n) {
throw new UnimplementedError(); // TODO(paulberry): fix the code below.
// handleType(a.type);
// expression.operations.add(UnlinkedExprOperation.typeCast);
}
handleBinary(Binary n) {
expression.operations.add(_binaryOpFor(n.operator));
}
handleBool(BoolLiteral n) {
expression.operations.add(n.value
? UnlinkedExprOperation.pushTrue
: UnlinkedExprOperation.pushFalse);
}
handleConditional(Conditional n) {
expression.operations.add(UnlinkedExprOperation.conditional);
}
handleConstCreation(ConstCreation n) {
var ctor = n.constructor;
var type = handleType(ctor.type);
if (ctor.name != null) {
throw new UnimplementedError(); // TODO(paulberry): fix the code below.
//var classRef = handleRef(ctor.type.name, push: false);
//var top = scope.top;
//var ref = new LazyEntityRef(ctor.name, top)
// ..reference = (scope.serializeReference(classRef.reference, ctor.name))
// ..typeArguments = type.typeArguments
// ..wasExpanded = true;
//expression.references.add(ref);
} else {
expression.references.add(type);
}
expression.ints.add(n.namedArgs.length);
expression.ints.add(n.positionalArgs.length);
expression.strings.addAll(n.namedArgs.map((a) => a.name));
expression.operations.add(UnlinkedExprOperation.invokeConstructor);
}
handleDouble(DoubleLiteral n) {
expression.operations.add(UnlinkedExprOperation.pushDouble);
expression.doubles.add(n.value);
}
handleIdentical(Identical n) {
expression.references.add(handleRef(new Ref('identical'), push: false));
expression.ints.add(0);
expression.ints.add(2);
expression.ints.add(0);
expression.operations.add(UnlinkedExprOperation.invokeMethodRef);
}
handleInt(IntLiteral n) {
var ints = expression.ints;
var operations = expression.operations;
int value = n.value;
assert(value >= 0);
if (value >= (1 << 32)) {
int numOfComponents = 0;
expression.ints.add(numOfComponents);
void pushComponents(int value) {
if (value >= (1 << 32)) {
pushComponents(value >> 32);
}
numOfComponents++;
ints.add(value & 0xFFFFFFFF);
}
pushComponents(value);
ints[ints.length - 1 - numOfComponents] = numOfComponents;
operations.add(UnlinkedExprOperation.pushLongInt);
} else {
operations.add(UnlinkedExprOperation.pushInt);
ints.add(value);
}
}
handleInvalid(Invalid n) {
expression.isValidConst = false;
throw new UnimplementedError(); // TODO(paulberry): fix the code below.
// expression.operations.add(UnlinkedExprOperation.pushInvalidor);
}
handleIs(Is n) {
throw new UnimplementedError(); // TODO(paulberry): fix the code below.
// handleType(i.type);
// expression.operations.add(UnlinkedExprOperation.typeCheck);
}
handleList(ListLiteral n) {
expression.ints.add(n.values.length);
if (n.elementType == null) {
expression.operations.add(UnlinkedExprOperation.makeUntypedList);
} else {
handleType(n.elementType);
expression.operations.add(UnlinkedExprOperation.makeTypedList);
}
}
handleLoad(Load n) {
expression.strings.add(n.name);
expression.operations.add(UnlinkedExprOperation.extractProperty);
}
handleMap(MapLiteral n) {
expression.ints.add(n.values.length);
if (n.types.isEmpty) {
expression.operations.add(UnlinkedExprOperation.makeUntypedMap);
} else {
n.types.forEach(handleType);
expression.operations.add(UnlinkedExprOperation.makeTypedMap);
}
}
handleNull(NullLiteral n) {
expression.operations.add(UnlinkedExprOperation.pushNull);
}
handleOpaque(Opaque n) {
if (n.type != null) {
handleType(n.type);
expression.operations.add(UnlinkedExprOperation.pushTypedAbstract);
} else {
expression.operations.add(UnlinkedExprOperation.pushUntypedAbstract);
}
}
handleOpaqueOp(OpaqueOp n) {
// nothing to do, recursive visitor serialized subexpression.
}
handleRef(Ref n, {push: true}) {
var ref = n.prefix == null
? new LazyEntityRef(n.name, scope)
: new NestedLazyEntityRef(
handleRef(n.prefix, push: false), n.name, scope);
if (push) {
expression.references.add(ref);
expression.operations.add(UnlinkedExprOperation.pushReference);
}
return ref;
}
handleString(StringLiteral n) {
expression.strings.add(n.value);
expression.operations.add(UnlinkedExprOperation.pushString);
}
handleSymbol(SymbolLiteral n) {
expression.strings.add(n.value);
expression.operations.add(UnlinkedExprOperation.makeSymbol);
}
handleType(TypeRef n) {
var t = handleRef(n.name, push: false);
var args = n.typeArguments ?? [];
t.typeArguments = args.map((a) => handleType(a)).toList();
return t;
}
handleUnary(Unary n) {
expression.operations.add(_unaryOpFor(n.operator));
}
run(Expression root) {
expression = new UnlinkedExprBuilder(
isValidConst: forConst,
operations: [],
assignmentOperators: [],
ints: [],
doubles: [],
strings: [],
references: []);
root.accept(this);
expression.references.forEach((r) => (r as LazyEntityRef).expand());
return expression;
}
}