// Copyright (c) 2019, 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.

part of 'constant_evaluator.dart';

abstract class _ListOrSetConstantBuilder<L extends Expression> {
  final ConstantEvaluator evaluator;
  final Expression original;
  final DartType elementType;

  // Each element of [parts] is either a `List<Constant>` (containing fully
  // evaluated constants) or a `Constant` (potentially unevaluated).
  List<Object> parts = <Object>[<Constant>[]];

  _ListOrSetConstantBuilder(this.original, this.elementType, this.evaluator);

  L makeLiteral(List<Expression> elements);

  /// Add an element to the constant list being built by this builder.
  ///
  /// Returns [null] on success and an error-"constant" on failure, as such the
  /// return value should be checked.
  AbortConstant add(Expression element) {
    Constant constant = evaluator._evaluateSubexpression(element);
    if (constant is AbortConstant) return constant;
    if (evaluator.shouldBeUnevaluated) {
      parts.add(evaluator.unevaluated(
          element, makeLiteral([evaluator.extract(constant)])));
      return null;
    } else {
      return addConstant(constant, element);
    }
  }

  /// Returns [null] on success and an error-"constant" on failure, as such the
  /// return value should be checked.
  AbortConstant addSpread(Expression spreadExpression) {
    Constant constant = evaluator._evaluateSubexpression(spreadExpression);
    if (constant is AbortConstant) return constant;
    Constant spread = evaluator.unlower(constant);
    if (evaluator.shouldBeUnevaluated) {
      // Unevaluated spread
      parts.add(spread);
    } else if (spread == evaluator.nullConstant) {
      // Null spread
      return evaluator.createErrorConstant(
          spreadExpression, messageConstEvalNullValue);
    } else {
      // Fully evaluated spread
      List<Constant> entries;
      if (spread is ListConstant) {
        entries = spread.entries;
      } else if (spread is SetConstant) {
        entries = spread.entries;
      } else {
        // Not list or set in spread
        return evaluator.createErrorConstant(
            spreadExpression, messageConstEvalNotListOrSetInSpread);
      }
      for (Constant entry in entries) {
        AbortConstant error = addConstant(entry, spreadExpression);
        if (error != null) return error;
      }
    }
    return null;
  }

  /// Returns [null] on success and an error-"constant" on failure, as such the
  /// return value should be checked.
  AbortConstant addConstant(Constant constant, TreeNode context);

  Constant build();
}

class ListConstantBuilder extends _ListOrSetConstantBuilder<ListLiteral> {
  ListConstantBuilder(
      Expression original, DartType elementType, ConstantEvaluator evaluator)
      : super(original, elementType, evaluator);

  @override
  ListLiteral makeLiteral(List<Expression> elements) =>
      new ListLiteral(elements, isConst: true);

  @override
  AbortConstant addConstant(Constant constant, TreeNode context) {
    List<Constant> lastPart;
    if (parts.last is List<Constant>) {
      lastPart = parts.last;
    } else {
      // Probably unreachable.
      parts.add(lastPart = <Constant>[]);
    }
    Constant value = evaluator.ensureIsSubtype(constant, elementType, context);
    if (value is AbortConstant) return value;
    lastPart.add(value);
    return null;
  }

  @override
  Constant build() {
    if (parts.length == 1) {
      // Fully evaluated
      return evaluator
          .lowerListConstant(new ListConstant(elementType, parts.single));
    }
    List<Expression> lists = <Expression>[];
    for (Object part in parts) {
      if (part is List<Constant>) {
        lists.add(new ConstantExpression(new ListConstant(elementType, part)));
      } else if (part is Constant) {
        lists.add(evaluator.extract(part));
      } else {
        throw 'Non-constant in constant list';
      }
    }
    return evaluator.unevaluated(
        original, new ListConcatenation(lists, typeArgument: elementType));
  }
}

class SetConstantBuilder extends _ListOrSetConstantBuilder<SetLiteral> {
  final Set<Constant> seen = new Set<Constant>.identity();
  final Set<Constant> weakSeen = new Set<Constant>.identity();

  SetConstantBuilder(
      Expression original, DartType elementType, ConstantEvaluator evaluator)
      : super(original, elementType, evaluator);

  @override
  SetLiteral makeLiteral(List<Expression> elements) =>
      new SetLiteral(elements, isConst: true);

  @override
  AbortConstant addConstant(Constant constant, TreeNode context) {
    if (!evaluator.hasPrimitiveEqual(constant)) {
      return evaluator.createErrorConstant(
          context,
          templateConstEvalElementImplementsEqual.withArguments(
              constant, evaluator.isNonNullableByDefault));
    }
    bool unseen = seen.add(constant);
    if (!unseen) {
      return evaluator.createErrorConstant(
          context,
          templateConstEvalDuplicateElement.withArguments(
              constant, evaluator.isNonNullableByDefault));
    }
    if (evaluator.evaluationMode == EvaluationMode.agnostic) {
      Constant weakConstant =
          evaluator._weakener.visitConstant(constant) ?? constant;
      bool weakUnseen = weakSeen.add(weakConstant);
      if (unseen != weakUnseen) {
        return evaluator.createErrorConstant(
            context, messageNonAgnosticConstant);
      }
    }

    List<Constant> lastPart;
    if (parts.last is List<Constant>) {
      lastPart = parts.last;
    } else {
      // Probably unreachable.
      parts.add(lastPart = <Constant>[]);
    }
    Constant value = evaluator.ensureIsSubtype(constant, elementType, context);
    if (value is AbortConstant) return value;
    lastPart.add(value);
    return null;
  }

  @override
  Constant build() {
    if (parts.length == 1) {
      // Fully evaluated
      List<Constant> entries = parts.single;
      SetConstant result = new SetConstant(elementType, entries);
      if (evaluator.desugarSets) {
        final List<ConstantMapEntry> mapEntries =
            new List<ConstantMapEntry>(entries.length);
        for (int i = 0; i < entries.length; ++i) {
          mapEntries[i] =
              new ConstantMapEntry(entries[i], evaluator.nullConstant);
        }
        Constant map = evaluator.lowerMapConstant(new MapConstant(
            elementType, evaluator.typeEnvironment.nullType, mapEntries));
        return evaluator.lower(
            result,
            new InstanceConstant(
                evaluator.unmodifiableSetMap.enclosingClass.reference, [
              elementType
            ], <Reference, Constant>{
              evaluator.unmodifiableSetMap.reference: map
            }));
      } else {
        return evaluator.lowerSetConstant(result);
      }
    }
    List<Expression> sets = <Expression>[];
    for (Object part in parts) {
      if (part is List<Constant>) {
        sets.add(new ConstantExpression(new SetConstant(elementType, part)));
      } else if (part is Constant) {
        sets.add(evaluator.extract(part));
      } else {
        throw 'Non-constant in constant set';
      }
    }
    return evaluator.unevaluated(
        original, new SetConcatenation(sets, typeArgument: elementType));
  }
}

class MapConstantBuilder {
  final ConstantEvaluator evaluator;
  final Expression original;
  final DartType keyType;
  final DartType valueType;

  /// Each element of [parts] is either a `List<ConstantMapEntry>` (containing
  /// fully evaluated map entries) or a `Constant` (potentially unevaluated).
  List<Object> parts = <Object>[<ConstantMapEntry>[]];

  final Set<Constant> seenKeys = new Set<Constant>.identity();
  final Set<Constant> weakSeenKeys = new Set<Constant>.identity();

  MapConstantBuilder(
      this.original, this.keyType, this.valueType, this.evaluator);

  /// Add a map entry to the constant map being built by this builder
  ///
  /// Returns [null] on success and an error-"constant" on failure, as such the
  /// return value should be checked.
  AbortConstant add(MapEntry element) {
    Constant key = evaluator._evaluateSubexpression(element.key);
    if (key is AbortConstant) return key;
    Constant value = evaluator._evaluateSubexpression(element.value);
    if (value is AbortConstant) return value;
    if (evaluator.shouldBeUnevaluated) {
      parts.add(evaluator.unevaluated(
          element.key,
          new MapLiteral(
              [new MapEntry(evaluator.extract(key), evaluator.extract(value))],
              isConst: true)));
      return null;
    } else {
      return addConstant(key, value, element.key, element.value);
    }
  }

  /// Returns [null] on success and an error-"constant" on failure, as such the
  /// return value should be checked.
  AbortConstant addSpread(Expression spreadExpression) {
    Constant constant = evaluator._evaluateSubexpression(spreadExpression);
    if (constant is AbortConstant) return constant;
    Constant spread = evaluator.unlower(constant);
    if (evaluator.shouldBeUnevaluated) {
      // Unevaluated spread
      parts.add(spread);
    } else if (spread == evaluator.nullConstant) {
      // Null spread
      return evaluator.createErrorConstant(
          spreadExpression, messageConstEvalNullValue);
    } else {
      // Fully evaluated spread
      if (spread is MapConstant) {
        for (ConstantMapEntry entry in spread.entries) {
          AbortConstant error = addConstant(
              entry.key, entry.value, spreadExpression, spreadExpression);
          if (error != null) return error;
        }
      } else {
        // Not map in spread
        return evaluator.createErrorConstant(
            spreadExpression, messageConstEvalNotMapInSpread);
      }
    }
    return null;
  }

  /// Returns [null] on success and an error-"constant" on failure, as such the
  /// return value should be checked.
  AbortConstant addConstant(Constant key, Constant value, TreeNode keyContext,
      TreeNode valueContext) {
    List<ConstantMapEntry> lastPart;
    if (parts.last is List<ConstantMapEntry>) {
      lastPart = parts.last;
    } else {
      // Probably unreachable.
      parts.add(lastPart = <ConstantMapEntry>[]);
    }
    if (!evaluator.hasPrimitiveEqual(key)) {
      return evaluator.createErrorConstant(
          keyContext,
          templateConstEvalKeyImplementsEqual.withArguments(
              key, evaluator.isNonNullableByDefault));
    }
    bool unseenKey = seenKeys.add(key);
    if (!unseenKey) {
      return evaluator.createErrorConstant(
          keyContext,
          templateConstEvalDuplicateKey.withArguments(
              key, evaluator.isNonNullableByDefault));
    }
    if (evaluator.evaluationMode == EvaluationMode.agnostic) {
      Constant weakKey = evaluator._weakener.visitConstant(key) ?? key;
      bool weakUnseenKey = weakSeenKeys.add(weakKey);
      if (unseenKey != weakUnseenKey) {
        return evaluator.createErrorConstant(
            keyContext, messageNonAgnosticConstant);
      }
    }
    Constant key2 = evaluator.ensureIsSubtype(key, keyType, keyContext);
    if (key2 is AbortConstant) return key2;
    Constant value2 = evaluator.ensureIsSubtype(value, valueType, valueContext);
    if (value2 is AbortConstant) return value2;
    lastPart.add(new ConstantMapEntry(key2, value2));
    return null;
  }

  Constant build() {
    if (parts.length == 1) {
      // Fully evaluated
      return evaluator
          .lowerMapConstant(new MapConstant(keyType, valueType, parts.single));
    }
    List<Expression> maps = <Expression>[];
    for (Object part in parts) {
      if (part is List<ConstantMapEntry>) {
        maps.add(
            new ConstantExpression(new MapConstant(keyType, valueType, part)));
      } else if (part is Constant) {
        maps.add(evaluator.extract(part));
      } else {
        throw 'Non-constant in constant map';
      }
    }
    return evaluator.unevaluated(original,
        new MapConcatenation(maps, keyType: keyType, valueType: valueType));
  }
}
