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

import '../common.dart';
import '../common/elements.dart';
import '../constants/constant_system.dart' as constant_system;
import '../constants/values.dart';
import '../elements/entities.dart';
import '../elements/types.dart';
import '../js/js.dart' as jsAst;
import '../js/js.dart' show js;
import '../js_backend/field_analysis.dart';
import '../js_backend/type_reference.dart' show TypeReference;
import '../js_backend/string_reference.dart'
    show StringReference, StringReferencePolicy;
import '../js_emitter/code_emitter_task.dart';
import '../js_model/type_recipe.dart' show TypeExpressionRecipe;
import '../options.dart';
import 'namer.dart';
import 'runtime_types_new.dart' show RecipeEncoder;
import 'runtime_types_resolution.dart';

typedef _ConstantReferenceGenerator = jsAst.Expression Function(
    ConstantValue constant);

typedef _ConstantListGenerator = jsAst.Expression Function(
    jsAst.Expression array);

/// Visitor that creates [jsAst.Expression]s for constants that are inlined
/// and therefore can be created during modular code generation.
class ModularConstantEmitter
    implements ConstantValueVisitor<jsAst.Expression, Null> {
  final CompilerOptions _options;
  final ModularNamer _namer;

  ModularConstantEmitter(this._options, this._namer);

  /// Constructs a literal expression that evaluates to the constant. Uses a
  /// canonical name unless the constant can be emitted multiple times (as for
  /// numbers and strings).
  jsAst.Expression generate(ConstantValue constant) {
    return _visit(constant);
  }

  jsAst.Expression _visit(ConstantValue constant) {
    return constant.accept(this, null);
  }

  @override
  jsAst.Expression visitFunction(FunctionConstantValue constant, [_]) {
    throw failedAt(NO_LOCATION_SPANNABLE,
        "The function constant does not need specific JS code.");
  }

  @override
  jsAst.Expression visitNull(NullConstantValue constant, [_]) {
    return jsAst.LiteralNull();
  }

  @override
  jsAst.Expression visitNonConstant(NonConstantValue constant, [_]) {
    return jsAst.LiteralNull();
  }

  static final _exponentialRE = RegExp('^'
      '\([-+]?\)' // 1: sign
      '\([0-9]+\)' // 2: leading digit(s)
      '\(\.\([0-9]*\)\)?' // 4: fraction digits
      'e\([-+]?[0-9]+\)' // 5: exponent with sign
      r'$');

  /// Reduces the size of exponential representations when minification is
  /// enabled.
  ///
  /// Removes the "+" after the exponential sign, and removes the "." before the
  /// "e". For example `1.23e+5` is changed to `123e3`.
  String _shortenExponentialRepresentation(String numberString) {
    Match match = _exponentialRE.firstMatch(numberString);
    if (match == null) return numberString;
    String sign = match[1];
    String leadingDigits = match[2];
    String fractionDigits = match[4];
    int exponent = int.parse(match[5]);
    if (fractionDigits == null) fractionDigits = '';
    exponent -= fractionDigits.length;
    String result = '${sign}${leadingDigits}${fractionDigits}e${exponent}';
    assert(double.parse(result) == double.parse(numberString));
    return result;
  }

  @override
  jsAst.Expression visitInt(IntConstantValue constant, [_]) {
    BigInt value = constant.intValue;
    // Since we are in JavaScript we can shorten long integers to their shorter
    // exponential representation, for example: "1e4" is shorter than "10000".
    //
    // Note that this shortening apparently loses precision for big numbers
    // (like 1234567890123456789012345 which becomes 12345678901234568e8).
    // However, since JavaScript engines represent all numbers as doubles, these
    // digits are lost anyway.
    String representation = value.toString();
    String alternative = null;
    int cutoff = _options.enableMinification ? 10000 : 1e10.toInt();
    if (value.abs() >= BigInt.from(cutoff)) {
      alternative = _shortenExponentialRepresentation(
          value.toDouble().toStringAsExponential());
    }
    if (alternative != null && alternative.length < representation.length) {
      representation = alternative;
    }
    return jsAst.LiteralNumber(representation);
  }

  @override
  jsAst.Expression visitDouble(DoubleConstantValue constant, [_]) {
    double value = constant.doubleValue;
    if (value.isNaN) {
      return js("0/0");
    } else if (value == double.infinity) {
      return js("1/0");
    } else if (value == -double.infinity) {
      return js("-1/0");
    } else {
      String shortened = _shortenExponentialRepresentation("$value");
      return jsAst.LiteralNumber(shortened);
    }
  }

  @override
  jsAst.Expression visitBool(BoolConstantValue constant, [_]) {
    if (_options.enableMinification) {
      if (constant is TrueConstantValue) {
        // Use !0 for true.
        return js("!0");
      } else {
        // Use !1 for false.
        return js("!1");
      }
    } else {
      return constant is TrueConstantValue ? js('true') : js('false');
    }
  }

  /// Write the contents of the quoted string to a [CodeBuffer] in
  /// a form that is valid as JavaScript string literal content.
  /// The string is assumed quoted by double quote characters.
  @override
  jsAst.Expression visitString(StringConstantValue constant, [_]) {
    String value = constant.stringValue;
    if (value.length < StringReferencePolicy.minimumLength) {
      return js.string(value);
    }
    return StringReference(constant);
  }

  @override
  jsAst.Expression visitDummyInterceptor(DummyInterceptorConstantValue constant,
      [_]) {
    return jsAst.LiteralNumber('0');
  }

  @override
  jsAst.Expression visitLateSentinel(LateSentinelConstantValue constant, [_]) =>
      _namer.globalObjectForStaticState();

  @override
  jsAst.Expression visitUnreachable(UnreachableConstantValue constant, [_]) {
    // Unreachable constants should be rare in generated code, so we use
    // `undefined` encoded as `void 1' to make them distinctive.
    return js('void 1');
  }

  @override
  jsAst.Expression visitJsName(JsNameConstantValue constant, [_]) {
    return constant.name;
  }

  @override
  jsAst.Expression visitInstantiation(InstantiationConstantValue constant,
          [_]) =>
      null;

  @override
  jsAst.Expression visitDeferredGlobal(DeferredGlobalConstantValue constant,
          [_]) =>
      null;

  @override
  jsAst.Expression visitInterceptor(InterceptorConstantValue constant, [_]) =>
      null;

  @override
  jsAst.Expression visitType(TypeConstantValue constant, [_]) => null;

  @override
  jsAst.Expression visitConstructed(ConstructedConstantValue constant, [_]) =>
      null;

  @override
  jsAst.Expression visitMap(MapConstantValue constant, [_]) => null;

  @override
  jsAst.Expression visitSet(SetConstantValue constant, [_]) => null;

  @override
  jsAst.Expression visitList(ListConstantValue constant, [_]) => null;
}

/// Generates the JavaScript expressions for constants.
///
/// It uses a given [_constantReferenceGenerator] to reference nested constants
/// (if there are some). It is hence up to that function to decide which
/// constants should be inlined or not.
class ConstantEmitter extends ModularConstantEmitter {
  // Matches blank lines, comment lines and trailing comments that can't be part
  // of a string.
  static final RegExp COMMENT_RE =
      RegExp(r'''^ *(//.*)?\n|  *//[^''"\n]*$''', multiLine: true);

  final JCommonElements _commonElements;
  final JElementEnvironment _elementEnvironment;
  final RuntimeTypesNeed _rtiNeed;
  final RecipeEncoder _rtiRecipeEncoder;
  final JFieldAnalysis _fieldAnalysis;
  final Emitter _emitter;
  final _ConstantReferenceGenerator _constantReferenceGenerator;
  final _ConstantListGenerator _makeConstantList;

  /// The given [_constantReferenceGenerator] function must, when invoked with a
  /// constant, either return a reference or return its literal expression if it
  /// can be inlined.
  ConstantEmitter(
      CompilerOptions options,
      ModularNamer _namer,
      this._commonElements,
      this._elementEnvironment,
      this._rtiNeed,
      this._rtiRecipeEncoder,
      this._fieldAnalysis,
      this._emitter,
      this._constantReferenceGenerator,
      this._makeConstantList)
      : super(options, _namer);

  @override
  jsAst.Expression visitList(ListConstantValue constant, [_]) {
    List<jsAst.Expression> elements = constant.entries
        .map(_constantReferenceGenerator)
        .toList(growable: false);
    jsAst.ArrayInitializer array = jsAst.ArrayInitializer(elements);
    jsAst.Expression value = _makeConstantList(array);
    return maybeAddListTypeArgumentsNewRti(constant, constant.type, value);
  }

  @override
  jsAst.Expression visitSet(constant_system.JavaScriptSetConstant constant,
      [_]) {
    InterfaceType sourceType = constant.type;
    ClassEntity classElement = sourceType.element;
    String className = classElement.name;
    if (!identical(classElement, _commonElements.constSetLiteralClass)) {
      failedAt(
          classElement, "Compiler encoutered unexpected set class $className");
    }

    List<jsAst.Expression> arguments = [
      _constantReferenceGenerator(constant.entries),
    ];

    if (_rtiNeed.classNeedsTypeArguments(classElement)) {
      arguments.add(_reifiedTypeNewRti(sourceType));
    }

    jsAst.Expression constructor = _emitter.constructorAccess(classElement);
    return jsAst.New(constructor, arguments);
  }

  @override
  jsAst.Expression visitMap(constant_system.JavaScriptMapConstant constant,
      [_]) {
    jsAst.Expression jsMap() {
      List<jsAst.Property> properties = [];
      for (int i = 0; i < constant.length; i++) {
        StringConstantValue key = constant.keys[i];
        if (key.stringValue ==
            constant_system.JavaScriptMapConstant.PROTO_PROPERTY) {
          continue;
        }

        // Keys in literal maps must be emitted in place.
        jsAst.Literal keyExpression = js.string(key.stringValue);
        jsAst.Expression valueExpression =
            _constantReferenceGenerator(constant.values[i]);
        properties.add(jsAst.Property(keyExpression, valueExpression));
      }
      return jsAst.ObjectInitializer(properties);
    }

    jsAst.Expression jsGeneralMap() {
      List<jsAst.Expression> data = [];
      for (int i = 0; i < constant.keys.length; i++) {
        jsAst.Expression keyExpression =
            _constantReferenceGenerator(constant.keys[i]);
        jsAst.Expression valueExpression =
            _constantReferenceGenerator(constant.values[i]);
        data.add(keyExpression);
        data.add(valueExpression);
      }
      return jsAst.ArrayInitializer(data);
    }

    ClassEntity classElement = constant.type.element;
    String className = classElement.name;

    List<jsAst.Expression> arguments = [];

    // The arguments of the JavaScript constructor for any given Dart class
    // are in the same order as the members of the class element.
    int emittedArgumentCount = 0;
    _elementEnvironment.forEachInstanceField(classElement,
        (ClassEntity enclosing, FieldEntity field) {
      if (_fieldAnalysis.getFieldData(field).isElided) return;
      if (field.name == constant_system.JavaScriptMapConstant.LENGTH_NAME) {
        arguments
            .add(jsAst.LiteralNumber('${constant.keyList.entries.length}'));
      } else if (field.name ==
          constant_system.JavaScriptMapConstant.JS_OBJECT_NAME) {
        arguments.add(jsMap());
      } else if (field.name ==
          constant_system.JavaScriptMapConstant.KEYS_NAME) {
        arguments.add(_constantReferenceGenerator(constant.keyList));
      } else if (field.name ==
          constant_system.JavaScriptMapConstant.JS_DATA_NAME) {
        arguments.add(jsGeneralMap());
      } else {
        failedAt(field,
            "Compiler has unexpected field ${field.name} for ${className}.");
      }
      emittedArgumentCount++;
    });
    if ((className == constant_system.JavaScriptMapConstant.DART_STRING_CLASS &&
            emittedArgumentCount != 3) ||
        (className ==
                constant_system.JavaScriptMapConstant.DART_GENERAL_CLASS &&
            emittedArgumentCount != 1)) {
      failedAt(classElement,
          "Compiler and ${className} disagree on number of fields.");
    }

    if (_rtiNeed.classNeedsTypeArguments(classElement)) {
      arguments.add(_reifiedTypeNewRti(constant.type));
    }

    jsAst.Expression constructor = _emitter.constructorAccess(classElement);
    jsAst.Expression value = jsAst.New(constructor, arguments);
    return value;
  }

  jsAst.PropertyAccess getHelperProperty(FunctionEntity helper) {
    return _emitter.staticFunctionAccess(helper);
  }

  @override
  jsAst.Expression visitType(TypeConstantValue constant, [_]) {
    DartType type = constant.representedType;

    assert(!type.containsTypeVariables);

    jsAst.Expression recipe = _rtiRecipeEncoder.encodeGroundRecipe(
        _emitter, TypeExpressionRecipe(type));

    // Generate  `typeLiteral(recipe)`.

    // TODO(sra): `typeLiteral(r)` calls `createRuntimeType(findType(r))`.
    // Find a way to share the `findType` call with methods that also use the
    // type.
    return js(
        '#(#)', [getHelperProperty(_commonElements.typeLiteralMaker), recipe]);
  }

  @override
  jsAst.Expression visitInterceptor(InterceptorConstantValue constant, [_]) {
    ClassEntity interceptorClass = constant.cls;
    return _emitter.interceptorPrototypeAccess(interceptorClass);
  }

  @override
  jsAst.Expression visitConstructed(ConstructedConstantValue constant, [_]) {
    ClassEntity element = constant.type.element;
    if (element == _commonElements.jsConstClass) {
      StringConstantValue str = constant.fields.values.single;
      String value = str.stringValue;
      return jsAst.LiteralExpression(stripComments(value));
    }
    jsAst.Expression constructor =
        _emitter.constructorAccess(constant.type.element);
    List<jsAst.Expression> fields = [];
    _elementEnvironment.forEachInstanceField(element, (_, FieldEntity field) {
      FieldAnalysisData fieldData = _fieldAnalysis.getFieldData(field);
      if (fieldData.isElided) return;
      if (!fieldData.isInitializedInAllocator) {
        fields.add(_constantReferenceGenerator(constant.fields[field]));
      }
    });
    if (_rtiNeed.classNeedsTypeArguments(constant.type.element)) {
      fields.add(_reifiedTypeNewRti(constant.type));
    }
    return jsAst.New(constructor, fields);
  }

  @override
  jsAst.Expression visitInstantiation(InstantiationConstantValue constant,
      [_]) {
    ClassEntity cls =
        _commonElements.getInstantiationClass(constant.typeArguments.length);
    List<jsAst.Expression> fields = [
      _constantReferenceGenerator(constant.function)
    ];
    fields.add(_reifiedTypeNewRti(
        _commonElements.dartTypes.interfaceType(cls, constant.typeArguments)));
    jsAst.Expression constructor = _emitter.constructorAccess(cls);
    return jsAst.New(constructor, fields);
  }

  String stripComments(String rawJavaScript) {
    return rawJavaScript.replaceAll(COMMENT_RE, '');
  }

  jsAst.Expression maybeAddListTypeArgumentsNewRti(
      ConstantValue constant, InterfaceType type, jsAst.Expression value) {
    assert(type.element == _commonElements.jsArrayClass);
    if (_rtiNeed.classNeedsTypeArguments(type.element)) {
      return jsAst.Call(getHelperProperty(_commonElements.setArrayType),
          [value, _reifiedTypeNewRti(type)]);
    }
    return value;
  }

  jsAst.Expression _reifiedTypeNewRti(DartType type) {
    assert(!type.containsTypeVariables);
    return TypeReference(TypeExpressionRecipe(type))..forConstant = true;
  }

  @override
  jsAst.Expression visitDeferredGlobal(DeferredGlobalConstantValue constant,
      [_]) {
    return _constantReferenceGenerator(constant.referenced);
  }
}
