a91cae8bb4
Note that this affects the binary format, since a type is no longer stored on LogicalExpression. R=kmillikin@google.com Review URL: https://chromereviews.googleplex.com/502297014 .
916 lines
31 KiB
Dart
916 lines
31 KiB
Dart
// 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 kernel.ast_from_binary;
|
|
|
|
import '../ast.dart';
|
|
import 'tag.dart';
|
|
import 'loader.dart';
|
|
import 'dart:convert';
|
|
import 'package:kernel/transformations/flags.dart';
|
|
|
|
class ParseError {
|
|
String filename;
|
|
int byteIndex;
|
|
String message;
|
|
String path;
|
|
|
|
ParseError(this.message, {this.filename, this.byteIndex, this.path});
|
|
|
|
String toString() => '$filename:$byteIndex: $message at $path';
|
|
}
|
|
|
|
class BinaryBuilder {
|
|
final BinaryReferenceLoader loader;
|
|
final List<Library> importTable = <Library>[];
|
|
final List<VariableDeclaration> variableStack = <VariableDeclaration>[];
|
|
final List<LabeledStatement> labelStack = <LabeledStatement>[];
|
|
int labelStackBase = 0;
|
|
final List<SwitchCase> switchCaseStack = <SwitchCase>[];
|
|
final List<TypeParameter> typeParameterStack = <TypeParameter>[];
|
|
final String filename;
|
|
final List<int> _bytes;
|
|
int _byteIndex = 0;
|
|
Library _currentLibrary;
|
|
List<String> _stringTable;
|
|
int _transformerFlags = 0;
|
|
|
|
// If something goes wrong, this list should indicate what library,
|
|
// class, and member was being built.
|
|
List<String> debugPath = <String>[];
|
|
|
|
BinaryBuilder(this.loader, this._bytes, [this.filename]);
|
|
|
|
fail(String message) {
|
|
throw new ParseError(message,
|
|
byteIndex: _byteIndex, filename: filename, path: debugPath.join('::'));
|
|
}
|
|
|
|
int readByte() => _bytes[_byteIndex++];
|
|
|
|
int readUInt() {
|
|
var byte = readByte();
|
|
if (byte & 0x80 == 0) {
|
|
// 0xxxxxxx
|
|
return byte;
|
|
} else if (byte & 0x40 == 0) {
|
|
// 10xxxxxx
|
|
return ((byte & 0x3F) << 8) | readByte();
|
|
} else {
|
|
// 11xxxxxx
|
|
return ((byte & 0x3F) << 24) |
|
|
(readByte() << 16) |
|
|
(readByte() << 8) |
|
|
readByte();
|
|
}
|
|
}
|
|
|
|
int readMagicWord() {
|
|
return (readByte() << 24) |
|
|
(readByte() << 16) |
|
|
(readByte() << 8) |
|
|
readByte();
|
|
}
|
|
|
|
String readStringEntry() {
|
|
int numBytes = readUInt();
|
|
// Utf8Decoder will skip leading BOM characters, but we must preserve them.
|
|
// Collect leading BOMs before passing the bytes onto Utf8Decoder.
|
|
int numByteOrderMarks = 0;
|
|
while (_byteIndex + 2 < _bytes.length &&
|
|
_bytes[_byteIndex] == 0xef &&
|
|
_bytes[_byteIndex + 1] == 0xbb &&
|
|
_bytes[_byteIndex + 2] == 0xbf) {
|
|
++numByteOrderMarks;
|
|
_byteIndex += 3;
|
|
numBytes -= 3;
|
|
}
|
|
String string =
|
|
const Utf8Decoder().convert(_bytes, _byteIndex, _byteIndex + numBytes);
|
|
_byteIndex += numBytes;
|
|
if (numByteOrderMarks > 0) {
|
|
return '\ufeff' * numByteOrderMarks + string;
|
|
}
|
|
return string;
|
|
}
|
|
|
|
void readStringTable() {
|
|
int length = readUInt();
|
|
_stringTable = new List<String>(length);
|
|
for (int i = 0; i < length; ++i) {
|
|
_stringTable[i] = readStringEntry();
|
|
}
|
|
}
|
|
|
|
String readStringReference() {
|
|
return _stringTable[readUInt()];
|
|
}
|
|
|
|
String readStringOrNullIfEmpty() {
|
|
var string = readStringReference();
|
|
return string.isEmpty ? null : string;
|
|
}
|
|
|
|
InferredValue readOptionalInferredValue() {
|
|
if (readAndCheckOptionTag()) {
|
|
Class baseClass = readClassReference(allowNull: true);
|
|
BaseClassKind baseClassKind = BaseClassKind.values[readByte()];
|
|
int valueBits = readByte();
|
|
return new InferredValue(baseClass, baseClassKind, valueBits);
|
|
}
|
|
return null;
|
|
}
|
|
|
|
bool readAndCheckOptionTag() {
|
|
int tag = readByte();
|
|
if (tag == Tag.Nothing) {
|
|
return false;
|
|
} else if (tag == Tag.Something) {
|
|
return true;
|
|
} else {
|
|
throw fail('Invalid Option tag: $tag');
|
|
}
|
|
}
|
|
|
|
List<Expression> readAnnotationList(TreeNode parent) {
|
|
int length = readUInt();
|
|
if (length == 0) return const <Expression>[];
|
|
List<Expression> list = new List<Expression>(length);
|
|
for (int i = 0; i < length; ++i) {
|
|
list[i] = readExpression()..parent = parent;
|
|
}
|
|
return list;
|
|
}
|
|
|
|
void _fillTreeNodeList(
|
|
List<TreeNode> list, TreeNode buildObject(), TreeNode parent) {
|
|
list.length = readUInt();
|
|
for (int i = 0; i < list.length; ++i) {
|
|
list[i] = buildObject()..parent = parent;
|
|
}
|
|
}
|
|
|
|
void _fillNonTreeNodeList(List<Node> list, Node buildObject()) {
|
|
list.length = readUInt();
|
|
for (int i = 0; i < list.length; ++i) {
|
|
list[i] = buildObject();
|
|
}
|
|
}
|
|
|
|
TreeNode readProgramOrLibraryFile(Library makeLibrary()) {
|
|
int magic = readMagicWord();
|
|
switch (magic) {
|
|
case Tag.LibraryFile:
|
|
var library = makeLibrary();
|
|
readUntaggedLibraryFile(library);
|
|
return library;
|
|
case Tag.ProgramFile:
|
|
return readUntaggedProgramFile();
|
|
default:
|
|
throw fail('This is not a binary dart file. '
|
|
'Magic number was: ${magic.toRadixString(16)}');
|
|
}
|
|
}
|
|
|
|
void readLibraryFile(Library library) {
|
|
int magic = readMagicWord();
|
|
if (magic != Tag.LibraryFile) {
|
|
if (magic == Tag.ProgramFile) {
|
|
throw fail('This is a program file, not a library.');
|
|
}
|
|
throw fail('This is not a binary dart file. '
|
|
'Magic number was: ${magic.toRadixString(16)}');
|
|
}
|
|
readUntaggedLibraryFile(library);
|
|
}
|
|
|
|
void readUntaggedLibraryFile(Library library) {
|
|
this._currentLibrary = library;
|
|
readStringTable();
|
|
readImportTable();
|
|
readLibrary();
|
|
}
|
|
|
|
Program readProgramFile() {
|
|
int magic = readMagicWord();
|
|
if (magic != Tag.ProgramFile) {
|
|
if (magic == Tag.LibraryFile) {
|
|
throw fail('This is a library file, not a program.');
|
|
}
|
|
throw fail('This is not a binary dart file. '
|
|
'Magic number was: ${magic.toRadixString(16)}');
|
|
}
|
|
return readUntaggedProgramFile();
|
|
}
|
|
|
|
Program readUntaggedProgramFile() {
|
|
readStringTable();
|
|
importTable.length = readUInt();
|
|
for (int i = 0; i < importTable.length; ++i) {
|
|
importTable[i] = new Library(null);
|
|
}
|
|
for (int i = 0; i < importTable.length; ++i) {
|
|
_currentLibrary = importTable[i];
|
|
readLibrary();
|
|
}
|
|
var mainMethod = readMemberReference();
|
|
return new Program(importTable)..mainMethod = mainMethod;
|
|
}
|
|
|
|
void readImportTable() {
|
|
importTable.length = readUInt();
|
|
if (importTable.isEmpty) {
|
|
throw fail('File must contain at least one import (the self reference)');
|
|
}
|
|
String self = readStringReference();
|
|
if (!self.isEmpty) {
|
|
throw fail('First import must be empty (the self reference)');
|
|
}
|
|
importTable[0] = _currentLibrary;
|
|
for (int i = 1; i < importTable.length; ++i) {
|
|
var importPath = readStringReference();
|
|
importTable[i] = loader.getLibraryReference(_currentLibrary, importPath);
|
|
}
|
|
}
|
|
|
|
void _fillLazilyLoadedList(
|
|
List<TreeNode> list, void buildObject(int tag, int index)) {
|
|
int length = readUInt();
|
|
list.length = length;
|
|
for (int i = 0; i < length; ++i) {
|
|
int tag = readByte();
|
|
buildObject(tag, i);
|
|
}
|
|
}
|
|
|
|
Library readLibraryReference() {
|
|
int index = readUInt();
|
|
return importTable[index];
|
|
}
|
|
|
|
Class readClassReference({bool allowNull: false}) {
|
|
int tag = readByte();
|
|
if (tag == Tag.NullReference) {
|
|
if (!allowNull) {
|
|
throw 'Expected a class reference to be valid but was `null`.';
|
|
}
|
|
return null;
|
|
} else {
|
|
var library = readLibraryReference();
|
|
int index = readUInt();
|
|
return loader.getClassReference(library, tag, index);
|
|
}
|
|
}
|
|
|
|
Member readMemberReference({bool allowNull: false}) {
|
|
int tag = readByte();
|
|
switch (tag) {
|
|
case Tag.LibraryFieldReference:
|
|
case Tag.LibraryProcedureReference:
|
|
var library = readLibraryReference();
|
|
var index = readUInt();
|
|
return loader.getLibraryMemberReference(library, tag, index);
|
|
|
|
case Tag.ClassFieldReference:
|
|
case Tag.ClassConstructorReference:
|
|
case Tag.ClassProcedureReference:
|
|
var classNode = readClassReference();
|
|
var index = readUInt();
|
|
return loader.getClassMemberReference(classNode, tag, index);
|
|
|
|
case Tag.NullReference:
|
|
if (!allowNull) {
|
|
throw 'Expected a member reference to be valid but was `null`.';
|
|
}
|
|
return null;
|
|
|
|
default:
|
|
throw fail('Invalid member reference tag: $tag');
|
|
}
|
|
}
|
|
|
|
Name readName() {
|
|
String text = readStringReference();
|
|
if (text.isNotEmpty && text[0] == '_') {
|
|
return new Name(text, readLibraryReference());
|
|
} else {
|
|
return new Name(text);
|
|
}
|
|
}
|
|
|
|
Uri readImportUri() {
|
|
return Uri.parse(readStringReference());
|
|
}
|
|
|
|
void readLibrary() {
|
|
_currentLibrary.name = readStringOrNullIfEmpty();
|
|
_currentLibrary.importUri = readImportUri();
|
|
debugPath.add(_currentLibrary.name ??
|
|
_currentLibrary.importUri?.toString() ??
|
|
'library');
|
|
_fillLazilyLoadedList(_currentLibrary.classes, (int tag, int index) {
|
|
readClass(loader.getClassReference(_currentLibrary, tag, index), tag);
|
|
});
|
|
_fillLazilyLoadedList(_currentLibrary.fields, (int tag, int index) {
|
|
readField(
|
|
loader.getLibraryMemberReference(_currentLibrary, tag, index), tag);
|
|
});
|
|
_fillLazilyLoadedList(_currentLibrary.procedures, (int tag, int index) {
|
|
readProcedure(
|
|
loader.getLibraryMemberReference(_currentLibrary, tag, index), tag);
|
|
});
|
|
debugPath.removeLast();
|
|
}
|
|
|
|
void readClass(Class node, int tag) {
|
|
assert(node != null);
|
|
switch (tag) {
|
|
case Tag.NormalClass:
|
|
readNormalClass(node);
|
|
break;
|
|
case Tag.MixinClass:
|
|
readMixinClass(node);
|
|
break;
|
|
default:
|
|
throw fail('Invalid class tag: $tag');
|
|
}
|
|
}
|
|
|
|
void readNormalClass(Class node) {
|
|
int flags = readByte();
|
|
node.isAbstract = flags & 0x1 != 0;
|
|
node.name = readStringOrNullIfEmpty();
|
|
node.annotations = readAnnotationList(node);
|
|
debugPath.add(node.name ?? 'normal-class');
|
|
readAndPushTypeParameterList(node.typeParameters, node);
|
|
node.supertype = readDartTypeOption();
|
|
_fillNonTreeNodeList(node.implementedTypes, readDartType);
|
|
_fillLazilyLoadedList(node.fields, (int tag, int index) {
|
|
readField(loader.getClassMemberReference(node, tag, index), tag);
|
|
});
|
|
_fillLazilyLoadedList(node.constructors, (int tag, int index) {
|
|
readConstructor(loader.getClassMemberReference(node, tag, index), tag);
|
|
});
|
|
_fillLazilyLoadedList(node.procedures, (int tag, int index) {
|
|
readProcedure(loader.getClassMemberReference(node, tag, index), tag);
|
|
});
|
|
typeParameterStack.length = 0;
|
|
debugPath.removeLast();
|
|
}
|
|
|
|
void readMixinClass(Class node) {
|
|
int flags = readByte();
|
|
node.isAbstract = flags & 0x1 != 0;
|
|
node.name = readStringOrNullIfEmpty();
|
|
node.annotations = readAnnotationList(node);
|
|
debugPath.add(node.name ?? 'mixin-class');
|
|
readAndPushTypeParameterList(node.typeParameters, node);
|
|
node.supertype = readDartType();
|
|
node.mixedInType = readDartType();
|
|
_fillNonTreeNodeList(node.implementedTypes, readDartType);
|
|
_fillLazilyLoadedList(node.constructors, (int tag, int index) {
|
|
readConstructor(loader.getClassMemberReference(node, tag, index), tag);
|
|
});
|
|
typeParameterStack.length = 0;
|
|
debugPath.removeLast();
|
|
}
|
|
|
|
int getAndResetTransformerFlags() {
|
|
int flags = _transformerFlags;
|
|
_transformerFlags = 0;
|
|
return flags;
|
|
}
|
|
|
|
/// Adds the given flag to the current [Member.transformerFlags].
|
|
void addTransformerFlag(int flags) {
|
|
_transformerFlags |= flags;
|
|
}
|
|
|
|
void readField(Field node, int tag) {
|
|
// Note: as with readProcedure and readConstructor, the tag parameter
|
|
// is unused, but we pass it in to clarify that the tag has already been
|
|
// consumed from the input.
|
|
assert(tag == Tag.Field);
|
|
node.flags = readByte();
|
|
node.name = readName();
|
|
node.annotations = readAnnotationList(node);
|
|
debugPath.add(node.name?.name ?? 'field');
|
|
node.type = readDartType();
|
|
node.inferredValue = readOptionalInferredValue();
|
|
node.initializer = readExpressionOption();
|
|
node.initializer?.parent = node;
|
|
node.transformerFlags = getAndResetTransformerFlags();
|
|
debugPath.removeLast();
|
|
}
|
|
|
|
void readConstructor(Constructor node, int tag) {
|
|
assert(tag == Tag.Constructor);
|
|
node.flags = readByte();
|
|
node.name = readName();
|
|
node.annotations = readAnnotationList(node);
|
|
debugPath.add(node.name?.name ?? 'constructor');
|
|
node.function = readFunctionNode()..parent = node;
|
|
pushVariableDeclarations(node.function.positionalParameters);
|
|
pushVariableDeclarations(node.function.namedParameters);
|
|
_fillTreeNodeList(node.initializers, readInitializer, node);
|
|
variableStack.length = 0;
|
|
node.transformerFlags = getAndResetTransformerFlags();
|
|
debugPath.removeLast();
|
|
}
|
|
|
|
void readProcedure(Procedure node, int tag) {
|
|
assert(tag == Tag.Procedure);
|
|
int kindIndex = readByte();
|
|
node.kind = ProcedureKind.values[kindIndex];
|
|
node.flags = readByte();
|
|
node.name = readName();
|
|
node.annotations = readAnnotationList(node);
|
|
debugPath.add(node.name?.name ?? 'procedure');
|
|
node.function = readFunctionNodeOption();
|
|
node.function?.parent = node;
|
|
node.transformerFlags = getAndResetTransformerFlags();
|
|
debugPath.removeLast();
|
|
}
|
|
|
|
Initializer readInitializer() {
|
|
int tag = readByte();
|
|
switch (tag) {
|
|
case Tag.InvalidInitializer:
|
|
return new InvalidInitializer();
|
|
case Tag.FieldInitializer:
|
|
return new FieldInitializer(readMemberReference(), readExpression());
|
|
case Tag.SuperInitializer:
|
|
return new SuperInitializer(readMemberReference(), readArguments());
|
|
case Tag.RedirectingInitializer:
|
|
return new RedirectingInitializer(
|
|
readMemberReference(), readArguments());
|
|
case Tag.LocalInitializer:
|
|
return new LocalInitializer(readAndPushVariableDeclaration());
|
|
default:
|
|
throw fail('Invalid initializer tag: $tag');
|
|
}
|
|
}
|
|
|
|
FunctionNode readFunctionNodeOption() {
|
|
return readAndCheckOptionTag() ? readFunctionNode() : null;
|
|
}
|
|
|
|
FunctionNode readFunctionNode() {
|
|
AsyncMarker asyncMarker = AsyncMarker.values[readByte()];
|
|
int typeParameterStackHeight = typeParameterStack.length;
|
|
var typeParameters = readAndPushTypeParameterList();
|
|
var requiredParameterCount = readUInt();
|
|
int variableStackHeight = variableStack.length;
|
|
var positional = readAndPushVariableDeclarationList();
|
|
var named = readAndPushVariableDeclarationList();
|
|
var returnType = readDartType();
|
|
var inferredReturnValue = readOptionalInferredValue();
|
|
int oldLabelStackBase = labelStackBase;
|
|
labelStackBase = labelStack.length;
|
|
var body = readStatementOption();
|
|
labelStackBase = oldLabelStackBase;
|
|
variableStack.length = variableStackHeight;
|
|
typeParameterStack.length = typeParameterStackHeight;
|
|
return new FunctionNode(body,
|
|
typeParameters: typeParameters,
|
|
requiredParameterCount: requiredParameterCount,
|
|
positionalParameters: positional,
|
|
namedParameters: named,
|
|
returnType: returnType,
|
|
inferredReturnValue: inferredReturnValue,
|
|
asyncMarker: asyncMarker);
|
|
}
|
|
|
|
void pushVariableDeclaration(VariableDeclaration variable) {
|
|
variableStack.add(variable);
|
|
}
|
|
|
|
void pushVariableDeclarations(List<VariableDeclaration> variables) {
|
|
variableStack.addAll(variables);
|
|
}
|
|
|
|
VariableDeclaration readVariableReference() {
|
|
int index = readUInt();
|
|
if (index >= variableStack.length) {
|
|
throw fail('Invalid variable index: $index');
|
|
}
|
|
return variableStack[index];
|
|
}
|
|
|
|
String logicalOperatorToString(int index) {
|
|
switch (index) {
|
|
case 0:
|
|
return '&&';
|
|
case 1:
|
|
return '||';
|
|
default:
|
|
throw fail('Invalid logical operator index: $index');
|
|
}
|
|
}
|
|
|
|
List<Expression> readExpressionList() {
|
|
return new List<Expression>.generate(readUInt(), (i) => readExpression());
|
|
}
|
|
|
|
Expression readExpressionOption() {
|
|
return readAndCheckOptionTag() ? readExpression() : null;
|
|
}
|
|
|
|
Expression readExpression() {
|
|
int tagByte = readByte();
|
|
int tag = tagByte & Tag.SpecializedTagHighBit == 0
|
|
? tagByte
|
|
: (tagByte & Tag.SpecializedTagMask);
|
|
switch (tag) {
|
|
case Tag.InvalidExpression:
|
|
return new InvalidExpression();
|
|
case Tag.VariableGet:
|
|
return new VariableGet(readVariableReference(), readDartTypeOption());
|
|
case Tag.SpecializedVariableGet:
|
|
int index = tagByte & Tag.SpecializedPayloadMask;
|
|
return new VariableGet(variableStack[index]);
|
|
case Tag.VariableSet:
|
|
return new VariableSet(readVariableReference(), readExpression());
|
|
case Tag.SpecializedVariableSet:
|
|
int index = tagByte & Tag.SpecializedPayloadMask;
|
|
return new VariableSet(variableStack[index], readExpression());
|
|
case Tag.PropertyGet:
|
|
return new PropertyGet(
|
|
readExpression(), readName(), readMemberReference(allowNull: true));
|
|
case Tag.PropertySet:
|
|
return new PropertySet(readExpression(), readName(), readExpression(),
|
|
readMemberReference(allowNull: true));
|
|
case Tag.SuperPropertyGet:
|
|
addTransformerFlag(TransformerFlag.superCalls);
|
|
return new SuperPropertyGet(
|
|
readName(), readMemberReference(allowNull: true));
|
|
case Tag.SuperPropertySet:
|
|
addTransformerFlag(TransformerFlag.superCalls);
|
|
return new SuperPropertySet(
|
|
readName(), readExpression(), readMemberReference(allowNull: true));
|
|
case Tag.DirectPropertyGet:
|
|
return new DirectPropertyGet(readExpression(), readMemberReference());
|
|
case Tag.DirectPropertySet:
|
|
return new DirectPropertySet(
|
|
readExpression(), readMemberReference(), readExpression());
|
|
case Tag.StaticGet:
|
|
return new StaticGet(readMemberReference());
|
|
case Tag.StaticSet:
|
|
return new StaticSet(readMemberReference(), readExpression());
|
|
case Tag.MethodInvocation:
|
|
return new MethodInvocation(readExpression(), readName(),
|
|
readArguments(), readMemberReference(allowNull: true));
|
|
case Tag.SuperMethodInvocation:
|
|
addTransformerFlag(TransformerFlag.superCalls);
|
|
return new SuperMethodInvocation(
|
|
readName(), readArguments(), readMemberReference(allowNull: true));
|
|
case Tag.DirectMethodInvocation:
|
|
return new DirectMethodInvocation(
|
|
readExpression(), readMemberReference(), readArguments());
|
|
case Tag.StaticInvocation:
|
|
return new StaticInvocation(readMemberReference(), readArguments(),
|
|
isConst: false);
|
|
case Tag.ConstStaticInvocation:
|
|
return new StaticInvocation(readMemberReference(), readArguments(),
|
|
isConst: true);
|
|
case Tag.ConstructorInvocation:
|
|
return new ConstructorInvocation(readMemberReference(), readArguments(),
|
|
isConst: false);
|
|
case Tag.ConstConstructorInvocation:
|
|
return new ConstructorInvocation(readMemberReference(), readArguments(),
|
|
isConst: true);
|
|
case Tag.Not:
|
|
return new Not(readExpression());
|
|
case Tag.LogicalExpression:
|
|
return new LogicalExpression(readExpression(),
|
|
logicalOperatorToString(readByte()), readExpression());
|
|
case Tag.ConditionalExpression:
|
|
return new ConditionalExpression(readExpression(), readExpression(),
|
|
readExpression(), readDartTypeOption());
|
|
case Tag.StringConcatenation:
|
|
return new StringConcatenation(readExpressionList());
|
|
case Tag.IsExpression:
|
|
return new IsExpression(readExpression(), readDartType());
|
|
case Tag.AsExpression:
|
|
return new AsExpression(readExpression(), readDartType());
|
|
case Tag.StringLiteral:
|
|
return new StringLiteral(readStringReference());
|
|
case Tag.SpecializedIntLiteral:
|
|
int biasedValue = tagByte & Tag.SpecializedPayloadMask;
|
|
return new IntLiteral(biasedValue - Tag.SpecializedIntLiteralBias);
|
|
case Tag.PositiveIntLiteral:
|
|
return new IntLiteral(readUInt());
|
|
case Tag.NegativeIntLiteral:
|
|
return new IntLiteral(-readUInt());
|
|
case Tag.BigIntLiteral:
|
|
return new IntLiteral(int.parse(readStringReference()));
|
|
case Tag.DoubleLiteral:
|
|
return new DoubleLiteral(double.parse(readStringReference()));
|
|
case Tag.TrueLiteral:
|
|
return new BoolLiteral(true);
|
|
case Tag.FalseLiteral:
|
|
return new BoolLiteral(false);
|
|
case Tag.NullLiteral:
|
|
return new NullLiteral();
|
|
case Tag.SymbolLiteral:
|
|
return new SymbolLiteral(readStringReference());
|
|
case Tag.TypeLiteral:
|
|
return new TypeLiteral(readDartType());
|
|
case Tag.ThisExpression:
|
|
return new ThisExpression();
|
|
case Tag.Rethrow:
|
|
return new Rethrow();
|
|
case Tag.Throw:
|
|
return new Throw(readExpression());
|
|
case Tag.ListLiteral:
|
|
var typeArgument = readDartType();
|
|
return new ListLiteral(readExpressionList(),
|
|
typeArgument: typeArgument, isConst: false);
|
|
case Tag.ConstListLiteral:
|
|
var typeArgument = readDartType();
|
|
return new ListLiteral(readExpressionList(),
|
|
typeArgument: typeArgument, isConst: true);
|
|
case Tag.MapLiteral:
|
|
var keyType = readDartType();
|
|
var valueType = readDartType();
|
|
return new MapLiteral(readMapEntryList(),
|
|
keyType: keyType, valueType: valueType, isConst: false);
|
|
case Tag.ConstMapLiteral:
|
|
var keyType = readDartType();
|
|
var valueType = readDartType();
|
|
return new MapLiteral(readMapEntryList(),
|
|
keyType: keyType, valueType: valueType, isConst: true);
|
|
case Tag.AwaitExpression:
|
|
return new AwaitExpression(readExpression());
|
|
case Tag.FunctionExpression:
|
|
return new FunctionExpression(readFunctionNode());
|
|
case Tag.Let:
|
|
var variable = readVariableDeclaration();
|
|
int stackHeight = variableStack.length;
|
|
pushVariableDeclaration(variable);
|
|
var body = readExpression();
|
|
variableStack.length = stackHeight;
|
|
return new Let(variable, body);
|
|
case Tag.BlockExpression:
|
|
var body = readBlock();
|
|
var expression = readExpression();
|
|
return new BlockExpression(body, expression);
|
|
default:
|
|
throw fail('Invalid expression tag: $tag');
|
|
}
|
|
}
|
|
|
|
List<MapEntry> readMapEntryList() {
|
|
return new List<MapEntry>.generate(readUInt(), (i) => readMapEntry());
|
|
}
|
|
|
|
MapEntry readMapEntry() {
|
|
return new MapEntry(readExpression(), readExpression());
|
|
}
|
|
|
|
List<Statement> readStatementList() {
|
|
return new List<Statement>.generate(readUInt(), (i) => readStatement());
|
|
}
|
|
|
|
Statement readStatementOrNullIfEmpty() {
|
|
var node = readStatement();
|
|
if (node is EmptyStatement) {
|
|
return null;
|
|
} else {
|
|
return node;
|
|
}
|
|
}
|
|
|
|
Statement readStatementOption() {
|
|
return readAndCheckOptionTag() ? readStatement() : null;
|
|
}
|
|
|
|
Statement readStatement() {
|
|
int tag = readByte();
|
|
switch (tag) {
|
|
case Tag.InvalidStatement:
|
|
return new InvalidStatement();
|
|
case Tag.ExpressionStatement:
|
|
return new ExpressionStatement(readExpression());
|
|
case Tag.Block:
|
|
return readBlock();
|
|
case Tag.EmptyStatement:
|
|
return new EmptyStatement();
|
|
case Tag.AssertStatement:
|
|
return new AssertStatement(readExpression(), readExpressionOption());
|
|
case Tag.LabeledStatement:
|
|
var label = new LabeledStatement(null);
|
|
labelStack.add(label);
|
|
label.body = readStatement()..parent = label;
|
|
labelStack.removeLast();
|
|
return label;
|
|
case Tag.BreakStatement:
|
|
int index = readUInt();
|
|
return new BreakStatement(labelStack[labelStackBase + index]);
|
|
case Tag.WhileStatement:
|
|
return new WhileStatement(readExpression(), readStatement());
|
|
case Tag.DoStatement:
|
|
return new DoStatement(readStatement(), readExpression());
|
|
case Tag.ForStatement:
|
|
int variableStackHeight = variableStack.length;
|
|
var variables = readAndPushVariableDeclarationList();
|
|
var condition = readExpressionOption();
|
|
var updates = readExpressionList();
|
|
var body = readStatement();
|
|
variableStack.length = variableStackHeight;
|
|
return new ForStatement(variables, condition, updates, body);
|
|
case Tag.ForInStatement:
|
|
case Tag.AsyncForInStatement:
|
|
bool isAsync = tag == Tag.AsyncForInStatement;
|
|
int variableStackHeight = variableStack.length;
|
|
var variable = readAndPushVariableDeclaration();
|
|
var iterable = readExpression();
|
|
var body = readStatement();
|
|
variableStack.length = variableStackHeight;
|
|
return new ForInStatement(variable, iterable, body, isAsync: isAsync);
|
|
case Tag.SwitchStatement:
|
|
var expression = readExpression();
|
|
int count = readUInt();
|
|
List<SwitchCase> cases =
|
|
new List<SwitchCase>.generate(count, (i) => new SwitchCase.empty());
|
|
switchCaseStack.addAll(cases);
|
|
for (int i = 0; i < cases.length; ++i) {
|
|
var caseNode = cases[i];
|
|
_fillTreeNodeList(caseNode.expressions, readExpression, caseNode);
|
|
caseNode.isDefault = readByte() == 1;
|
|
caseNode.body = readStatement()..parent = caseNode;
|
|
}
|
|
switchCaseStack.length -= count;
|
|
return new SwitchStatement(expression, cases);
|
|
case Tag.ContinueSwitchStatement:
|
|
int index = readUInt();
|
|
return new ContinueSwitchStatement(switchCaseStack[index]);
|
|
case Tag.IfStatement:
|
|
return new IfStatement(
|
|
readExpression(), readStatement(), readStatementOrNullIfEmpty());
|
|
case Tag.ReturnStatement:
|
|
return new ReturnStatement(readExpressionOption());
|
|
case Tag.TryCatch:
|
|
return new TryCatch(readStatement(), readCatchList());
|
|
case Tag.TryFinally:
|
|
return new TryFinally(readStatement(), readStatement());
|
|
case Tag.YieldStatement:
|
|
int flags = readByte();
|
|
return new YieldStatement(readExpression(),
|
|
isYieldStar: flags & YieldStatement.FlagYieldStar != 0,
|
|
isNative: flags & YieldStatement.FlagNative != 0);
|
|
case Tag.VariableDeclaration:
|
|
var variable = readVariableDeclaration();
|
|
variableStack.add(variable); // Will be popped by the enclosing scope.
|
|
return variable;
|
|
case Tag.FunctionDeclaration:
|
|
var variable = readVariableDeclaration();
|
|
variableStack.add(variable); // Will be popped by the enclosing scope.
|
|
var function = readFunctionNode();
|
|
return new FunctionDeclaration(variable, function);
|
|
default:
|
|
throw fail('Invalid statement tag: $tag');
|
|
}
|
|
}
|
|
|
|
List<Catch> readCatchList() {
|
|
return new List<Catch>.generate(readUInt(), (i) => readCatch());
|
|
}
|
|
|
|
Catch readCatch() {
|
|
int variableStackHeight = variableStack.length;
|
|
var guard = readDartType();
|
|
var exception = readAndPushVariableDeclarationOption();
|
|
var stackTrace = readAndPushVariableDeclarationOption();
|
|
var body = readStatement();
|
|
variableStack.length = variableStackHeight;
|
|
return new Catch(exception, body, guard: guard, stackTrace: stackTrace);
|
|
}
|
|
|
|
Block readBlock() {
|
|
int stackHeight = variableStack.length;
|
|
var body = readStatementList();
|
|
variableStack.length = stackHeight;
|
|
return new Block(body);
|
|
}
|
|
|
|
List<DartType> readDartTypeList() {
|
|
return new List<DartType>.generate(readUInt(), (i) => readDartType());
|
|
}
|
|
|
|
DartType readDartTypeOption() {
|
|
return readAndCheckOptionTag() ? readDartType() : null;
|
|
}
|
|
|
|
DartType readDartType() {
|
|
int tag = readByte();
|
|
switch (tag) {
|
|
case Tag.BottomType:
|
|
return const BottomType();
|
|
case Tag.InvalidType:
|
|
return const InvalidType();
|
|
case Tag.DynamicType:
|
|
return const DynamicType();
|
|
case Tag.VoidType:
|
|
return const VoidType();
|
|
case Tag.InterfaceType:
|
|
return new InterfaceType(readClassReference(), readDartTypeList());
|
|
case Tag.SimpleInterfaceType:
|
|
return new InterfaceType(readClassReference(), const <DartType>[]);
|
|
case Tag.FunctionType:
|
|
int typeParameterStackHeight = typeParameterStack.length;
|
|
var typeParameters = readAndPushTypeParameterList();
|
|
var requiredParameterCount = readUInt();
|
|
var positional = readDartTypeList();
|
|
int namedParameterCount = readUInt();
|
|
var named = <String, DartType>{};
|
|
for (int i = 0; i < namedParameterCount; ++i) {
|
|
var name = readStringReference();
|
|
var type = readDartType();
|
|
named[name] = type;
|
|
}
|
|
var returnType = readDartType();
|
|
typeParameterStack.length = typeParameterStackHeight;
|
|
return new FunctionType(positional, returnType,
|
|
typeParameters: typeParameters,
|
|
requiredParameterCount: requiredParameterCount,
|
|
namedParameters: named);
|
|
case Tag.SimpleFunctionType:
|
|
var positional = readDartTypeList();
|
|
var returnType = readDartType();
|
|
return new FunctionType(positional, returnType);
|
|
case Tag.TypeParameterType:
|
|
int index = readUInt();
|
|
return new TypeParameterType(typeParameterStack[index]);
|
|
default:
|
|
throw fail('Invalid dart type tag: $tag');
|
|
}
|
|
}
|
|
|
|
List<TypeParameter> readAndPushTypeParameterList(
|
|
[List<TypeParameter> list, TreeNode parent]) {
|
|
int length = readUInt();
|
|
if (length == 0) return list ?? <TypeParameter>[];
|
|
if (list == null) {
|
|
list = new List<TypeParameter>.generate(
|
|
length, (i) => new TypeParameter(null, null)..parent = parent);
|
|
} else {
|
|
list.length = length;
|
|
for (int i = 0; i < length; ++i) {
|
|
list[i] = new TypeParameter(null, null)..parent = parent;
|
|
}
|
|
}
|
|
typeParameterStack.addAll(list);
|
|
for (int i = 0; i < list.length; ++i) {
|
|
readTypeParameter(list[i]);
|
|
}
|
|
return list;
|
|
}
|
|
|
|
void readTypeParameter(TypeParameter node) {
|
|
node.name = readStringOrNullIfEmpty();
|
|
node.bound = readDartType();
|
|
}
|
|
|
|
Arguments readArguments() {
|
|
var typeArguments = readDartTypeList();
|
|
var positional = readExpressionList();
|
|
var named = readNamedExpressionList();
|
|
return new Arguments(positional, types: typeArguments, named: named);
|
|
}
|
|
|
|
List<NamedExpression> readNamedExpressionList() {
|
|
return new List<NamedExpression>.generate(
|
|
readUInt(), (i) => readNamedExpression());
|
|
}
|
|
|
|
NamedExpression readNamedExpression() {
|
|
return new NamedExpression(readStringReference(), readExpression());
|
|
}
|
|
|
|
List<VariableDeclaration> readAndPushVariableDeclarationList() {
|
|
return new List<VariableDeclaration>.generate(
|
|
readUInt(), (i) => readAndPushVariableDeclaration());
|
|
}
|
|
|
|
VariableDeclaration readAndPushVariableDeclarationOption() {
|
|
return readAndCheckOptionTag() ? readAndPushVariableDeclaration() : null;
|
|
}
|
|
|
|
VariableDeclaration readAndPushVariableDeclaration() {
|
|
var variable = readVariableDeclaration();
|
|
variableStack.add(variable);
|
|
return variable;
|
|
}
|
|
|
|
VariableDeclaration readVariableDeclaration() {
|
|
int flags = readByte();
|
|
return new VariableDeclaration(readStringOrNullIfEmpty(),
|
|
type: readDartType(),
|
|
inferredValue: readOptionalInferredValue(),
|
|
initializer: readExpressionOption(),
|
|
isFinal: flags & 0x1 != 0,
|
|
isConst: flags & 0x2 != 0);
|
|
}
|
|
}
|