// Copyright (c) 2017, the Dart project authors.  Please see the AUTHORS file
// for details. All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE file.

// @dart = 2.9

library vm.constants_native_effects;

import '../ast.dart';
import '../target/targets.dart';
import '../core_types.dart';

class VmConstantsBackend extends ConstantsBackend {
  final Class immutableMapClass;
  final Class unmodifiableSetClass;
  final Field unmodifiableSetMap;

  VmConstantsBackend._(this.immutableMapClass, this.unmodifiableSetMap,
      this.unmodifiableSetClass);

  /// If [defines] is not `null` it will be used for handling
  /// `const {bool,...}.fromEnvironment()` otherwise the current VM's values
  /// will be used.
  factory VmConstantsBackend(CoreTypes coreTypes) {
    final Library coreLibrary = coreTypes.coreLibrary;
    final Class immutableMapClass = coreLibrary.classes
        .firstWhere((Class klass) => klass.name == '_ImmutableMap');
    assert(immutableMapClass != null);
    Field unmodifiableSetMap = coreTypes.index
        .getMember('dart:collection', '_UnmodifiableSet', '_map');

    return new VmConstantsBackend._(immutableMapClass, unmodifiableSetMap,
        unmodifiableSetMap.enclosingClass);
  }

  @override
  Constant lowerMapConstant(MapConstant constant) {
    // The _ImmutableMap class is implemented via one field pointing to a list
    // of key/value pairs -- see runtime/lib/immutable_map.dart!
    final List<Constant> kvListPairs =
        new List<Constant>.filled(2 * constant.entries.length, null);
    for (int i = 0; i < constant.entries.length; i++) {
      final ConstantMapEntry entry = constant.entries[i];
      kvListPairs[2 * i] = entry.key;
      kvListPairs[2 * i + 1] = entry.value;
    }
    // This is a bit fishy, since we merge the key and the value type by
    // putting both into the same list.
    final ListConstant kvListConstant =
        new ListConstant(const DynamicType(), kvListPairs);
    assert(immutableMapClass.fields.length == 1);
    final Field kvPairListField = immutableMapClass.fields[0];
    return new InstanceConstant(immutableMapClass.reference, <DartType>[
      constant.keyType,
      constant.valueType,
    ], <Reference, Constant>{
      // We use getterReference as we refer to the field itself.
      kvPairListField.getterReference: kvListConstant,
    });
  }

  @override
  bool isLoweredMapConstant(Constant constant) {
    return constant is InstanceConstant &&
        constant.classNode == immutableMapClass;
  }

  @override
  void forEachLoweredMapConstantEntry(
      Constant constant, void Function(Constant key, Constant value) f) {
    assert(isLoweredMapConstant(constant));
    final InstanceConstant instance = constant;
    assert(immutableMapClass.fields.length == 1);
    final Field kvPairListField = immutableMapClass.fields[0];
    final ListConstant kvListConstant =
        instance.fieldValues[kvPairListField.getterReference];
    assert(kvListConstant.entries.length % 2 == 0);
    for (int index = 0; index < kvListConstant.entries.length; index += 2) {
      f(kvListConstant.entries[index], kvListConstant.entries[index + 1]);
    }
  }

  @override
  Constant lowerSetConstant(SetConstant constant) {
    final DartType elementType = constant.typeArgument;
    final List<Constant> entries = constant.entries;
    final List<ConstantMapEntry> mapEntries =
        new List<ConstantMapEntry>.filled(entries.length, null);
    for (int i = 0; i < entries.length; ++i) {
      mapEntries[i] = new ConstantMapEntry(entries[i], new NullConstant());
    }
    Constant map = lowerMapConstant(
        new MapConstant(elementType, const NullType(), mapEntries));
    return new InstanceConstant(unmodifiableSetClass.reference, [elementType],
        <Reference, Constant>{unmodifiableSetMap.getterReference: map});
  }

  @override
  bool isLoweredSetConstant(Constant constant) {
    if (constant is InstanceConstant &&
        constant.classNode == unmodifiableSetClass) {
      InstanceConstant instance = constant;
      return isLoweredMapConstant(
          instance.fieldValues[unmodifiableSetMap.getterReference]);
    }
    return false;
  }

  @override
  void forEachLoweredSetConstantElement(
      Constant constant, void Function(Constant element) f) {
    assert(isLoweredSetConstant(constant));
    final InstanceConstant instance = constant;
    final Constant mapConstant =
        instance.fieldValues[unmodifiableSetMap.getterReference];
    forEachLoweredMapConstantEntry(mapConstant, (Constant key, Constant value) {
      f(key);
    });
  }
}
