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

// This file implements a miniature string-based internal representation ("IR")
// of Dart code suitable for use in unit testing.

import 'package:test/test.dart';

import 'mini_ast.dart';

/// A single stack entry representing an intermediate representation of some
/// Dart code produced using the facilities of `mini_ast.dart`.
class IRNode {
  /// The intermediate representation itself, expressed as a string.
  final String ir;

  /// The location of the Dart code that led to this [IRNode].
  final String location;

  /// The kind of entity represented by this [IRNode].
  final Kind kind;

  IRNode({required this.ir, required this.location, required this.kind});

  @override
  String toString() => '$kind $ir ($location)';
}

/// Kinds of entities that can be represented by an [IRNode].
enum Kind {
  /// A single `case` or `default` clause in a switch statement or switch
  /// expression.
  caseHead,

  /// A set of `case` or `default` clauses in a switch statement, which all
  /// share the same body.
  caseHeads,

  /// A collection element.
  collectionElement,

  /// An expression.
  expression,

  /// A single case from a switch expression, consisting of a [caseHead] and a
  /// body [expression].
  expressionCase,

  /// A label for `break` or `continue` to branch to.
  label,

  /// A map pattern element.
  mapPatternElement,

  /// A pattern.
  pattern,

  /// A statement.
  statement,

  /// A single case from a switch statement, consisting of [caseHeads] and body
  /// [statement]s.
  statementCase,

  /// A type in the type system.
  type,

  /// A local variable.
  variable,

  /// A set of pattern variables.
  variables,
}

/// Stack-based builder class allowing construction of a miniature string-based
/// internal representation ("IR") of Dart code suitable for use in unit
/// testing.
class MiniIRBuilder {
  /// Set this to `true` to enable print-based tracing of stack operations.
  static const bool _debug = false;

  /// If [_debug] is enabled, number of outstanding calls to [guard].  This
  /// controls indentation of debug output.
  int _guardDepth = 0;

  /// Number of labels allocated so far.
  int _labelCounter = 0;

  /// Size threshold for [_stack].  [_pop] and [_popList] will cause a test
  /// failure if an attempt is made to reduce the stack size to less than this
  /// amount.  See [guard].
  int _popLimit = 0;

  /// Stack of partially built IR nodes.
  final _stack = <IRNode>[];

  /// Number of temporaries allocated so far.
  int _tmpCounter = 0;

  /// Creates a fresh [MiniIRLabel] representing a label that can be used as a
  /// break target.
  ///
  /// See [labeled].
  MiniIRLabel allocateLabel() => MiniIRLabel._();

  /// Pops the top node from the stack (which should represent an expression)
  /// and creates a fresh [MiniIRTmp] representing a temporary variable whose
  /// initializer is that expression.
  ///
  /// [location] should be a string representing the location of the test logic
  /// that caused this temporary variable to be created (see [computeLocation]).
  ///
  /// See [let].
  MiniIRTmp allocateTmp({required String location}) {
    return MiniIRTmp._('t${_tmpCounter++}', _pop(Kind.expression).ir,
        location: location);
  }

  /// Pops the top [inputKinds].length nodes from the stack and pushes a node
  /// that combines them using [name].  For example, if the stack contains
  /// `1, 2, 3`, calling `apply('f', [Kind.expression, Kind.expression])`
  /// results in a stack of `1, f(2, 3)`.
  ///
  /// Optional argument [names] allows applying names to the last n arguments.
  /// For example, if the stack contains `1, 2, 3`, calling
  /// `apply('f', 3, names: ['a', 'b'])` results in a stack of
  /// `f(1, a: 2, b: 3)`.
  void apply(String name, List<Kind> inputKinds, Kind outputKind,
      {required String location, List<String> names = const []}) {
    var args = [
      for (var irNode in _popList(inputKinds.length, inputKinds)) irNode.ir
    ];
    for (int i = 1; i <= names.length; i++) {
      args[args.length - i] =
          '${names[names.length - i]}: ${args[args.length - i]}';
    }
    _push(IRNode(
        ir: '$name(${args.join(', ')})', kind: outputKind, location: location));
  }

  /// Pushes a node on the stack representing a single atomic expression (for
  /// example a literal value or a variable reference).
  void atom(String name, Kind kind, {required String location}) =>
      _push(IRNode(ir: name, kind: kind, location: location));

  /// Verifies that the top node on the stack matches [expectedIR] exactly.
  void check(String expectedIR, Kind expectedKind, {required String location}) {
    expect(_stack.last, _nodeWithKind(expectedKind), reason: 'at $location');
    expect(_stack.last.ir, expectedIR, reason: 'at $location');
  }

  /// Pushes a node representing a `for-in` loop onto the stack, using a loop
  /// variable, iterable expression, and loop body obtained from the stack.
  ///
  /// If [tmp] is non-null, it is used as the loop variable instead of obtaining
  /// it from the stack.
  void forIn(MiniIRTmp? tmp,
      {required String location, required bool isAsynchronous}) {
    var name = isAsynchronous ? 'forIn_async' : 'forIn';
    var body = _pop(Kind.statement);
    var iterable = _pop(Kind.expression);
    var variable = tmp == null ? _pop(Kind.variable) : tmp._name;
    _push(IRNode(
        ir: '$name($variable, $iterable, $body)',
        kind: Kind.statement,
        location: location));
  }

  /// Executes [callback], checking that it leaves all nodes presently on the
  /// stack untouched, and results in exactly one node being added to the stack.
  T guard<T>(Node node, T Function() callback) {
    if (_debug) {
      print('  ' * _guardDepth++ + '$node');
    }
    int previousStackDepth = _stack.length;
    int previousPopLimit = _popLimit;
    _popLimit = previousStackDepth;
    var result = callback();
    var stackDelta = _stack.length - previousStackDepth;
    if (stackDelta != 1) {
      fail('Stack delta of $stackDelta while visiting '
          '${node.runtimeType} $node\n'
          'Stack: $this');
    }
    if (_debug) {
      print('  ' * --_guardDepth + '=> ${_stack.last}');
    }
    _popLimit = previousPopLimit;
    return result;
  }

  /// Pushes a node representing an "if not null" check onto the stack, using
  /// [tmp] and an expression obtained from the stack.  The intended semantics
  /// are `tmp == null ? null : <expression>`.
  ///
  /// This is intended to be used as a building block for null shorting
  /// operations.
  void ifNotNull(MiniIRTmp tmp, {required String location}) {
    _push(IRNode(
        ir: 'if(==(${tmp._name}, null), null, ${_pop(Kind.expression).ir})',
        kind: Kind.expression,
        location: location));
    let(tmp, location: location);
  }

  /// Pushes a node representing an "if null" check onto the stack, using [tmp]
  /// and two expressions obtained from the stack.  The intended semantics
  /// are `tmp == null ? <expression 1> : <expression 2>`.
  ///
  /// This is intended to be used as a building block for null `??` and `??=`
  /// operations.
  void ifNull(MiniIRTmp tmp, {required String location}) {
    var ifNull = _pop(Kind.expression);
    var ifNotNull = _pop(Kind.expression);
    _push(IRNode(
        ir: 'if(==(${tmp._name}, null), $ifNull, $ifNotNull)',
        kind: Kind.expression,
        location: location));
    let(tmp, location: location);
  }

  /// Pushes a node representing a call to `operator[]` onto the stack, using
  /// a receiver and an index obtained from the stack.
  void indexGet({required String location}) =>
      apply('[]', [Kind.expression, Kind.expression], Kind.expression,
          location: location);

  /// Pushes a node representing a call to `operator[]=` onto the stack, using
  /// a receiver, index, and value obtained from the stack.
  ///
  /// If [receiverTmp] and/or [indexTmp] is non-null, they are used instead of
  /// obtaining values from the stack.
  void indexSet(MiniIRTmp? receiverTmp, MiniIRTmp? indexTmp,
      {required String location}) {
    var value = _pop(Kind.expression);
    var index = indexTmp == null ? _pop(Kind.expression) : indexTmp._name;
    var receiver =
        receiverTmp == null ? _pop(Kind.expression) : receiverTmp._name;
    _push(IRNode(
        ir: '[]=($receiver, $index, $value)',
        kind: Kind.expression,
        location: location));
  }

  /// Pushes a node representing a labeled statement onto the stack, using an
  /// inner statement obtained from the stack.
  ///
  /// To build up a statement of the form `labeled(L0, stmt)` (where `stmt`
  /// might refer to `L0`), do the following operations:
  /// - Call [allocateLabel] to prepare the label.
  /// - build `stmt` on the stack, using [referToLabel] to refer to label as
  ///   needed.
  /// - Call [labeled] to build the final `labeled` statement.
  void labeled(MiniIRLabel label, {required String location}) {
    var name = label._name;
    if (name != null) {
      _push(IRNode(
          ir: 'labeled($name, ${_pop(Kind.statement)})',
          kind: Kind.statement,
          location: location));
    }
  }

  /// Pushes a node representing a `let` expression onto the stack, using a
  /// value obtained from the stack.
  ///
  /// To build up an expression of the form `let(#0, value, expr)` (meaning
  /// "let temporary variable #0 take on value while evaluating expr"), do the
  /// following operations:
  /// - Build `value` on the stack.
  /// - Call [allocateTmp] to pop `value` off the stack and obtain a
  ///   [MiniIRTmp] object.  This will assign the temporary variable a name that
  ///   doesn't conflict with any other outstanding temporary variables.
  /// - Build `expr` on the stack, using [readTmp] to refer to the temporary
  ///   variable as needed.
  /// - Call [let] to build the final `let` expression.
  void let(MiniIRTmp tmp, {required String location}) {
    _push(IRNode(
        ir: 'let(${tmp._name}, ${tmp._value}, ${_pop(Kind.expression).ir})',
        kind: Kind.expression,
        location: location));
  }

  /// Pushes a node representing a property get onto the stack, using a receiver
  /// obtained from the stack.
  void propertyGet(String propertyName, {required String location}) =>
      apply('get_$propertyName', [Kind.expression], Kind.expression,
          location: location);

  /// Pushes a node representing a property set onto the stack, using a receiver
  /// and value obtained from the stack.
  ///
  /// If [receiverTmp] is non-null, it is used as the receiver rather than
  /// obtaining it from the stack.
  void propertySet(MiniIRTmp? receiverTmp, String propertyName,
      {required String location}) {
    var value = _pop(Kind.expression);
    var receiver =
        receiverTmp == null ? _pop(Kind.expression) : receiverTmp._name;
    _push(IRNode(
        ir: 'set_$propertyName($receiver, $value)',
        kind: Kind.expression,
        location: location));
  }

  /// Pushes a node representing a read of [tmp] onto the stack.
  void readTmp(MiniIRTmp tmp, {required String location}) =>
      _push(IRNode(ir: tmp._name, kind: Kind.expression, location: location));

  /// Pushes a node representing a reference to [label] onto the stack.
  void referToLabel(MiniIRLabel label, {required String location}) {
    _push(IRNode(
        ir: label._name ??= 'L${_labelCounter++}',
        kind: Kind.label,
        location: location));
  }

  @override
  String toString() => [for (var irNode in _stack) irNode.ir].join(', ');

  /// Pushes a node representing a read of a local variable onto the stack.
  void variableGet(Var v, {required String location}) =>
      atom(v.name, Kind.expression, location: location);

  /// Pushes a node representing a set of a local variable onto the stack, using
  /// a value obtained from the stack.
  void variableSet(Var v, {required String location}) =>
      apply('${v.name}=', [Kind.expression], Kind.expression,
          location: location);

  TypeMatcher<IRNode> _nodeWithKind(Kind expectedKind) =>
      TypeMatcher<IRNode>().having((node) => node.kind, 'kind', expectedKind);

  /// Pops a single node off the stack.
  IRNode _pop(Kind expectedKind) {
    expect(_stack.length, greaterThan(_popLimit));
    var irNode = _stack.removeLast();
    expect(irNode, _nodeWithKind(expectedKind));
    return irNode;
  }

  /// Pops a list of nodes off the stack.
  List<IRNode> _popList(int count, List<Kind> expectedKinds) {
    var newLength = _stack.length - count;
    expect(newLength, greaterThanOrEqualTo(_popLimit));
    var result = _stack.sublist(newLength);
    _stack.length = newLength;
    expect(result,
        [for (var expectedKind in expectedKinds) _nodeWithKind(expectedKind)]);
    return result;
  }

  /// Pushes a node onto the stack.
  void _push(IRNode node) {
    _stack.add(node);
  }
}

/// Representation of a branch target label used by [MiniIRBuilder] when
/// building up `labeled` statements.
class MiniIRLabel {
  /// The name of the label, or `null` if no name has been assigned yet.
  String? _name;

  MiniIRLabel._();
}

/// Representation of a temporary variable used by [MiniIRBuilder] when building
/// up `let` expressions.
class MiniIRTmp {
  /// The name of the temporary variable.
  final String _name;

  /// The initial value of the temporary variable.
  final String _value;

  /// A string representing the location of the test logic that caused this
  /// temporary variable to be created (see [computeLocation]).
  final String location;

  MiniIRTmp._(this._name, this._value, {required this.location});
}
