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

import 'dart:collection';

import '../js_ast/js_ast.dart';

/// The ES6 name for the Dart SDK.  All dart:* libraries are in this module.
const String dartSdkModule = 'dart_sdk';

/// Unique instance for temporary variables. Will be renamed consistently
/// across the entire file. Different instances will be named differently
/// even if they have the same name, this makes it safe to use in code
/// generation without needing global knowledge. See [TemporaryNamer].
// TODO(jmesserly): move into js_ast? add a boolean to Identifier?
class TemporaryId extends Identifier {
  // TODO(jmesserly): by design, temporary identifier nodes are shared
  // throughout the AST, so any source information we attach in one location
  // be incorrect for another location (and overwrites previous data).
  //
  // If we want to track source information for temporary variables, we'll
  // need to separate the identity of the variable from its Identifier.
  //
  // In practice that makes temporaries more difficult to use: they're no longer
  // JS AST nodes, so `toIdentifier()` is required to put them in the JS AST.
  // And anywhere we currently use type `Identifier` to hold Identifier or
  // TemporaryId, those types would need to change to `Identifier Function()`.
  //
  // However we may need to fix this if we want hover to work well for things
  // like library prefixes and field-initializing formals.
  @override
  dynamic get sourceInformation => null;
  @override
  set sourceInformation(Object obj) {}

  TemporaryId(String name) : super(name);
}

/// Creates a qualified identifier, without determining for sure if it needs to
/// be qualified until [setQualified] is called.
///
/// This expression is transparent to visiting after [setQualified].
class MaybeQualifiedId extends Expression {
  Expression _expr;

  final Identifier qualifier;
  final Expression name;

  MaybeQualifiedId(this.qualifier, this.name) {
    _expr = PropertyAccess(qualifier, name);
  }

  /// Helper to create an [Identifier] from something that starts as a property.
  static Identifier identifier(LiteralString propertyName) =>
      Identifier(propertyName.valueWithoutQuotes);

  void setQualified(bool qualified) {
    var name = this.name;
    if (!qualified && name is LiteralString) {
      _expr = identifier(name);
    }
  }

  @override
  int get precedenceLevel => _expr.precedenceLevel;

  @override
  T accept<T>(NodeVisitor<T> visitor) => _expr.accept(visitor);

  @override
  void visitChildren(NodeVisitor visitor) => _expr.visitChildren(visitor);
}

/// Provides a mechanism to listen for naming choices when `Identifier` nodes
/// are compiled into an actual name in the JavaScript.
class NameListener {
  /// A mapping of all name selections that were made.
  final identifierNames = <Identifier, String>{};

  /// Signals that [name] was selected to represent [identifier].
  void nameSelected(Identifier identifier, String name) =>
      identifierNames[identifier] = name;
}

/// This class has two purposes:
///
/// * rename JS identifiers to avoid keywords.
/// * rename temporary variables to avoid colliding with user-specified names,
///   or other temporaries
///
/// Each instance of [TemporaryId] is treated as a unique variable, with its
/// `name` field simply the suggestion of what name to use. By contrast
/// [Identifiers] are never renamed unless they are an invalid identifier, like
/// `function` or `instanceof`, and their `name` field controls whether they
/// refer to the same variable.
class TemporaryNamer extends LocalNamer {
  _FunctionScope scope;

  /// Listener to be notified when a name is selected (rename or not) for an
  /// `Identifier`.
  ///
  /// Can be `null` when there is no listener attached.
  final NameListener _nameListener;

  TemporaryNamer(Node node, [this._nameListener])
      : scope = _RenameVisitor.build(node).rootScope;

  @override
  String getName(Identifier node) {
    var name = scope.renames[identifierKey(node)] ?? node.name;
    _nameListener?.nameSelected(node, name);
    return name;
  }

  @override
  void enterScope(Node node) {
    scope = scope.childScopes[node];
  }

  @override
  void leaveScope() {
    scope = scope.parent;
  }
}

/// Represents a complete function scope in JS.
///
/// We don't currently track ES6 block scopes.
class _FunctionScope {
  /// The parent scope.
  final _FunctionScope parent;

  /// All names declared in this scope.
  final declared = HashSet<Object>();

  /// All names [declared] in this scope or its [parent]s, that is used in this
  /// scope and/or children. This is exactly the set of variable names we must
  /// not collide with inside this scope.
  final used = HashSet<String>();

  /// Nested scopes, these are visited after everything else so the names
  /// they might need are in scope.
  final childScopes = <Node, _FunctionScope>{};

  /// New names assigned for temps and identifiers.
  final renames = HashMap<Object, String>();

  _FunctionScope(this.parent);
}

/// Collects all names used in the visited tree.
class _RenameVisitor extends VariableDeclarationVisitor {
  final pendingRenames = <Object, Set<_FunctionScope>>{};

  final _FunctionScope globalScope = _FunctionScope(null);
  final _FunctionScope rootScope = _FunctionScope(null);
  _FunctionScope scope;

  _RenameVisitor.build(Node root) {
    scope = rootScope;
    root.accept(this);
    _finishScopes();
    _finishNames();
  }

  @override
  void declare(Identifier node) {
    var id = identifierKey(node);
    var notAlreadyDeclared = scope.declared.add(id);
    // Normal identifiers can be declared multiple times, because we don't
    // implement block scope yet. However temps should only be declared once.
    assert(notAlreadyDeclared || node is! TemporaryId);
    _markUsed(node, id, scope);
  }

  @override
  void visitIdentifier(Identifier node) {
    var id = identifierKey(node);

    // Find where the node was declared.
    var declScope = scope;
    while (declScope != null && !declScope.declared.contains(id)) {
      declScope = declScope.parent;
    }
    if (declScope == null) {
      // Assume it comes from the global scope.
      declScope = globalScope;
      declScope.declared.add(id);
    }
    _markUsed(node, id, declScope);
  }

  void _markUsed(Identifier node, Object id, _FunctionScope declScope) {
    // If it needs rename, we can't add it to the used name set yet, instead we
    // will record all scopes it is visible in.
    Set<_FunctionScope> usedIn;
    var rename = declScope != globalScope && needsRename(node);
    if (rename) {
      usedIn = pendingRenames.putIfAbsent(id, () => HashSet());
    }
    for (var s = scope, end = declScope.parent; s != end; s = s.parent) {
      if (usedIn != null) {
        usedIn.add(s);
      } else {
        s.used.add(node.name);
      }
    }
  }

  @override
  void visitFunctionExpression(FunctionExpression node) {
    // Visit nested functions after all identifiers are declared.
    scope.childScopes[node] = _FunctionScope(scope);
  }

  @override
  void visitClassExpression(ClassExpression node) {
    scope.childScopes[node] = _FunctionScope(scope);
  }

  void _finishScopes() {
    scope.childScopes.forEach((node, s) {
      scope = s;
      if (node is FunctionExpression) {
        super.visitFunctionExpression(node);
      } else {
        super.visitClassExpression(node as ClassExpression);
      }
      _finishScopes();
      scope = scope.parent;
    });
  }

  void _finishNames() {
    pendingRenames.forEach((id, scopes) {
      var name = _findName(id, scopes);
      for (var s in scopes) {
        s.used.add(name);
        s.renames[id] = name;
      }
    });
  }

  static String _findName(Object id, Set<_FunctionScope> scopes) {
    String name;
    bool valid;
    if (id is TemporaryId) {
      name = id.name;
      valid = !invalidVariableName(name);
    } else {
      name = id as String;
      valid = false;
    }

    // Try to use the temp's name, otherwise rename.
    String candidate;
    if (valid && !scopes.any((scope) => scope.used.contains(name))) {
      candidate = name;
    } else {
      // This assumes that collisions are rare, hence linear search.
      // If collisions become common we need a better search.
      // TODO(jmesserly): what's the most readable scheme here? Maybe 1-letter
      // names in some cases?
      candidate = name == 'function' ? 'func' : '$name\$';
      for (var i = 0;
          scopes.any((scope) => scope.used.contains(candidate));
          i++) {
        candidate = '$name\$$i';
      }
    }
    return candidate;
  }
}

bool needsRename(Identifier node) =>
    node is TemporaryId || node.allowRename && invalidVariableName(node.name);

Object /*String|TemporaryId*/ identifierKey(Identifier node) =>
    node is TemporaryId ? node : node.name;

/// Returns true for invalid JS variable names, such as keywords.
/// Also handles invalid variable names in strict mode, like "arguments".
bool invalidVariableName(String keyword, {bool strictMode = true}) {
  switch (keyword) {
    // http://www.ecma-international.org/ecma-262/6.0/#sec-future-reserved-words
    case 'await':

    case 'break':
    case 'case':
    case 'catch':
    case 'class':
    case 'const':
    case 'continue':
    case 'debugger':
    case 'default':
    case 'delete':
    case 'do':
    case 'else':
    case 'enum':
    case 'export':
    case 'extends':
    case 'finally':
    case 'for':
    case 'function':
    case 'if':
    case 'import':
    case 'in':
    case 'instanceof':
    case 'new':
    case 'return':
    case 'super':
    case 'switch':
    case 'this':
    case 'throw':
    case 'try':
    case 'typeof':
    case 'var':
    case 'void':
    case 'while':
    case 'with':
      return true;
    case 'arguments':
    case 'eval':
    // http://www.ecma-international.org/ecma-262/6.0/#sec-future-reserved-words
    // http://www.ecma-international.org/ecma-262/6.0/#sec-identifiers-static-semantics-early-errors
    case 'implements':
    case 'interface':
    case 'let':
    case 'package':
    case 'private':
    case 'protected':
    case 'public':
    case 'static':
    case 'yield':
      return strictMode;
  }
  return false;
}

/// Returns true for names that cannot be set via `className.fieldName = ...`
/// on a JS class/constructor function.
///
/// These are getters on `Function.prototype` so we cannot set them but we can
/// define them on our object using `Object.defineProperty` or equivalent.
/// They are also valid as static getter/setter/method names if we use the JS
/// class syntax.
bool isFunctionPrototypeGetter(String name) {
  switch (name) {
    case 'arguments':
    case 'caller':
    case 'callee':
    case 'name':
    case 'length':
      return true;
  }
  return false;
}

/// See ES6 spec (and `Object.getOwnPropertyNames(Object.prototype)`):
///
/// http://www.ecma-international.org/ecma-262/6.0/#sec-properties-of-the-object-prototype-object
/// http://www.ecma-international.org/ecma-262/6.0/#sec-additional-properties-of-the-object.prototype-object
final objectProperties = <String>{
  'constructor',
  'toString',
  'toLocaleString',
  'valueOf',
  'hasOwnProperty',
  'isPrototypeOf',
  'propertyIsEnumerable',
  '__defineGetter__',
  '__lookupGetter__',
  '__defineSetter__',
  '__lookupSetter__',
  '__proto__'
};

/// Returns the JS member name for a public Dart instance member, before it
/// is symbolized; generally you should use [_emitMemberName] or
/// [_declareMemberName] instead of this.
String memberNameForDartMember(String name, [bool isExternal = false]) {
  // When generating synthetic names, we use _ as the prefix, since Dart names
  // won't have this, nor will static names reach here.
  switch (name) {
    case '[]':
      return '_get';
    case '[]=':
      return '_set';
    case 'unary-':
      return '_negate';
    case '==':
      return '_equals';
    case 'constructor':
    case 'prototype':
      // If [isExternal], assume the JS member is intended.
      return isExternal ? name : '_$name';
  }
  return name;
}

final friendlyNameForDartOperator = {
  '<': 'lessThan',
  '>': 'greaterThan',
  '<=': 'lessOrEquals',
  '>=': 'greaterOrEquals',
  '-': 'minus',
  '+': 'plus',
  '/': 'divide',
  '~/': 'floorDivide',
  '*': 'times',
  '%': 'modulo',
  '|': 'bitOr',
  '^': 'bitXor',
  '&': 'bitAnd',
  '<<': 'leftShift',
  '>>': 'rightShift',
  '>>>': 'tripleShift',
  '~': 'bitNot',
  // These ones are always renamed, hence the choice of `_` to avoid conflict
  // with Dart names. See _emitMemberName.
  '==': '_equals',
  '[]': '_get',
  '[]=': '_set',
  'unary-': '_negate',
};

// Invalid characters for identifiers, which would need to be escaped.
final invalidCharInIdentifier = RegExp(r'[^A-Za-z_$0-9]');

/// Escape [name] to make it into a valid identifier.
String toJSIdentifier(String name) {
  if (name.isEmpty) return r'$';

  // Escape any invalid characters
  StringBuffer buffer;
  for (var i = 0; i < name.length; i++) {
    var ch = name[i];
    var needsEscape = ch == r'$' || invalidCharInIdentifier.hasMatch(ch);
    if (needsEscape && buffer == null) {
      buffer = StringBuffer(name.substring(0, i));
    }
    if (buffer != null) {
      buffer.write(needsEscape ? '\$${ch.codeUnits.join("")}' : ch);
    }
  }

  var result = buffer != null ? '$buffer' : name;
  // Ensure the identifier first character is not numeric and that the whole
  // identifier is not a keyword.
  if (result.startsWith(RegExp('[0-9]')) || invalidVariableName(result)) {
    return '\$$result';
  }
  return result;
}
