// Copyright (c) 2018, 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.text_serializer; import '../ast.dart'; import 'serializer_combinators.dart'; import '../visitor.dart' show ExpressionVisitor; abstract class Tagger { String tag(T object); } class NameTagger implements Tagger { const NameTagger(); String tag(Name name) => name.isPrivate ? "private" : "public"; } TextSerializer publicName = Wrapped((w) => w.text, (u) => Name(u), const DartString()); TextSerializer privateName = Wrapped, Name>( (w) => Tuple2(w.text, w.library!.reference.canonicalName!), (u) => Name.byReference(u.first, u.second.reference), Tuple2Serializer(DartString(), CanonicalNameSerializer())); TextSerializer nameSerializer = new Case( const NameTagger(), {"public": publicName, "private": privateName}); class ExpressionTagger extends ExpressionVisitor implements Tagger { const ExpressionTagger(); String tag(Expression expression) => expression.accept(this); String visitStringLiteral(StringLiteral _) => "string"; String visitIntLiteral(IntLiteral _) => "int"; String visitDoubleLiteral(DoubleLiteral _) => "double"; String visitBoolLiteral(BoolLiteral _) => "bool"; String visitNullLiteral(NullLiteral _) => "null"; String visitInvalidExpression(InvalidExpression _) => "invalid"; String visitNot(Not _) => "not"; String visitLogicalExpression(LogicalExpression expression) { return logicalExpressionOperatorToString(expression.operatorEnum); } String visitStringConcatenation(StringConcatenation _) => "concat"; String visitSymbolLiteral(SymbolLiteral _) => "symbol"; String visitThisExpression(ThisExpression _) => "this"; String visitRethrow(Rethrow _) => "rethrow"; String visitThrow(Throw _) => "throw"; String visitAwaitExpression(AwaitExpression _) => "await"; String visitConditionalExpression(ConditionalExpression _) => "cond"; String visitIsExpression(IsExpression _) => "is"; String visitAsExpression(AsExpression _) => "as"; String visitTypeLiteral(TypeLiteral _) => "type"; String visitListLiteral(ListLiteral expression) { return expression.isConst ? "const-list" : "list"; } String visitSetLiteral(SetLiteral expression) { return expression.isConst ? "const-set" : "set"; } String visitMapLiteral(MapLiteral expression) { return expression.isConst ? "const-map" : "map"; } String visitLet(Let _) => "let"; String visitPropertyGet(PropertyGet _) => "get-prop"; String visitPropertySet(PropertySet _) => "set-prop"; String visitInstanceGet(InstanceGet _) => "get-instance"; String visitInstanceSet(InstanceSet _) => "set-instance"; String visitDynamicGet(DynamicGet _) => "get-dynamic"; String visitDynamicSet(DynamicSet _) => "set-dynamic"; String visitInstanceTearOff(InstanceTearOff _) => "tearoff-instance"; String visitFunctionTearOff(FunctionTearOff _) => "tearoff-function"; String visitSuperPropertyGet(SuperPropertyGet _) => "get-super"; String visitSuperPropertySet(SuperPropertySet _) => "set-super"; String visitMethodInvocation(MethodInvocation _) => "invoke-method"; String visitInstanceInvocation(InstanceInvocation _) => "invoke-instance"; String visitInstanceGetterInvocation(InstanceGetterInvocation _) => "invoke-instance-getter"; String visitDynamicInvocation(DynamicInvocation _) => "invoke-dynamic"; String visitFunctionInvocation(FunctionInvocation _) => "invoke-function"; String visitLocalFunctionInvocation(LocalFunctionInvocation _) => "invoke-local-function"; String visitEqualsNull(EqualsNull _) => "equals-null"; String visitEqualsCall(EqualsCall _) => "equals-call"; String visitSuperMethodInvocation(SuperMethodInvocation _) => "invoke-super"; String visitVariableGet(VariableGet _) => "get-var"; String visitVariableSet(VariableSet _) => "set-var"; String visitStaticGet(StaticGet _) => "get-static"; String visitStaticSet(StaticSet _) => "set-static"; String visitStaticTearOff(StaticTearOff _) => "tearoff-static"; String visitStaticInvocation(StaticInvocation expression) { return expression.isConst ? "invoke-const-static" : "invoke-static"; } String visitConstructorInvocation(ConstructorInvocation expression) { return expression.isConst ? "invoke-const-constructor" : "invoke-constructor"; } String visitFunctionExpression(FunctionExpression _) => "fun"; String visitListConcatenation(ListConcatenation _) => "lists"; String visitSetConcatenation(SetConcatenation _) => "sets"; String visitMapConcatenation(MapConcatenation _) => "maps"; String visitBlockExpression(BlockExpression _) => "let-block"; String visitInstantiation(Instantiation _) => "apply"; String visitNullCheck(NullCheck _) => "not-null"; String visitFileUriExpression(FileUriExpression _) => "with-uri"; String visitCheckLibraryIsLoaded(CheckLibraryIsLoaded _) => "is-loaded"; String visitLoadLibrary(LoadLibrary _) => "load"; String visitConstantExpression(ConstantExpression _) => "const"; String visitInstanceCreation(InstanceCreation _) => "object"; @override String defaultExpression(Expression node) { throw new UnimplementedError( 'Unimplemented expression $node (${node.runtimeType})'); } } const TextSerializer invalidExpressionSerializer = const Wrapped( unwrapInvalidExpression, wrapInvalidExpression, const DartString()); String? unwrapInvalidExpression(InvalidExpression expression) { return expression.message; } InvalidExpression wrapInvalidExpression(String? message) { return new InvalidExpression(message); } TextSerializer notSerializer = new Wrapped(unwrapNot, wrapNot, expressionSerializer); Expression unwrapNot(Not expression) => expression.operand; Not wrapNot(Expression operand) => new Not(operand); TextSerializer logicalAndSerializer = new Wrapped( unwrapLogicalExpression, wrapLogicalAnd, new Tuple2Serializer(expressionSerializer, expressionSerializer)); Tuple2 unwrapLogicalExpression( LogicalExpression expression) { return new Tuple2(expression.left, expression.right); } LogicalExpression wrapLogicalAnd(Tuple2 tuple) { return new LogicalExpression( tuple.first, LogicalExpressionOperator.AND, tuple.second); } TextSerializer logicalOrSerializer = new Wrapped( unwrapLogicalExpression, wrapLogicalOr, new Tuple2Serializer(expressionSerializer, expressionSerializer)); LogicalExpression wrapLogicalOr(Tuple2 tuple) { return new LogicalExpression( tuple.first, LogicalExpressionOperator.OR, tuple.second); } TextSerializer stringConcatenationSerializer = new Wrapped( unwrapStringConcatenation, wrapStringConcatenation, new ListSerializer(expressionSerializer)); List unwrapStringConcatenation(StringConcatenation expression) { return expression.expressions; } StringConcatenation wrapStringConcatenation(List expressions) { return new StringConcatenation(expressions); } const TextSerializer stringLiteralSerializer = const Wrapped(unwrapStringLiteral, wrapStringLiteral, const DartString()); String unwrapStringLiteral(StringLiteral literal) => literal.value; StringLiteral wrapStringLiteral(String value) => new StringLiteral(value); const TextSerializer intLiteralSerializer = const Wrapped(unwrapIntLiteral, wrapIntLiteral, const DartInt()); int unwrapIntLiteral(IntLiteral literal) => literal.value; IntLiteral wrapIntLiteral(int value) => new IntLiteral(value); const TextSerializer doubleLiteralSerializer = const Wrapped(unwrapDoubleLiteral, wrapDoubleLiteral, const DartDouble()); double unwrapDoubleLiteral(DoubleLiteral literal) => literal.value; DoubleLiteral wrapDoubleLiteral(double value) => new DoubleLiteral(value); const TextSerializer boolLiteralSerializer = const Wrapped(unwrapBoolLiteral, wrapBoolLiteral, const DartBool()); bool unwrapBoolLiteral(BoolLiteral literal) => literal.value; BoolLiteral wrapBoolLiteral(bool value) => new BoolLiteral(value); const TextSerializer nullLiteralSerializer = const Wrapped(unwrapNullLiteral, wrapNullLiteral, const Nothing()); void unwrapNullLiteral(NullLiteral literal) {} NullLiteral wrapNullLiteral(void ignored) => new NullLiteral(); const TextSerializer symbolLiteralSerializer = const Wrapped(unwrapSymbolLiteral, wrapSymbolLiteral, const DartString()); String unwrapSymbolLiteral(SymbolLiteral expression) => expression.value; SymbolLiteral wrapSymbolLiteral(String value) => new SymbolLiteral(value); const TextSerializer thisExpressionSerializer = const Wrapped(unwrapThisExpression, wrapThisExpression, const Nothing()); void unwrapThisExpression(ThisExpression expression) {} ThisExpression wrapThisExpression(void ignored) => new ThisExpression(); const TextSerializer rethrowSerializer = const Wrapped(unwrapRethrow, wrapRethrow, const Nothing()); void unwrapRethrow(Rethrow expression) {} Rethrow wrapRethrow(void ignored) => new Rethrow(); TextSerializer throwSerializer = new Wrapped(unwrapThrow, wrapThrow, expressionSerializer); Expression unwrapThrow(Throw expression) => expression.expression; Throw wrapThrow(Expression expression) => new Throw(expression); TextSerializer awaitExpressionSerializer = new Wrapped( unwrapAwaitExpression, wrapAwaitExpression, expressionSerializer); Expression unwrapAwaitExpression(AwaitExpression expression) => expression.operand; AwaitExpression wrapAwaitExpression(Expression operand) => new AwaitExpression(operand); TextSerializer conditionalExpressionSerializer = new Wrapped( unwrapConditionalExpression, wrapConditionalExpression, new Tuple4Serializer(expressionSerializer, dartTypeSerializer, expressionSerializer, expressionSerializer)); Tuple4 unwrapConditionalExpression(ConditionalExpression expression) { return new Tuple4(expression.condition, expression.staticType, expression.then, expression.otherwise); } ConditionalExpression wrapConditionalExpression( Tuple4 tuple) { return new ConditionalExpression( tuple.first, tuple.third, tuple.fourth, tuple.second); } TextSerializer isExpressionSerializer = new Wrapped( unwrapIsExpression, wrapIsExpression, new Tuple2Serializer(expressionSerializer, dartTypeSerializer)); Tuple2 unwrapIsExpression(IsExpression expression) { return new Tuple2(expression.operand, expression.type); } IsExpression wrapIsExpression(Tuple2 tuple) { return new IsExpression(tuple.first, tuple.second); } TextSerializer asExpressionSerializer = new Wrapped( unwrapAsExpression, wrapAsExpression, new Tuple2Serializer(expressionSerializer, dartTypeSerializer)); Tuple2 unwrapAsExpression(AsExpression expression) { return new Tuple2(expression.operand, expression.type); } AsExpression wrapAsExpression(Tuple2 tuple) { return new AsExpression(tuple.first, tuple.second); } TextSerializer typeLiteralSerializer = new Wrapped(unwrapTypeLiteral, wrapTypeLiteral, dartTypeSerializer); DartType unwrapTypeLiteral(TypeLiteral expression) => expression.type; TypeLiteral wrapTypeLiteral(DartType type) => new TypeLiteral(type); TextSerializer listLiteralSerializer = new Wrapped( unwrapListLiteral, wrapListLiteral, new Tuple2Serializer( dartTypeSerializer, new ListSerializer(expressionSerializer))); Tuple2> unwrapListLiteral(ListLiteral expression) { return new Tuple2(expression.typeArgument, expression.expressions); } ListLiteral wrapListLiteral(Tuple2> tuple) { return new ListLiteral(tuple.second, typeArgument: tuple.first, isConst: false); } TextSerializer constListLiteralSerializer = new Wrapped( unwrapListLiteral, wrapConstListLiteral, new Tuple2Serializer( dartTypeSerializer, new ListSerializer(expressionSerializer))); ListLiteral wrapConstListLiteral(Tuple2> tuple) { return new ListLiteral(tuple.second, typeArgument: tuple.first, isConst: true); } TextSerializer setLiteralSerializer = new Wrapped( unwrapSetLiteral, wrapSetLiteral, new Tuple2Serializer( dartTypeSerializer, new ListSerializer(expressionSerializer))); Tuple2> unwrapSetLiteral(SetLiteral expression) { return new Tuple2(expression.typeArgument, expression.expressions); } SetLiteral wrapSetLiteral(Tuple2> tuple) { return new SetLiteral(tuple.second, typeArgument: tuple.first, isConst: false); } TextSerializer constSetLiteralSerializer = new Wrapped( unwrapSetLiteral, wrapConstSetLiteral, new Tuple2Serializer( dartTypeSerializer, new ListSerializer(expressionSerializer))); SetLiteral wrapConstSetLiteral(Tuple2> tuple) { return new SetLiteral(tuple.second, typeArgument: tuple.first, isConst: true); } TextSerializer mapLiteralSerializer = new Wrapped( unwrapMapLiteral, wrapMapLiteral, new Tuple3Serializer(dartTypeSerializer, dartTypeSerializer, new ListSerializer(expressionSerializer))); Tuple3> unwrapMapLiteral( MapLiteral expression) { List entries = new List.filled(2 * expression.entries.length, dummyExpression); for (int from = 0, to = 0; from < expression.entries.length; ++from) { MapEntry entry = expression.entries[from]; entries[to++] = entry.key; entries[to++] = entry.value; } return new Tuple3(expression.keyType, expression.valueType, entries); } MapLiteral wrapMapLiteral(Tuple3> tuple) { List entries = new List.filled(tuple.third.length ~/ 2, dummyMapEntry); for (int from = 0, to = 0; to < entries.length; ++to) { entries[to] = new MapEntry(tuple.third[from++], tuple.third[from++]); } return new MapLiteral(entries, keyType: tuple.first, valueType: tuple.second, isConst: false); } TextSerializer constMapLiteralSerializer = new Wrapped( unwrapMapLiteral, wrapConstMapLiteral, new Tuple3Serializer(dartTypeSerializer, dartTypeSerializer, new ListSerializer(expressionSerializer))); MapLiteral wrapConstMapLiteral( Tuple3> tuple) { List entries = new List.filled(tuple.third.length ~/ 2, dummyMapEntry); for (int from = 0, to = 0; to < entries.length; ++to) { entries[to] = new MapEntry(tuple.third[from++], tuple.third[from++]); } return new MapLiteral(entries, keyType: tuple.first, valueType: tuple.second, isConst: true); } TextSerializer letSerializer = new Wrapped(unwrapLet, wrapLet, new Bind(variableDeclarationSerializer, expressionSerializer)); Tuple2 unwrapLet(Let expression) { return new Tuple2(expression.variable, expression.body); } Let wrapLet(Tuple2 tuple) { return new Let(tuple.first, tuple.second); } TextSerializer propertyGetSerializer = new Wrapped( unwrapPropertyGet, wrapPropertyGet, new Tuple2Serializer(expressionSerializer, nameSerializer)); Tuple2 unwrapPropertyGet(PropertyGet expression) { return new Tuple2(expression.receiver, expression.name); } PropertyGet wrapPropertyGet(Tuple2 tuple) { return new PropertyGet(tuple.first, tuple.second); } TextSerializer propertySetSerializer = new Wrapped( unwrapPropertySet, wrapPropertySet, new Tuple3Serializer( expressionSerializer, nameSerializer, expressionSerializer)); Tuple3 unwrapPropertySet(PropertySet expression) { return new Tuple3(expression.receiver, expression.name, expression.value); } PropertySet wrapPropertySet(Tuple3 tuple) { return new PropertySet(tuple.first, tuple.second, tuple.third); } TextSerializer instanceGetSerializer = new Wrapped< Tuple5, InstanceGet>( unwrapInstanceGet, wrapInstanceGet, new Tuple5Serializer(instanceAccessKindSerializer, expressionSerializer, nameSerializer, canonicalNameSerializer, dartTypeSerializer)); Tuple5 unwrapInstanceGet(InstanceGet expression) { return new Tuple5( expression.kind, expression.receiver, expression.name, expression.interfaceTargetReference.canonicalName!, expression.resultType); } InstanceGet wrapInstanceGet( Tuple5 tuple) { return new InstanceGet.byReference(tuple.first, tuple.second, tuple.third, interfaceTargetReference: tuple.fourth.reference, resultType: tuple.fifth); } TextSerializer instanceSetSerializer = new Wrapped< Tuple5, InstanceSet>( unwrapInstanceSet, wrapInstanceSet, new Tuple5Serializer(instanceAccessKindSerializer, expressionSerializer, nameSerializer, expressionSerializer, canonicalNameSerializer)); Tuple5 unwrapInstanceSet(InstanceSet expression) { return new Tuple5(expression.kind, expression.receiver, expression.name, expression.value, expression.interfaceTargetReference.canonicalName!); } InstanceSet wrapInstanceSet( Tuple5 tuple) { return new InstanceSet.byReference( tuple.first, tuple.second, tuple.third, tuple.fourth, interfaceTargetReference: tuple.fifth.reference); } TextSerializer dynamicGetSerializer = new Wrapped, DynamicGet>( unwrapDynamicGet, wrapDynamicGet, new Tuple3Serializer( dynamicAccessKindSerializer, expressionSerializer, nameSerializer)); Tuple3 unwrapDynamicGet( DynamicGet expression) { return new Tuple3(expression.kind, expression.receiver, expression.name); } DynamicGet wrapDynamicGet(Tuple3 tuple) { return new DynamicGet(tuple.first, tuple.second, tuple.third); } TextSerializer dynamicSetSerializer = new Wrapped< Tuple4, DynamicSet>( unwrapDynamicSet, wrapDynamicSet, new Tuple4Serializer(dynamicAccessKindSerializer, expressionSerializer, nameSerializer, expressionSerializer)); Tuple4 unwrapDynamicSet( DynamicSet expression) { return new Tuple4( expression.kind, expression.receiver, expression.name, expression.value); } DynamicSet wrapDynamicSet( Tuple4 tuple) { return new DynamicSet(tuple.first, tuple.second, tuple.third, tuple.fourth); } TextSerializer instanceTearOffSerializer = new Wrapped< Tuple5, InstanceTearOff>( unwrapInstanceTearOff, wrapInstanceTearOff, new Tuple5Serializer(instanceAccessKindSerializer, expressionSerializer, nameSerializer, canonicalNameSerializer, dartTypeSerializer)); Tuple5 unwrapInstanceTearOff(InstanceTearOff expression) { return new Tuple5( expression.kind, expression.receiver, expression.name, expression.interfaceTargetReference.canonicalName!, expression.resultType); } InstanceTearOff wrapInstanceTearOff( Tuple5 tuple) { return new InstanceTearOff.byReference(tuple.first, tuple.second, tuple.third, interfaceTargetReference: tuple.fourth.reference, resultType: tuple.fifth); } TextSerializer functionTearOffSerializer = new Wrapped( unwrapFunctionTearOff, wrapFunctionTearOff, expressionSerializer); Expression unwrapFunctionTearOff(FunctionTearOff expression) { return expression.receiver; } FunctionTearOff wrapFunctionTearOff(Expression expression) { return new FunctionTearOff(expression); } TextSerializer superPropertyGetSerializer = new Wrapped(unwrapSuperPropertyGet, wrapSuperPropertyGet, nameSerializer); Name unwrapSuperPropertyGet(SuperPropertyGet expression) { return expression.name; } SuperPropertyGet wrapSuperPropertyGet(Name name) { return new SuperPropertyGet(name); } TextSerializer superPropertySetSerializer = new Wrapped( unwrapSuperPropertySet, wrapSuperPropertySet, new Tuple2Serializer(nameSerializer, expressionSerializer)); Tuple2 unwrapSuperPropertySet(SuperPropertySet expression) { return new Tuple2(expression.name, expression.value); } SuperPropertySet wrapSuperPropertySet(Tuple2 tuple) { return new SuperPropertySet(tuple.first, tuple.second, null); } TextSerializer methodInvocationSerializer = new Wrapped( unwrapMethodInvocation, wrapMethodInvocation, new Tuple3Serializer( expressionSerializer, nameSerializer, argumentsSerializer)); Tuple3 unwrapMethodInvocation( MethodInvocation expression) { return new Tuple3(expression.receiver, expression.name, expression.arguments); } MethodInvocation wrapMethodInvocation( Tuple3 tuple) { return new MethodInvocation(tuple.first, tuple.second, tuple.third); } const Map instanceAccessKindToName = const { InstanceAccessKind.Instance: "instance", InstanceAccessKind.Object: "object", InstanceAccessKind.Nullable: "nullable", InstanceAccessKind.Inapplicable: "inapplicable", }; class InstanceAccessKindTagger implements Tagger { const InstanceAccessKindTagger(); String tag(InstanceAccessKind kind) { return instanceAccessKindToName[kind] ?? (throw StateError("Unknown InstanceAccessKind flag value: ${kind}.")); } } TextSerializer instanceAccessKindSerializer = Case(InstanceAccessKindTagger(), convertFlagsMap(instanceAccessKindToName)); TextSerializer instanceInvocationSerializer = new Wrapped< Tuple6, InstanceInvocation>( unwrapInstanceInvocation, wrapInstanceInvocation, new Tuple6Serializer( instanceAccessKindSerializer, expressionSerializer, nameSerializer, argumentsSerializer, canonicalNameSerializer, dartTypeSerializer)); Tuple6 unwrapInstanceInvocation(InstanceInvocation expression) { return new Tuple6( expression.kind, expression.receiver, expression.name, expression.arguments, expression.interfaceTargetReference.canonicalName!, expression.functionType); } InstanceInvocation wrapInstanceInvocation( Tuple6 tuple) { return new InstanceInvocation.byReference( tuple.first, tuple.second, tuple.third, tuple.fourth, interfaceTargetReference: tuple.fifth.reference, functionType: tuple.sixth as FunctionType); } TextSerializer< InstanceGetterInvocation> instanceGetterInvocationSerializer = new Wrapped< Tuple6, InstanceGetterInvocation>( unwrapInstanceGetterInvocation, wrapInstanceGetterInvocation, new Tuple6Serializer( instanceAccessKindSerializer, expressionSerializer, nameSerializer, argumentsSerializer, const CanonicalNameSerializer(), Optional(dartTypeSerializer))); Tuple6 unwrapInstanceGetterInvocation(InstanceGetterInvocation expression) { return new Tuple6( expression.kind, expression.receiver, expression.name, expression.arguments, expression.interfaceTargetReference.canonicalName!, expression.functionType); } InstanceGetterInvocation wrapInstanceGetterInvocation( Tuple6 tuple) { return new InstanceGetterInvocation.byReference( tuple.first, tuple.second, tuple.third, tuple.fourth, interfaceTargetReference: tuple.fifth.reference, functionType: tuple.sixth as FunctionType?); } const Map dynamicAccessKindToName = const { DynamicAccessKind.Dynamic: "dynamic", DynamicAccessKind.Never: "never", DynamicAccessKind.Invalid: "invalid", DynamicAccessKind.Unresolved: "unresolved", }; class DynamicAccessKindTagger implements Tagger { const DynamicAccessKindTagger(); String tag(DynamicAccessKind kind) { return dynamicAccessKindToName[kind] ?? (throw StateError("Unknown DynamicAccessKind flag value: ${kind}.")); } } TextSerializer dynamicAccessKindSerializer = Case(DynamicAccessKindTagger(), convertFlagsMap(dynamicAccessKindToName)); TextSerializer dynamicInvocationSerializer = new Wrapped< Tuple4, DynamicInvocation>( unwrapDynamicInvocation, wrapDynamicInvocation, new Tuple4Serializer(dynamicAccessKindSerializer, expressionSerializer, nameSerializer, argumentsSerializer)); Tuple4 unwrapDynamicInvocation( DynamicInvocation expression) { return new Tuple4(expression.kind, expression.receiver, expression.name, expression.arguments); } DynamicInvocation wrapDynamicInvocation( Tuple4 tuple) { return new DynamicInvocation( tuple.first, tuple.second, tuple.third, tuple.fourth); } const Map functionAccessKindToName = const { FunctionAccessKind.Function: "function", FunctionAccessKind.FunctionType: "function-type", FunctionAccessKind.Inapplicable: "inapplicable", FunctionAccessKind.Nullable: "nullable", }; class FunctionAccessKindTagger implements Tagger { const FunctionAccessKindTagger(); String tag(FunctionAccessKind kind) { return functionAccessKindToName[kind] ?? (throw StateError("Unknown FunctionAccessKind flag value: ${kind}.")); } } TextSerializer functionAccessKindSerializer = Case(FunctionAccessKindTagger(), convertFlagsMap(functionAccessKindToName)); TextSerializer functionInvocationSerializer = new Wrapped< Tuple4, FunctionInvocation>( unwrapFunctionInvocation, wrapFunctionInvocation, new Tuple4Serializer(functionAccessKindSerializer, expressionSerializer, argumentsSerializer, new Optional(dartTypeSerializer))); Tuple4 unwrapFunctionInvocation(FunctionInvocation expression) { return new Tuple4(expression.kind, expression.receiver, expression.arguments, expression.functionType); } FunctionInvocation wrapFunctionInvocation( Tuple4 tuple) { return new FunctionInvocation(tuple.first, tuple.second, tuple.third, functionType: tuple.fourth as FunctionType?); } TextSerializer localFunctionInvocationSerializer = new Wrapped, LocalFunctionInvocation>( unwrapLocalFunctionInvocation, wrapLocalFunctionInvocation, new Tuple3Serializer(const ScopedUse(), argumentsSerializer, dartTypeSerializer)); Tuple3 unwrapLocalFunctionInvocation( LocalFunctionInvocation expression) { return new Tuple3( expression.variable, expression.arguments, expression.functionType); } LocalFunctionInvocation wrapLocalFunctionInvocation( Tuple3 tuple) { return new LocalFunctionInvocation(tuple.first, tuple.second, functionType: tuple.third as FunctionType); } TextSerializer equalsNullSerializer = new Wrapped( unwrapEqualsNull, wrapEqualsNull, expressionSerializer); Expression unwrapEqualsNull(EqualsNull expression) { return expression.expression; } EqualsNull wrapEqualsNull(Expression expression) { return new EqualsNull(expression); } TextSerializer equalsCallSerializer = new Wrapped< Tuple4, EqualsCall>( unwrapEqualsCall, wrapEqualsCall, new Tuple4Serializer(expressionSerializer, expressionSerializer, canonicalNameSerializer, dartTypeSerializer)); Tuple4 unwrapEqualsCall( EqualsCall expression) { return new Tuple4( expression.left, expression.right, expression.interfaceTargetReference.canonicalName!, expression.functionType); } EqualsCall wrapEqualsCall( Tuple4 tuple) { return new EqualsCall.byReference(tuple.first, tuple.second, interfaceTargetReference: tuple.third.reference, functionType: tuple.fourth as FunctionType); } TextSerializer superMethodInvocationSerializer = new Wrapped(unwrapSuperMethodInvocation, wrapSuperMethodInvocation, new Tuple2Serializer(nameSerializer, argumentsSerializer)); Tuple2 unwrapSuperMethodInvocation( SuperMethodInvocation expression) { return new Tuple2(expression.name, expression.arguments); } SuperMethodInvocation wrapSuperMethodInvocation(Tuple2 tuple) { return new SuperMethodInvocation(tuple.first, tuple.second); } TextSerializer variableGetSerializer = new Wrapped, VariableGet>( unwrapVariableGet, wrapVariableGet, new Tuple2Serializer(const ScopedUse(), new Optional(dartTypeSerializer))); Tuple2 unwrapVariableGet(VariableGet node) { return new Tuple2( node.variable, node.promotedType); } VariableGet wrapVariableGet(Tuple2 tuple) { return new VariableGet(tuple.first, tuple.second); } TextSerializer variableSetSerializer = new Wrapped( unwrapVariableSet, wrapVariableSet, new Tuple2Serializer( const ScopedUse(), expressionSerializer)); Tuple2 unwrapVariableSet(VariableSet node) { return new Tuple2(node.variable, node.value); } VariableSet wrapVariableSet(Tuple2 tuple) { return new VariableSet(tuple.first, tuple.second); } const CanonicalNameSerializer canonicalNameSerializer = const CanonicalNameSerializer(); class CanonicalNameSerializer extends TextSerializer { static const String delimiter = "::"; const CanonicalNameSerializer(); static void writeName(CanonicalName name, StringBuffer buffer) { if (!name.isRoot) { if (!name.parent!.isRoot) { writeName(name.parent!, buffer); buffer.write(delimiter); } buffer.write(name.name); } } CanonicalName readFrom( Iterator stream, DeserializationState? state) { if (state == null) { throw StateError( "No deserialization state provided for ${runtimeType}.readFrom."); } String string = const DartString().readFrom(stream, state); CanonicalName name = state.nameRoot; for (String s in string.split(delimiter)) { name = name.getChild(s); } return name; } void writeTo( StringBuffer buffer, CanonicalName name, SerializationState? state) { StringBuffer sb = new StringBuffer(); writeName(name, sb); const DartString().writeTo(buffer, sb.toString(), state); } } const TextSerializer staticGetSerializer = const Wrapped(unwrapStaticGet, wrapStaticGet, canonicalNameSerializer); CanonicalName unwrapStaticGet(StaticGet expression) { return expression.targetReference.canonicalName!; } StaticGet wrapStaticGet(CanonicalName name) { return new StaticGet.byReference(name.reference); } const TextSerializer staticTearOffSerializer = const Wrapped( unwrapStaticTearOff, wrapStaticTearOff, canonicalNameSerializer); CanonicalName unwrapStaticTearOff(StaticTearOff expression) { return expression.targetReference.canonicalName!; } StaticTearOff wrapStaticTearOff(CanonicalName name) { return new StaticTearOff.byReference(name.reference); } TextSerializer staticSetSerializer = new Wrapped( unwrapStaticSet, wrapStaticSet, new Tuple2Serializer(canonicalNameSerializer, expressionSerializer)); Tuple2 unwrapStaticSet(StaticSet expression) { return new Tuple2( expression.targetReference.canonicalName!, expression.value); } StaticSet wrapStaticSet(Tuple2 tuple) { return new StaticSet.byReference(tuple.first.reference, tuple.second); } TextSerializer staticInvocationSerializer = new Wrapped( unwrapStaticInvocation, wrapStaticInvocation, new Tuple2Serializer(canonicalNameSerializer, argumentsSerializer)); Tuple2 unwrapStaticInvocation( StaticInvocation expression) { return new Tuple2( expression.targetReference.canonicalName!, expression.arguments); } StaticInvocation wrapStaticInvocation(Tuple2 tuple) { return new StaticInvocation.byReference(tuple.first.reference, tuple.second, isConst: false); } TextSerializer constStaticInvocationSerializer = new Wrapped( unwrapStaticInvocation, wrapConstStaticInvocation, new Tuple2Serializer(canonicalNameSerializer, argumentsSerializer)); StaticInvocation wrapConstStaticInvocation( Tuple2 tuple) { return new StaticInvocation.byReference(tuple.first.reference, tuple.second, isConst: true); } TextSerializer constructorInvocationSerializer = new Wrapped(unwrapConstructorInvocation, wrapConstructorInvocation, new Tuple2Serializer(canonicalNameSerializer, argumentsSerializer)); Tuple2 unwrapConstructorInvocation( ConstructorInvocation expression) { return new Tuple2( expression.targetReference.canonicalName!, expression.arguments); } ConstructorInvocation wrapConstructorInvocation( Tuple2 tuple) { return new ConstructorInvocation.byReference( tuple.first.reference, tuple.second, isConst: false); } TextSerializer constConstructorInvocationSerializer = new Wrapped(unwrapConstructorInvocation, wrapConstConstructorInvocation, Tuple2Serializer(canonicalNameSerializer, argumentsSerializer)); ConstructorInvocation wrapConstConstructorInvocation( Tuple2 tuple) { return new ConstructorInvocation.byReference( tuple.first.reference, tuple.second, isConst: true); } TextSerializer functionExpressionSerializer = new Wrapped( unwrapFunctionExpression, wrapFunctionExpression, functionNodeSerializer); FunctionNode unwrapFunctionExpression(FunctionExpression expression) { return expression.function; } FunctionExpression wrapFunctionExpression(FunctionNode node) { return new FunctionExpression(node); } TextSerializer listConcatenationSerializer = Wrapped>, ListConcatenation>( (lc) => Tuple2(lc.typeArgument, lc.lists), (t) => ListConcatenation(t.second, typeArgument: t.first), Tuple2Serializer( dartTypeSerializer, ListSerializer(expressionSerializer))); TextSerializer setConcatenationSerializer = Wrapped>, SetConcatenation>( (sc) => Tuple2(sc.typeArgument, sc.sets), (t) => SetConcatenation(t.second, typeArgument: t.first), Tuple2Serializer( dartTypeSerializer, ListSerializer(expressionSerializer))); TextSerializer mapConcatenationSerializer = Wrapped>, MapConcatenation>( (mc) => Tuple3(mc.keyType, mc.valueType, mc.maps), (t) => MapConcatenation(t.third, keyType: t.first, valueType: t.second), Tuple3Serializer(dartTypeSerializer, dartTypeSerializer, ListSerializer(expressionSerializer))); TextSerializer blockExpressionSerializer = Wrapped, Expression?>, BlockExpression>( (w) => Tuple2(w.body.statements, w.value), (u) => BlockExpression(Block(u.first), u.second!), const BlockSerializer()); TextSerializer instantiationSerializer = Wrapped>, Instantiation>( (i) => Tuple2(i.expression, i.typeArguments), (t) => Instantiation(t.first, t.second), Tuple2Serializer( expressionSerializer, ListSerializer(dartTypeSerializer))); TextSerializer nullCheckSerializer = Wrapped( (nc) => nc.operand, (op) => NullCheck(op), expressionSerializer); TextSerializer fileUriExpressionSerializer = Wrapped, FileUriExpression>( (fue) => Tuple2(fue.expression, fue.fileUri), (t) => FileUriExpression(t.first, t.second), Tuple2Serializer(expressionSerializer, const UriSerializer())); TextSerializer checkLibraryIsLoadedSerializer = Wrapped((clil) => clil.import, (i) => CheckLibraryIsLoaded(i), libraryDependencySerializer); TextSerializer loadLibrarySerializer = Wrapped( (ll) => ll.import, (i) => LoadLibrary(i), libraryDependencySerializer); TextSerializer constantExpressionSerializer = Wrapped, ConstantExpression>( (ce) => Tuple2(ce.constant, ce.type), (t) => ConstantExpression(t.first, t.second), Tuple2Serializer(constantSerializer, dartTypeSerializer)); TextSerializer instanceCreationSerializer = Wrapped< Tuple6, List, List, List, List>, InstanceCreation>( (ic) => Tuple6( ic.classReference.canonicalName!, ic.typeArguments, ic.fieldValues.keys.map((r) => r.canonicalName!).toList(), ic.fieldValues.values.toList(), ic.asserts, ic.unusedArguments), (t) => InstanceCreation( t.first.reference, t.second, Map.fromIterables(t.third.map((cn) => cn.reference), t.fourth), t.fifth, t.sixth), Tuple6Serializer( CanonicalNameSerializer(), ListSerializer(dartTypeSerializer), ListSerializer(CanonicalNameSerializer()), ListSerializer(expressionSerializer), ListSerializer(assertStatementSerializer), ListSerializer(expressionSerializer))); Case expressionSerializer = new Case.uninitialized(const ExpressionTagger()); TextSerializer nullableExpressionSerializer = new Optional(expressionSerializer); TextSerializer namedExpressionSerializer = new Wrapped( unwrapNamedExpression, wrapNamedExpression, new Tuple2Serializer(const DartString(), expressionSerializer)); Tuple2 unwrapNamedExpression(NamedExpression expression) { return new Tuple2(expression.name, expression.value); } NamedExpression wrapNamedExpression(Tuple2 tuple) { return new NamedExpression(tuple.first, tuple.second); } TextSerializer argumentsSerializer = new Wrapped( unwrapArguments, wrapArguments, Tuple3Serializer( new ListSerializer(dartTypeSerializer), new ListSerializer(expressionSerializer), new ListSerializer(namedExpressionSerializer))); Tuple3, List, List> unwrapArguments( Arguments arguments) { return new Tuple3(arguments.types, arguments.positional, arguments.named); } Arguments wrapArguments( Tuple3, List, List> tuple) { return new Arguments(tuple.second, types: tuple.first, named: tuple.third); } const Map variableDeclarationFlagToName = const { VariableDeclaration.FlagFinal: "final", VariableDeclaration.FlagConst: "const", VariableDeclaration.FlagFieldFormal: "field-formal", VariableDeclaration.FlagCovariant: "covariant", VariableDeclaration.FlagGenericCovariantImpl: "generic-covariant-impl", VariableDeclaration.FlagLate: "late", VariableDeclaration.FlagRequired: "required", VariableDeclaration.FlagLowered: "lowered", }; class VariableDeclarationFlagTagger implements Tagger { String tag(int flag) { return variableDeclarationFlagToName[flag] ?? (throw StateError("Unknown VariableDeclaration flag value: ${flag}.")); } } TextSerializer variableDeclarationFlagsSerializer = Wrapped, int>( (w) => List.generate(30, (i) => w & (1 << i)) .where((f) => f != 0) .toList(), (u) => u.fold(0, (fs, f) => fs |= f), ListSerializer(Case(VariableDeclarationFlagTagger(), convertFlagsMap(variableDeclarationFlagToName)))); TextSerializer variableDeclarationSerializer = Wrapped, VariableDeclaration>( (v) => Tuple2(v.name, v), (t) => t.second..name = t.first, Binder( new Wrapped>, VariableDeclaration>( (w) => Tuple4(w.flags, w.type, w.initializer, w.annotations), (u) => u.fourth.fold( VariableDeclaration(null, flags: u.first, type: u.second, initializer: u.third), (v, a) => v..addAnnotation(a)), Tuple4Serializer( variableDeclarationFlagsSerializer, dartTypeSerializer, new Optional(expressionSerializer), new ListSerializer(expressionSerializer))), )); TextSerializer typeParameterSerializer = Wrapped, TypeParameter>( (p) => Tuple2(p.name, p), (t) => t.second..name = t.first, Binder(Wrapped((_) => null, (_) => TypeParameter(), const Nothing()))); TextSerializer> typeParametersSerializer = new Zip( new Rebind( new Zip( new Rebind(new ListSerializer(typeParameterSerializer), new ListSerializer(dartTypeSerializer)), zipTypeParameterBound, unzipTypeParameterBound), new ListSerializer(dartTypeSerializer)), zipTypeParameterDefaultType, unzipTypeParameterDefaultType); TypeParameter zipTypeParameterBound(TypeParameter node, DartType? bound) { return node..bound = bound; } Tuple2 unzipTypeParameterBound(TypeParameter node) { return new Tuple2(node, node.bound); } TypeParameter zipTypeParameterDefaultType( TypeParameter node, DartType? defaultType) { return node..defaultType = defaultType; } Tuple2 unzipTypeParameterDefaultType( TypeParameter node) { return new Tuple2(node, node.defaultType); } class DartTypeTagger extends DartTypeVisitor implements Tagger { const DartTypeTagger(); String tag(DartType type) => type.accept(this); String visitInvalidType(InvalidType _) => "invalid"; String visitDynamicType(DynamicType _) => "dynamic"; String visitVoidType(VoidType _) => "void"; String visitFunctionType(FunctionType _) => "->"; String visitTypeParameterType(TypeParameterType _) => "par"; String visitInterfaceType(InterfaceType _) => "interface"; String visitNeverType(NeverType _) => "never"; String visitTypedefType(TypedefType _) => "typedef"; String visitFutureOrType(FutureOrType _) => "futureor"; String visitNullType(NullType _) => "null-type"; @override String defaultDartType(DartType node) { throw UnimplementedError('Unimplemented type $node (${node.runtimeType})'); } } const TextSerializer invalidTypeSerializer = const Wrapped(unwrapInvalidType, wrapInvalidType, const Nothing()); void unwrapInvalidType(InvalidType type) {} InvalidType wrapInvalidType(void ignored) => const InvalidType(); const TextSerializer dynamicTypeSerializer = const Wrapped(unwrapDynamicType, wrapDynamicType, const Nothing()); void unwrapDynamicType(DynamicType type) {} DynamicType wrapDynamicType(void ignored) => const DynamicType(); const TextSerializer voidTypeSerializer = const Wrapped(unwrapVoidType, wrapVoidType, const Nothing()); void unwrapVoidType(VoidType type) {} VoidType wrapVoidType(void ignored) => const VoidType(); const TextSerializer neverTypeSerializer = const Wrapped(unwrapNeverType, wrapNeverType, const Nothing()); void unwrapNeverType(NeverType type) {} NeverType wrapNeverType(void ignored) => const NeverType.legacy(); // TODO(dmitryas): Also handle nameParameters, and typedefType. TextSerializer functionTypeSerializer = new Wrapped( unwrapFunctionType, wrapFunctionType, new Bind( typeParametersSerializer, new Tuple4Serializer( new ListSerializer(dartTypeSerializer), new ListSerializer(dartTypeSerializer), new ListSerializer(namedTypeSerializer), dartTypeSerializer))); Tuple2, Tuple4, List, List, DartType>> unwrapFunctionType(FunctionType type) { return new Tuple2( type.typeParameters, new Tuple4( type.positionalParameters.sublist(0, type.requiredParameterCount), type.positionalParameters.sublist(type.requiredParameterCount), type.namedParameters, type.returnType)); } FunctionType wrapFunctionType( Tuple2, Tuple4, List, List, DartType>> tuple) { return new FunctionType(tuple.second.first + tuple.second.second, tuple.second.fourth, Nullability.legacy, requiredParameterCount: tuple.second.first.length, typeParameters: tuple.first, namedParameters: tuple.second.third); } TextSerializer namedTypeSerializer = new Wrapped(unwrapNamedType, wrapNamedType, Tuple2Serializer(const DartString(), dartTypeSerializer)); Tuple2 unwrapNamedType(NamedType namedType) { return new Tuple2(namedType.name, namedType.type); } NamedType wrapNamedType(Tuple2 tuple) { return new NamedType(tuple.first, tuple.second); } TextSerializer typeParameterTypeSerializer = new Wrapped( unwrapTypeParameterType, wrapTypeParameterType, Tuple2Serializer( new ScopedUse(), new Optional(dartTypeSerializer))); Tuple2 unwrapTypeParameterType( TypeParameterType node) { return new Tuple2(node.parameter, node.promotedBound); } TypeParameterType wrapTypeParameterType( Tuple2 tuple) { return new TypeParameterType(tuple.first, Nullability.legacy, tuple.second); } TextSerializer interfaceTypeSerializer = new Wrapped( unwrapInterfaceType, wrapInterfaceType, Tuple2Serializer( canonicalNameSerializer, new ListSerializer(dartTypeSerializer))); Tuple2> unwrapInterfaceType(InterfaceType node) { return new Tuple2(node.className.canonicalName!, node.typeArguments); } InterfaceType wrapInterfaceType(Tuple2> tuple) { return new InterfaceType.byReference( tuple.first.reference, Nullability.legacy, tuple.second); } TextSerializer typedefTypeSerializer = new Wrapped( unwrapTypedefType, wrapTypedefType, Tuple2Serializer( canonicalNameSerializer, new ListSerializer(dartTypeSerializer))); Tuple2> unwrapTypedefType(TypedefType node) { return new Tuple2(node.typedefReference.canonicalName!, node.typeArguments); } TypedefType wrapTypedefType(Tuple2> tuple) { return new TypedefType.byReference( tuple.first.reference, Nullability.legacy, tuple.second); } TextSerializer futureOrTypeSerializer = new Wrapped(unwrapFutureOrType, wrapFutureOrType, dartTypeSerializer); DartType unwrapFutureOrType(FutureOrType node) { return node.typeArgument; } FutureOrType wrapFutureOrType(DartType typeArgument) { return new FutureOrType(typeArgument, Nullability.legacy); } TextSerializer nullTypeSerializer = new Wrapped(unwrapNullType, wrapNullType, const Nothing()); void unwrapNullType(NullType type) {} NullType wrapNullType(void ignored) => const NullType(); Case dartTypeSerializer = new Case.uninitialized(const DartTypeTagger()); class StatementTagger extends StatementVisitor implements Tagger { const StatementTagger(); String tag(Statement statement) => statement.accept(this); String visitExpressionStatement(ExpressionStatement _) => "expr"; String visitReturnStatement(ReturnStatement node) { return node.expression == null ? "ret-void" : "ret"; } String visitYieldStatement(YieldStatement _) => "yield"; String visitBlock(Block _) => "block"; String visitVariableDeclaration(VariableDeclaration _) => "local"; String visitIfStatement(IfStatement node) { return node.otherwise == null ? "if" : "if-else"; } String visitEmptyStatement(EmptyStatement node) => "skip"; String visitWhileStatement(WhileStatement node) => "while"; String visitDoStatement(DoStatement node) => "do-while"; String visitForStatement(ForStatement node) => "for"; String visitForInStatement(ForInStatement node) { return node.isAsync ? "await-for-in" : "for-in"; } String visitAssertStatement(AssertStatement node) => "assert"; String visitAssertBlock(AssertBlock node) => "assert-block"; String visitLabeledStatement(LabeledStatement node) => "label"; String visitBreakStatement(BreakStatement node) => "break"; String visitTryFinally(TryFinally node) => "try-finally"; String visitTryCatch(TryCatch node) => "try-catch"; String visitSwitchStatement(SwitchStatement node) => "switch"; String visitContinueSwitchStatement(ContinueSwitchStatement node) => "continue"; String visitFunctionDeclaration(FunctionDeclaration node) => "local-fun"; @override String defaultStatement(Statement node) { throw new UnimplementedError( "Unimplemented statement $node (${node.runtimeType})"); } } TextSerializer expressionStatementSerializer = new Wrapped( unwrapExpressionStatement, wrapExpressionStatement, expressionSerializer); Expression unwrapExpressionStatement(ExpressionStatement statement) { return statement.expression; } ExpressionStatement wrapExpressionStatement(Expression expression) { return new ExpressionStatement(expression); } TextSerializer returnStatementSerializer = new Wrapped( unwrapReturnStatement, wrapReturnStatement, expressionSerializer); Expression? unwrapReturnStatement(ReturnStatement statement) { return statement.expression; } ReturnStatement wrapReturnStatement(Expression? expression) { return new ReturnStatement(expression); } TextSerializer returnVoidStatementSerializer = new Wrapped( unwrapReturnVoidStatement, wrapReturnVoidStatement, const Nothing()); void unwrapReturnVoidStatement(void ignored) {} ReturnStatement wrapReturnVoidStatement(void ignored) => new ReturnStatement(); TextSerializer yieldStatementSerializer = new Wrapped(unwrapYieldStatement, wrapYieldStatement, expressionSerializer); Expression unwrapYieldStatement(YieldStatement node) => node.expression; YieldStatement wrapYieldStatement(Expression expression) { return new YieldStatement(expression); } TextSerializer assertStatementSerializer = Wrapped, AssertStatement>( (a) => Tuple4(a.condition, a.message, a.conditionStartOffset, a.conditionEndOffset), (t) => AssertStatement(t.first, message: t.second, conditionStartOffset: t.third, conditionEndOffset: t.fourth), Tuple4Serializer(expressionSerializer, nullableExpressionSerializer, const DartInt(), const DartInt())); TextSerializer blockSerializer = Wrapped, Expression?>, Block>( (w) => Tuple2(w.statements, null), (u) => Block(u.first), const BlockSerializer()); TextSerializer assertBlockSerializer = Wrapped, Expression?>, AssertBlock>( (w) => Tuple2(w.statements, null), (u) => AssertBlock(u.first), const BlockSerializer()); /// Serializer for [Block]s. /// /// [BlockSerializer] is a combination of [ListSerializer] and [Bind]. As in /// the case of [ListSerializer], [BlockSerializer] is a sequence of statements. /// As in the case of [Bind], a statement in a block can be a /// [VariableDeclaration] introducing binders that are bound in the rest of the /// statements in the block. Effectively, [BlockSerializer] could have been /// expressed in terms of [ListSerializer] and [Bind], but that would transform /// blocks like {stmt1; stmt2; stmt3;} into {stmt1; {stmt2; {stmt3; {}}}} via /// the round-trip, and an extra pass will be required to flatten the /// unnecessary nested blocks. Instead, [BlockSerializer] is implemented /// without direct invocations of either [ListSerializer] or [Bind], but with a /// certain internal correspondence to how they work. class BlockSerializer extends TextSerializer, Expression?>> { const BlockSerializer(); Tuple2, Expression?> readFrom( Iterator stream, DeserializationState? state) { if (state == null) { throw StateError( "No deserialization state provided for ${runtimeType}.readFrom."); } Object? iterator = stream.current; if (iterator is! Iterator) { throw StateError("Expected a list, found an atom: '${iterator}'."); } iterator.moveNext(); List statements = []; DeserializationState currentState = state; while (iterator.current != null) { currentState = new DeserializationState( new DeserializationEnvironment(currentState.environment), currentState.nameRoot); statements.add(statementSerializer.readFrom(iterator, currentState)); currentState.environment.extend(); } stream.moveNext(); Expression? expression = nullableExpressionSerializer.readFrom(stream, currentState); return new Tuple2(statements, expression); } void writeTo(StringBuffer buffer, Tuple2, Expression?> tuple, SerializationState? state) { if (state == null) { throw StateError( "No serialization state provided for ${runtimeType}.writeTo."); } buffer.write('('); SerializationState currentState = state; for (int i = 0; i < tuple.first.length; ++i) { if (i != 0) buffer.write(' '); currentState = new SerializationState( new SerializationEnvironment(currentState.environment)); statementSerializer.writeTo(buffer, tuple.first[i], currentState); currentState.environment.extend(); } buffer.write(') '); nullableExpressionSerializer.writeTo(buffer, tuple.second, currentState); } } TextSerializer ifStatementSerializer = new Wrapped( unwrapIfStatement, wrapIfStatement, Tuple2Serializer(expressionSerializer, statementSerializer)); Tuple2 unwrapIfStatement(IfStatement node) { return new Tuple2(node.condition, node.then); } IfStatement wrapIfStatement(Tuple2 tuple) { return new IfStatement(tuple.first, tuple.second, null); } TextSerializer ifElseStatementSerializer = new Wrapped( unwrapIfElseStatement, wrapIfElseStatement, Tuple3Serializer( expressionSerializer, statementSerializer, statementSerializer)); Tuple3 unwrapIfElseStatement( IfStatement node) { return new Tuple3(node.condition, node.then, node.otherwise); } IfStatement wrapIfElseStatement( Tuple3 tuple) { return new IfStatement(tuple.first, tuple.second, tuple.third); } TextSerializer emptyStatementSerializer = new Wrapped(unwrapEmptyStatement, wrapEmptyStatement, const Nothing()); void unwrapEmptyStatement(EmptyStatement node) {} EmptyStatement wrapEmptyStatement(void ignored) => new EmptyStatement(); TextSerializer whileStatementSerializer = new Wrapped( unwrapWhileStatement, wrapWhileStatement, new Tuple2Serializer(expressionSerializer, statementSerializer)); Tuple2 unwrapWhileStatement(WhileStatement node) { return new Tuple2(node.condition, node.body); } WhileStatement wrapWhileStatement(Tuple2 tuple) { return new WhileStatement(tuple.first, tuple.second); } TextSerializer doStatementSerializer = new Wrapped( unwrapDoStatement, wrapDoStatement, new Tuple2Serializer(statementSerializer, expressionSerializer)); Tuple2 unwrapDoStatement(DoStatement node) { return new Tuple2(node.body, node.condition); } DoStatement wrapDoStatement(Tuple2 tuple) { return new DoStatement(tuple.first, tuple.second); } TextSerializer forStatementSerializer = Wrapped< Tuple2, Tuple3, Statement>>, ForStatement>( (w) => Tuple2(w.variables, Tuple3(w.condition, w.updates, w.body)), (u) => ForStatement(u.first, u.second.first, u.second.second, u.second.third), new Bind( ListSerializer(variableDeclarationSerializer), new Tuple3Serializer(Optional(expressionSerializer), new ListSerializer(expressionSerializer), statementSerializer))); TextSerializer forInStatementSerializer = new Wrapped( unwrapForInStatement, wrapForInStatement, new Tuple2Serializer(expressionSerializer, new Bind(variableDeclarationSerializer, statementSerializer))); Tuple2> unwrapForInStatement( ForInStatement node) { return new Tuple2(node.iterable, new Tuple2(node.variable, node.body)); } ForInStatement wrapForInStatement( Tuple2> tuple) { return new ForInStatement( tuple.second.first, tuple.first, tuple.second.second); } TextSerializer awaitForInStatementSerializer = new Wrapped( unwrapForInStatement, wrapAwaitForInStatement, new Tuple2Serializer(expressionSerializer, new Bind(variableDeclarationSerializer, statementSerializer))); ForInStatement wrapAwaitForInStatement( Tuple2> tuple) { return new ForInStatement( tuple.second.first, tuple.first, tuple.second.second, isAsync: true); } TextSerializer labeledStatementSerializer = Wrapped, LabeledStatement>( (ls) => Tuple2(ls, ls.body), (t) => t.first..body = t.second, Bind( Wrapped, LabeledStatement>( (ls) => Tuple2("L", ls), (t) => t.second, Binder(Wrapped( (_) => null, (_) => LabeledStatement(null), Nothing()))), statementSerializer)); TextSerializer breakSerializer = new Wrapped( unwrapBreakStatement, wrapBreakStatement, const ScopedUse()); LabeledStatement unwrapBreakStatement(BreakStatement node) { return node.target; } BreakStatement wrapBreakStatement(LabeledStatement node) { return new BreakStatement(node); } TextSerializer tryFinallySerializer = Wrapped, TryFinally>( (w) => Tuple2(w.body, w.finalizer), (u) => TryFinally(u.first, u.second), Tuple2Serializer(statementSerializer, statementSerializer)); TextSerializer tryCatchSerializer = Wrapped>, TryCatch>( (w) => Tuple2(w.body, w.catches), (u) => TryCatch(u.first, u.second), Tuple2Serializer(statementSerializer, ListSerializer(catchSerializer))); TextSerializer catchSerializer = Wrapped< Tuple2< DartType, Tuple2, Statement>>, Catch>( (w) => Tuple2(w.guard, Tuple2(Tuple2(w.exception, w.stackTrace), w.body)), (u) => Catch(u.second.first.first, u.second.second, stackTrace: u.second.first.second, guard: u.first), Tuple2Serializer( dartTypeSerializer, Bind( Tuple2Serializer(Optional(variableDeclarationSerializer), Optional(variableDeclarationSerializer)), statementSerializer))); TextSerializer switchStatementSerializer = Wrapped>, SwitchStatement>( (w) => Tuple2(w.expression, w.cases), (u) => SwitchStatement(u.first, u.second), Tuple2Serializer( expressionSerializer, Zip( Bind(ListSerializer(switchCaseSerializer), ListSerializer(statementSerializer)), (SwitchCase c, Statement b) => c..body = b, (SwitchCase z) => Tuple2(z, z.body)))); class SwitchCaseTagger implements Tagger { String tag(SwitchCase node) { return node.isDefault ? "default" : "case"; } } TextSerializer switchCaseCaseSerializer = Wrapped, SwitchCase>( (w) => Tuple2("L", w), (u) => u.second, Binder(Wrapped, SwitchCase>( (w) => w.expressions, (u) => SwitchCase(u, List.filled(u.length, 0), null), ListSerializer(expressionSerializer)))); TextSerializer switchCaseDefaultSerializer = Wrapped< Tuple2, SwitchCase>( (w) => Tuple2("L", w), (u) => u.second, Binder( Wrapped((w) => null, (u) => SwitchCase.defaultCase(null), Nothing()))); TextSerializer switchCaseSerializer = Case(SwitchCaseTagger(), { "case": switchCaseCaseSerializer, "default": switchCaseDefaultSerializer, }); TextSerializer continueSwitchStatementSerializer = Wrapped( (w) => w.target, (u) => ContinueSwitchStatement(u), ScopedUse()); TextSerializer functionDeclarationSerializer = Wrapped, FunctionDeclaration>( (w) => Tuple2(w.variable, w.function!), (u) => FunctionDeclaration(u.first, u.second), Rebind(variableDeclarationSerializer, functionNodeSerializer)); Case statementSerializer = new Case.uninitialized(const StatementTagger()); const Map asyncMarkerToName = { AsyncMarker.Async: "async", AsyncMarker.Sync: "sync", AsyncMarker.AsyncStar: "async-star", AsyncMarker.SyncStar: "sync-star", AsyncMarker.SyncYielding: "sync-yielding", }; class AsyncMarkerTagger implements Tagger { const AsyncMarkerTagger(); String tag(AsyncMarker node) { return asyncMarkerToName[node] ?? (throw new UnsupportedError("${node}")); } } TextSerializer asyncMarkerSerializer = Case(AsyncMarkerTagger(), convertFlagsMap(asyncMarkerToName)); // '/**/' comments added to guide formatting. TextSerializer?>> /**/ functionNodeWithInitializersSerializer = Wrapped< Tuple2< AsyncMarker, Tuple2< /**/ Tuple2< /**/ List, Tuple3< List, List, List>>, Tuple3?, Statement?>>>, Tuple2?>>( (w) => Tuple2( w.first.asyncMarker, Tuple2( Tuple2( w.first.typeParameters, Tuple3( w.first.positionalParameters .sublist(0, w.first.requiredParameterCount), w.first.positionalParameters .sublist(w.first.requiredParameterCount), w.first.namedParameters)), Tuple3(w.first.returnType, w.second, w.first.body))), (u) => Tuple2( FunctionNode(u.second.second.third, typeParameters: u.second.first.first, positionalParameters: u.second.first.second.first + u.second.first.second.second, namedParameters: u.second.first.second.third, requiredParameterCount: u.second.first.second.first.length, returnType: u.second.second.first, asyncMarker: u.first), u.second.second.second), Tuple2Serializer( asyncMarkerSerializer, Bind( Rebind( typeParametersSerializer, Tuple3Serializer( ListSerializer(variableDeclarationSerializer), ListSerializer(variableDeclarationSerializer), ListSerializer(variableDeclarationSerializer))), Tuple3Serializer( dartTypeSerializer, Optional(ListSerializer(initializerSerializer)), Optional(statementSerializer))))); TextSerializer functionNodeSerializer = Wrapped?>, FunctionNode>( (w) => Tuple2(w, null), (u) => u.first, functionNodeWithInitializersSerializer); const Map procedureFlagToName = const { Procedure.FlagStatic: "static", Procedure.FlagAbstract: "abstract", Procedure.FlagExternal: "external", Procedure.FlagConst: "const", Procedure.FlagRedirectingFactoryConstructor: "redirecting-factory-constructor", Procedure.FlagExtensionMember: "extension-member", Procedure.FlagNonNullableByDefault: "non-nullable-by-default", Procedure.FlagSynthetic: "synthetic", }; class ProcedureFlagTagger implements Tagger { const ProcedureFlagTagger(); String tag(int flag) { return procedureFlagToName[flag] ?? (throw StateError("Unknown Procedure flag value: ${flag}.")); } } TextSerializer procedureFlagsSerializer = Wrapped, int>( (w) => List.generate(30, (i) => w & (1 << i)).where((f) => f != 0).toList(), (u) => u.fold(0, (fs, f) => fs |= f), ListSerializer( Case(ProcedureFlagTagger(), convertFlagsMap(procedureFlagToName)))); const Map fieldFlagToName = const { Field.FlagFinal: "final", Field.FlagConst: "const", Field.FlagStatic: "static", Field.FlagCovariant: "covariant", Field.FlagGenericCovariantImpl: "generic-covariant-impl", Field.FlagLate: "late", Field.FlagExtensionMember: "extension-member", Field.FlagNonNullableByDefault: "non-nullable-by-default", Field.FlagInternalImplementation: "internal-implementation", }; class FieldFlagTagger implements Tagger { const FieldFlagTagger(); String tag(int flag) { return fieldFlagToName[flag] ?? (throw StateError("Unknown Field flag value: ${flag}.")); } } TextSerializer fieldFlagsSerializer = Wrapped, int>( (w) => List.generate(30, (i) => w & (1 << i)).where((f) => f != 0).toList(), (u) => u.fold(0, (fs, f) => fs |= f), ListSerializer(Case(FieldFlagTagger(), convertFlagsMap(fieldFlagToName)))); const Map constructorFlagToName = const { Constructor.FlagConst: "const", Constructor.FlagExternal: "external", Constructor.FlagSynthetic: "synthetic", Constructor.FlagNonNullableByDefault: "non-nullable-by-default", }; class ConstructorFlagTagger implements Tagger { const ConstructorFlagTagger(); String tag(int flag) { return constructorFlagToName[flag] ?? (throw StateError("Unknown Constructor flag value: ${flag}.")); } } TextSerializer constructorFlagsSerializer = Wrapped, int>( (w) => List.generate(30, (i) => w & (1 << i)).where((f) => f != 0).toList(), (u) => u.fold(0, (fs, f) => fs |= f), ListSerializer( Case(ConstructorFlagTagger(), convertFlagsMap(constructorFlagToName)))); const Map redirectingFactoryConstructorFlagToName = const { RedirectingFactoryConstructor.FlagConst: "const", RedirectingFactoryConstructor.FlagExternal: "external", RedirectingFactoryConstructor.FlagNonNullableByDefault: "non-nullable-by-default", }; class RedirectingFactoryConstructorFlagTagger implements Tagger { const RedirectingFactoryConstructorFlagTagger(); String tag(int flag) { return redirectingFactoryConstructorFlagToName[flag] ?? (throw StateError( "Unknown RedirectingFactoryConstructor flag value: ${flag}.")); } } TextSerializer redirectingFactoryConstructorFlagsSerializer = Wrapped, int>( (w) => List.generate(30, (i) => w & (1 << i)) .where((f) => f != 0) .toList(), (u) => u.fold(0, (fs, f) => fs |= f), ListSerializer(Case(RedirectingFactoryConstructorFlagTagger(), convertFlagsMap(redirectingFactoryConstructorFlagToName)))); class MemberTagger implements Tagger { const MemberTagger(); String tag(Member node) { if (node is Field) { return node.hasSetter ? "mutable-field" : "immutable-field"; } else if (node is Constructor) { return "constructor"; } else if (node is RedirectingFactoryConstructor) { return "redirecting-factory-constructor"; } else if (node is Procedure) { switch (node.kind) { case ProcedureKind.Method: return "method"; case ProcedureKind.Getter: return "getter"; case ProcedureKind.Setter: return "setter"; case ProcedureKind.Operator: return "operator"; case ProcedureKind.Factory: return "factory"; default: throw new UnsupportedError("MemberTagger.tag(${node.kind})"); } } else { throw UnimplementedError("MemberTagger.tag(${node.runtimeType})"); } } } TextSerializer mutableFieldSerializer = Wrapped, Field>( (w) => Tuple4(w.name!, w.flags, w.type, w.initializer), (u) => Field.mutable(u.first, type: u.third, initializer: u.fourth) ..flags = u.second, Tuple4Serializer(nameSerializer, fieldFlagsSerializer, dartTypeSerializer, nullableExpressionSerializer)); TextSerializer immutableFieldSerializer = Wrapped, Field>( (w) => Tuple4(w.name!, w.flags, w.type, w.initializer), (u) => Field.immutable(u.first, type: u.third, initializer: u.fourth) ..flags = u.second, Tuple4Serializer(nameSerializer, fieldFlagsSerializer, dartTypeSerializer, nullableExpressionSerializer)); TextSerializer methodSerializer = Wrapped, Procedure>( (w) => Tuple3(w.name!, w.flags, w.function!), (u) => Procedure(u.first, ProcedureKind.Method, u.third)..flags = u.second, Tuple3Serializer( nameSerializer, procedureFlagsSerializer, functionNodeSerializer)); TextSerializer getterSerializer = Wrapped, Procedure>( (w) => Tuple3(w.name!, w.flags, w.function!), (u) => Procedure(u.first, ProcedureKind.Getter, u.third)..flags = u.second, Tuple3Serializer( nameSerializer, procedureFlagsSerializer, functionNodeSerializer)); TextSerializer setterSerializer = Wrapped, Procedure>( (w) => Tuple3(w.name!, w.flags, w.function!), (u) => Procedure(u.first, ProcedureKind.Setter, u.third)..flags = u.second, Tuple3Serializer( nameSerializer, procedureFlagsSerializer, functionNodeSerializer)); TextSerializer operatorSerializer = Wrapped, Procedure>( (w) => Tuple3(w.name!, w.flags, w.function!), (u) => Procedure(u.first, ProcedureKind.Operator, u.third) ..flags = u.second, Tuple3Serializer( nameSerializer, procedureFlagsSerializer, functionNodeSerializer)); TextSerializer factorySerializer = Wrapped, Procedure>( (w) => Tuple3(w.name!, w.flags, w.function!), (u) => Procedure(u.first, ProcedureKind.Factory, u.third) ..flags = u.second, Tuple3Serializer( nameSerializer, procedureFlagsSerializer, functionNodeSerializer)); TextSerializer constructorSerializer = Wrapped< Tuple3?>>, Constructor>( (w) => Tuple3(w.name!, w.flags, Tuple2(w.function!, w.initializers)), (u) => Constructor(u.third.first, name: u.first, initializers: u.third.second) ..flags = u.second, Tuple3Serializer(nameSerializer, constructorFlagsSerializer, functionNodeWithInitializersSerializer)); TextSerializer redirectingFactoryConstructorSerializer = Wrapped< Tuple4< Name, int, CanonicalName, Tuple2< List, Tuple4, List, List, List>>>, RedirectingFactoryConstructor>( (w) => Tuple4( w.name!, w.flags, w.targetReference!.canonicalName!, Tuple2( w.typeParameters, Tuple4( w.positionalParameters .take(w.requiredParameterCount) .toList(), w.positionalParameters .skip(w.requiredParameterCount) .toList(), w.namedParameters, w.typeArguments))), (u) => RedirectingFactoryConstructor(u.third.reference, name: u.first, typeParameters: u.fourth.first, positionalParameters: u.fourth.second.first + u.fourth.second.second, requiredParameterCount: u.fourth.second.first.length, namedParameters: u.fourth.second.third, typeArguments: u.fourth.second.fourth) ..flags = u.second, Tuple4Serializer( nameSerializer, redirectingFactoryConstructorFlagsSerializer, CanonicalNameSerializer(), Bind( typeParametersSerializer, Tuple4Serializer( ListSerializer(variableDeclarationSerializer), ListSerializer(variableDeclarationSerializer), ListSerializer(variableDeclarationSerializer), ListSerializer(dartTypeSerializer))))); Case memberSerializer = new Case.uninitialized(const MemberTagger()); TextSerializer libraryPartSerializer = Wrapped>, LibraryPart>( (w) => Tuple2(w.partUri, w.annotations), (u) => LibraryPart(u.second, u.first), Tuple2Serializer(DartString(), ListSerializer(expressionSerializer))); class LibraryTagger implements Tagger { const LibraryTagger(); String tag(Library node) { return node.isNonNullableByDefault ? "null-safe" : "legacy"; } } const Map libraryFlagToName = const { Library.SyntheticFlag: "synthetic", Library.NonNullableByDefaultFlag: "nnbd", Library.NonNullableByDefaultModeBit1: "nnbd-bit1", Library.NonNullableByDefaultModeBit2: "nnbd-bit2", }; class LibraryFlagTagger implements Tagger { const LibraryFlagTagger(); String tag(int flag) { return libraryFlagToName[flag] ?? (throw StateError("Unknown Library flag value: ${flag}.")); } } TextSerializer libraryFlagsSerializer = Wrapped, int>( (w) => List.generate(30, (i) => w & (1 << i)).where((f) => f != 0).toList(), (u) => u.fold(0, (fs, f) => fs |= f), ListSerializer( Case(LibraryFlagTagger(), convertFlagsMap(libraryFlagToName)))); TextSerializer librarySerializer = new Wrapped< Tuple7, List, List, List, List>, Library>( (w) => Tuple7(w.importUri, w.flags, w.parts, [...w.fields, ...w.procedures], w.classes, w.typedefs, w.extensions), (u) => Library(u.first, parts: u.third, fields: u.fourth.where((m) => m is Field).cast().toList(), procedures: u.fourth.where((m) => m is Procedure).cast().toList(), classes: u.fifth, typedefs: u.sixth, extensions: u.seventh) ..flags = u.second, Tuple7Serializer( UriSerializer(), libraryFlagsSerializer, ListSerializer(libraryPartSerializer), ListSerializer(memberSerializer), ListSerializer(classSerializer), ListSerializer(typedefSerializer), ListSerializer(extensionSerializer)), ); TextSerializer componentSerializer = Wrapped, Component>( (w) => w.libraries, (u) => Component(nameRoot: CanonicalName.root(), libraries: u), ListSerializer(librarySerializer)); class ShowHideTagger implements Tagger { String tag(Combinator node) => node.isShow ? "show" : "hide"; } TextSerializer showSerializer = Wrapped, Combinator>( (c) => c.names, (ns) => Combinator(true, ns), ListSerializer(DartString())); TextSerializer hideSerializer = Wrapped, Combinator>( (c) => c.names, (ns) => Combinator(false, ns), ListSerializer(DartString())); Case showHideSerializer = new Case(ShowHideTagger(), { "show": showSerializer, "hide": hideSerializer, }); TextSerializer libraryDependencySerializer = Wrapped< Tuple5, int, List>, LibraryDependency>( (ld) => Tuple5(ld.importedLibraryReference.canonicalName!, ld.name, ld.combinators, ld.flags, ld.annotations), (t) => LibraryDependency.byReference( t.fourth, t.fifth, t.first.reference, t.second, t.third), Tuple5Serializer( CanonicalNameSerializer(), Optional(DartString()), ListSerializer(showHideSerializer), DartInt(), ListSerializer(expressionSerializer))); class ConstantTagger extends ConstantVisitor implements Tagger { const ConstantTagger(); String tag(Constant node) => node.accept(this); String visitBoolConstant(BoolConstant node) => "const-bool"; String visitDoubleConstant(DoubleConstant node) => "const-double"; String visitInstanceConstant(InstanceConstant node) => "const-object"; String visitIntConstant(IntConstant node) => "const-int"; String visitListConstant(ListConstant node) => "const-list"; String visitMapConstant(MapConstant node) => "const-map"; String visitNullConstant(NullConstant node) => "const-null"; String visitPartialInstantiationConstant(PartialInstantiationConstant node) => "const-apply"; String visitSetConstant(SetConstant node) => "const-set"; String visitStringConstant(StringConstant node) => "const-string"; String visitSymbolConstant(SymbolConstant node) => "const-symbol"; String visitTearOffConstant(TearOffConstant node) => "const-tearoff"; String visitTypeLiteralConstant(TypeLiteralConstant node) => "const-type"; String visitUnevaluatedConstant(UnevaluatedConstant node) => "const-expr"; @override String defaultConstant(Constant node) { throw new UnimplementedError( 'Unimplemented constant $node (${node.runtimeType})'); } } TextSerializer boolConstantSerializer = Wrapped( (w) => w.value, (u) => BoolConstant(u), DartBool()); TextSerializer doubleConstantSerializer = Wrapped( (w) => w.value, (u) => DoubleConstant(u), DartDouble()); TextSerializer intConstantSerializer = Wrapped((w) => w.value, (u) => IntConstant(u), DartInt()); TextSerializer listConstantSerializer = Wrapped>, ListConstant>( (w) => Tuple2(w.typeArgument, w.entries), (u) => ListConstant(u.first, u.second), Tuple2Serializer( dartTypeSerializer, ListSerializer(constantSerializer))); TextSerializer mapConstantSerializer = Wrapped>, MapConstant>( (w) => Tuple3(w.keyType, w.valueType, w.entries), (u) => MapConstant(u.first, u.second, u.third), Tuple3Serializer( dartTypeSerializer, dartTypeSerializer, Zip( Tuple2Serializer(ListSerializer(constantSerializer), ListSerializer(constantSerializer)), (Constant k, Constant v) => ConstantMapEntry(k, v), (z) => Tuple2(z.key, z.value)))); TextSerializer nullConstantSerializer = Wrapped((w) => null, (u) => NullConstant(), Nothing()); TextSerializer partialInstantiationConstantSerializer = Wrapped< Tuple2>, PartialInstantiationConstant>( (w) => Tuple2(w.tearOffConstant, w.types), (u) => PartialInstantiationConstant(u.first, u.second), Tuple2Serializer( tearOffConstantSerializer, ListSerializer(dartTypeSerializer))); TextSerializer setConstantSerializer = Wrapped>, SetConstant>( (w) => Tuple2(w.typeArgument, w.entries), (u) => SetConstant(u.first, u.second), Tuple2Serializer( dartTypeSerializer, ListSerializer(constantSerializer))); TextSerializer stringConstantSerializer = Wrapped( (w) => w.value, (u) => StringConstant(u), DartString()); TextSerializer symbolConstantSerializer = Wrapped, SymbolConstant>( (w) => Tuple2(w.name, w.libraryReference?.canonicalName), (u) => SymbolConstant(u.first, u.second?.reference), Tuple2Serializer(DartString(), Optional(CanonicalNameSerializer()))); TextSerializer tearOffConstantSerializer = Wrapped( (w) => w.procedureReference.canonicalName!, (u) => TearOffConstant.byReference(u.reference), CanonicalNameSerializer()); TextSerializer typeLiteralConstantSerializer = Wrapped( (w) => w.type, (u) => TypeLiteralConstant(u), dartTypeSerializer); TextSerializer unevaluatedConstantSerializer = Wrapped((w) => w.expression, (u) => UnevaluatedConstant(u), expressionSerializer); TextSerializer instanceConstantSerializer = Wrapped< Tuple4, List, List>, InstanceConstant>( (w) => Tuple4( w.classReference.canonicalName!, w.typeArguments, w.fieldValues.keys.map((r) => r.canonicalName!).toList(), w.fieldValues.values.toList()), (u) => InstanceConstant(u.first.reference, u.second, Map.fromIterables(u.third.map((c) => c.reference), u.fourth)), Tuple4Serializer( CanonicalNameSerializer(), ListSerializer(dartTypeSerializer), ListSerializer(CanonicalNameSerializer()), ListSerializer(constantSerializer))); Case constantSerializer = Case.uninitialized(ConstantTagger()); class InitializerTagger implements Tagger { const InitializerTagger(); String tag(Initializer node) { if (node is AssertInitializer) { return "assert"; } else if (node is FieldInitializer) { return "field"; } else if (node is InvalidInitializer) { return "invalid"; } else if (node is LocalInitializer) { return "local"; } else if (node is RedirectingInitializer) { return "redirecting"; } else if (node is SuperInitializer) { return "super"; } else { throw UnimplementedError("InitializerTagger.tag(${node.runtimeType})."); } } } TextSerializer assertInitializerSerializer = Wrapped((w) => w.statement, (u) => AssertInitializer(u as AssertStatement), statementSerializer); TextSerializer fieldInitializerSerializer = Wrapped, FieldInitializer>( (w) => Tuple2(w.fieldReference.canonicalName!, w.value), (u) => FieldInitializer.byReference(u.first.reference, u.second), Tuple2Serializer(CanonicalNameSerializer(), expressionSerializer)); TextSerializer invalidInitializerSerializer = Wrapped( (_) => null, (_) => InvalidInitializer(), Nothing()); TextSerializer localInitializerSerializer = Wrapped((w) => w.variable, (u) => LocalInitializer(u), variableDeclarationSerializer); TextSerializer redirectingInitializerSerializer = Wrapped, RedirectingInitializer>( (w) => Tuple2(w.targetReference.canonicalName!, w.arguments), (u) => RedirectingInitializer.byReference(u.first.reference, u.second), Tuple2Serializer(CanonicalNameSerializer(), argumentsSerializer)); TextSerializer superInitializerSerializer = Wrapped, SuperInitializer>( (w) => Tuple2(w.targetReference.canonicalName!, w.arguments), (u) => SuperInitializer.byReference(u.first.reference, u.second), Tuple2Serializer(CanonicalNameSerializer(), argumentsSerializer)); Case initializerSerializer = Case.uninitialized(InitializerTagger()); TextSerializer supertypeSerializer = Wrapped>, Supertype>( (w) => Tuple2(w.className.canonicalName!, w.typeArguments), (u) => Supertype.byReference(u.first.reference, u.second), Tuple2Serializer( CanonicalNameSerializer(), ListSerializer(dartTypeSerializer))); const Map classFlagToName = const { Class.FlagAbstract: "abstract", Class.FlagEnum: "enum", Class.FlagAnonymousMixin: "anonymous-mixin", Class.FlagEliminatedMixin: "eliminated-mixin", Class.FlagMixinDeclaration: "mixin-declaration", Class.FlagHasConstConstructor: "has-const-constructor", }; class ClassFlagTagger implements Tagger { const ClassFlagTagger(); String tag(int flag) { return classFlagToName[flag] ?? (throw StateError("Unknown Class flag value: ${flag}.")); } } TextSerializer classFlagsSerializer = Wrapped, int>( (w) => List.generate(30, (i) => w & (1 << i)).where((f) => f != 0).toList(), (u) => u.fold(0, (fs, f) => fs |= f), ListSerializer(Case(ClassFlagTagger(), convertFlagsMap(classFlagToName)))); TextSerializer classSerializer = Wrapped< Tuple3< String, int, Tuple2< List, /* Comment added to guide formatting. */ Tuple4, List>>>, Class>( (w) => Tuple3( w.name, w.flags, Tuple2( w.typeParameters, Tuple4(w.supertype, w.mixedInType, w.implementedTypes, [...w.fields, ...w.constructors, ...w.procedures]))), (u) => Class( name: u.first, typeParameters: u.third.first, supertype: u.third.second.first, mixedInType: u.third.second.second, implementedTypes: u.third.second.third, fields: u.third.second.fourth .where((m) => m is Field) .cast() .toList(), constructors: u.third.second.fourth .where((m) => m is Constructor) .cast() .toList(), procedures: u.third.second.fourth .where((m) => m is Procedure) .cast() .toList()) ..flags = u.second, Tuple3Serializer( DartString(), classFlagsSerializer, Bind( typeParametersSerializer, Tuple4Serializer( Optional(supertypeSerializer), Optional(supertypeSerializer), ListSerializer(supertypeSerializer), ListSerializer(memberSerializer))))); TextSerializer typedefSerializer = Wrapped, DartType>>, Typedef>( (w) => Tuple2(w.name, Tuple2(w.typeParameters, w.type!)), (u) => Typedef(u.first, u.second.second, typeParameters: u.second.first), Tuple2Serializer( DartString(), Bind(typeParametersSerializer, dartTypeSerializer))); const Map extensionMemberDescriptorFlagToName = const { ExtensionMemberDescriptor.FlagStatic: "static", }; class ExtensionMemberDescriptorFlagTagger implements Tagger { const ExtensionMemberDescriptorFlagTagger(); String tag(int flag) { return extensionMemberDescriptorFlagToName[flag] ?? (throw StateError( "Unknown ExtensionMemberDescriptor flag value: ${flag}.")); } } TextSerializer extensionMemberDescriptorFlagsSerializer = Wrapped, int>( (w) => List.generate(30, (i) => w & (1 << i)) .where((f) => f != 0) .toList(), (u) => u.fold(0, (fs, f) => fs |= f), ListSerializer(Case(ExtensionMemberDescriptorFlagTagger(), convertFlagsMap(extensionMemberDescriptorFlagToName)))); const Map extensionMemberKindToName = const { ExtensionMemberKind.Field: "field", ExtensionMemberKind.Method: "method", ExtensionMemberKind.Getter: "getter", ExtensionMemberKind.Setter: "setter", ExtensionMemberKind.Operator: "operator", ExtensionMemberKind.TearOff: "tearOff", }; class ExtensionMemberKindTagger implements Tagger { const ExtensionMemberKindTagger(); String tag(ExtensionMemberKind kind) { return extensionMemberKindToName[kind] ?? (throw StateError("Unknown ExtensionMemberKind flag value: ${kind}.")); } } TextSerializer extensionMemberKindSerializer = Case( ExtensionMemberKindTagger(), convertFlagsMap(extensionMemberKindToName)); TextSerializer extensionMemberDescriptorSerializer = Wrapped, ExtensionMemberDescriptor>( (w) => Tuple4(w.name, w.kind, w.flags, w.member.canonicalName!), (u) => ExtensionMemberDescriptor( name: u.first, kind: u.second, member: u.fourth.reference) ..flags = u.third, Tuple4Serializer( nameSerializer, extensionMemberKindSerializer, extensionMemberDescriptorFlagsSerializer, CanonicalNameSerializer())); TextSerializer extensionSerializer = Wrapped< Tuple3, DartType>, List>, Extension>( (w) => Tuple3(w.name, Tuple2(w.typeParameters, w.onType), w.members), (u) => Extension( name: u.first, typeParameters: u.second.first, onType: u.second.second, members: u.third), Tuple3Serializer( DartString(), Bind(typeParametersSerializer, dartTypeSerializer), ListSerializer(extensionMemberDescriptorSerializer))); void initializeSerializers() { expressionSerializer.registerTags({ "string": stringLiteralSerializer, "int": intLiteralSerializer, "double": doubleLiteralSerializer, "bool": boolLiteralSerializer, "null": nullLiteralSerializer, "invalid": invalidExpressionSerializer, "not": notSerializer, "&&": logicalAndSerializer, "||": logicalOrSerializer, "concat": stringConcatenationSerializer, "symbol": symbolLiteralSerializer, "this": thisExpressionSerializer, "rethrow": rethrowSerializer, "throw": throwSerializer, "await": awaitExpressionSerializer, "cond": conditionalExpressionSerializer, "is": isExpressionSerializer, "as": asExpressionSerializer, "type": typeLiteralSerializer, "list": listLiteralSerializer, "const-list": constListLiteralSerializer, "set": setLiteralSerializer, "const-set": constSetLiteralSerializer, "map": mapLiteralSerializer, "const-map": constMapLiteralSerializer, "let": letSerializer, "get-prop": propertyGetSerializer, "set-prop": propertySetSerializer, "get-instance": instanceGetSerializer, "set-instance": instanceSetSerializer, "get-dynamic": dynamicGetSerializer, "set-dynamic": dynamicSetSerializer, "tearoff-instance": instanceTearOffSerializer, "tearoff-function": functionTearOffSerializer, "get-super": superPropertyGetSerializer, "set-super": superPropertySetSerializer, "invoke-method": methodInvocationSerializer, "invoke-instance": instanceInvocationSerializer, "invoke-instance-getter": instanceGetterInvocationSerializer, "invoke-dynamic": dynamicInvocationSerializer, "invoke-function": functionInvocationSerializer, "invoke-local-function": localFunctionInvocationSerializer, "equals-null": equalsNullSerializer, "equals-call": equalsCallSerializer, "invoke-super": superMethodInvocationSerializer, "get-var": variableGetSerializer, "set-var": variableSetSerializer, "get-static": staticGetSerializer, "set-static": staticSetSerializer, "tearoff-static": staticGetSerializer, "invoke-static": staticInvocationSerializer, "invoke-const-static": constStaticInvocationSerializer, "invoke-constructor": constructorInvocationSerializer, "invoke-const-constructor": constConstructorInvocationSerializer, "fun": functionExpressionSerializer, "lists": listConcatenationSerializer, "sets": setConcatenationSerializer, "maps": mapConcatenationSerializer, "let-block": blockExpressionSerializer, "apply": instantiationSerializer, "not-null": nullCheckSerializer, "with-uri": fileUriExpressionSerializer, "is-loaded": checkLibraryIsLoadedSerializer, "load": loadLibrarySerializer, "const": constantExpressionSerializer, "object": instanceCreationSerializer, }); dartTypeSerializer.registerTags({ "invalid": invalidTypeSerializer, "dynamic": dynamicTypeSerializer, "void": voidTypeSerializer, "->": functionTypeSerializer, "par": typeParameterTypeSerializer, "interface": interfaceTypeSerializer, "never": neverTypeSerializer, "typedef": typedefTypeSerializer, "futureor": futureOrTypeSerializer, "null-type": nullTypeSerializer, }); statementSerializer.registerTags({ "expr": expressionStatementSerializer, "ret": returnStatementSerializer, "ret-void": returnVoidStatementSerializer, "yield": yieldStatementSerializer, "block": blockSerializer, "local": variableDeclarationSerializer, "if": ifStatementSerializer, "if-else": ifElseStatementSerializer, "skip": emptyStatementSerializer, "while": whileStatementSerializer, "do-while": doStatementSerializer, "for": forStatementSerializer, "for-in": forInStatementSerializer, "await-for-in": awaitForInStatementSerializer, "assert": assertStatementSerializer, "assert-block": assertBlockSerializer, "label": labeledStatementSerializer, "break": breakSerializer, "try-finally": tryFinallySerializer, "try-catch": tryCatchSerializer, "switch": switchStatementSerializer, "continue": continueSwitchStatementSerializer, "local-fun": functionDeclarationSerializer, }); memberSerializer.registerTags({ "mutable-field": mutableFieldSerializer, "immutable-field": immutableFieldSerializer, "method": methodSerializer, "getter": getterSerializer, "setter": setterSerializer, "operator": operatorSerializer, "factory": factorySerializer, "constructor": constructorSerializer, "redirecting-factory-constructor": redirectingFactoryConstructorSerializer, }); constantSerializer.registerTags({ "const-bool": boolConstantSerializer, "const-double": doubleConstantSerializer, "const-int": intConstantSerializer, "const-list": listConstantSerializer, "const-map": mapConstantSerializer, "const-null": nullConstantSerializer, "const-apply": partialInstantiationConstantSerializer, "const-set": setConstantSerializer, "const-string": stringConstantSerializer, "const-symbol": symbolConstantSerializer, "const-tearoff": tearOffConstantSerializer, "const-type": typeLiteralConstantSerializer, "const-expr": unevaluatedConstantSerializer, "const-object": instanceConstantSerializer, }); initializerSerializer.registerTags({ "assert": assertInitializerSerializer, "field": fieldInitializerSerializer, "invalid": invalidInitializerSerializer, "local": localInitializerSerializer, "redirecting": redirectingInitializerSerializer, "super": superInitializerSerializer, }); } Map> convertFlagsMap(Map map) { return map.entries.toMap( key: (e) => e.value, value: (e) => Wrapped((_) => null, (_) => e.key, Nothing())); } extension MapFromIterable on Iterable { Map toMap( {required K Function(E) key, required V Function(E) value}) { return {for (E e in this) key(e): value(e)}; } }