// 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.

library vm.bytecode.local_variable_table;

import 'bytecode_serialization.dart';

enum LocalVariableEntryKind {
  invalid,
  scope,
  variableDeclaration,
  contextVariable,
}

abstract class LocalVariableEntry {
  static const KindMask = 0x0F;
  static const IsCapturedFlag = 1 << 4;

  LocalVariableEntryKind get kind;
  int get flags => 0;
  final int startPC;
  void writeContents(BufferedWriter writer);

  LocalVariableEntry(this.startPC);
}

class Scope extends LocalVariableEntry {
  int endPC;
  int contextLevel;
  int position;
  int endPosition;
  final List<VariableDeclaration> variables = <VariableDeclaration>[];

  Scope(int startPC, this.endPC, this.contextLevel, this.position,
      this.endPosition)
      : super(startPC);

  @override
  LocalVariableEntryKind get kind => LocalVariableEntryKind.scope;

  @override
  void writeContents(BufferedWriter writer) {
    if (endPC == null) {
      throw '$this is not closed';
    }
    writer.writePackedUInt30(endPC - startPC);
    writer.writeSLEB128(contextLevel);
    writer.writePackedUInt30(position + 1);
    writer.writePackedUInt30(endPosition + 1);
  }

  Scope.readContents(BufferedReader reader, int startPC) : super(startPC) {
    endPC = startPC = reader.readPackedUInt30();
    contextLevel = reader.readSLEB128();
    position = reader.readPackedUInt30() - 1;
    endPosition = reader.readPackedUInt30() - 1;
  }

  @override
  String toString() =>
      'scope (pc $startPC-$endPC pos $position-$endPosition context-level $contextLevel)';
}

class VariableDeclaration extends LocalVariableEntry {
  bool isCaptured;
  int index;
  int name;
  int type;
  int position;
  int initializedPosition;

  VariableDeclaration(int startPC, this.isCaptured, this.index, this.name,
      this.type, this.position, this.initializedPosition)
      : super(startPC);

  @override
  LocalVariableEntryKind get kind => LocalVariableEntryKind.variableDeclaration;

  @override
  int get flags => (isCaptured ? LocalVariableEntry.IsCapturedFlag : 0);

  @override
  void writeContents(BufferedWriter writer) {
    writer.writeSLEB128(index);
    writer.writePackedUInt30(name);
    writer.writePackedUInt30(type);
    writer.writePackedUInt30(position + 1);
    writer.writePackedUInt30(initializedPosition + 1);
  }

  VariableDeclaration.readContents(
      BufferedReader reader, int startPC, int flags)
      : super(startPC) {
    isCaptured = (flags & LocalVariableEntry.IsCapturedFlag) != 0;
    index = reader.readSLEB128();
    name = reader.readPackedUInt30();
    type = reader.readPackedUInt30();
    position = reader.readPackedUInt30() - 1;
    initializedPosition = reader.readPackedUInt30() - 1;
  }

  @override
  String toString() =>
      'variable $index${isCaptured ? ' (captured)' : ''} pc $startPC, name CP#$name, type CP#$type, pos $position, init-pos $initializedPosition';
}

class ContextVariable extends LocalVariableEntry {
  int index;

  ContextVariable(int startPC, this.index) : super(startPC);

  @override
  LocalVariableEntryKind get kind => LocalVariableEntryKind.contextVariable;

  @override
  void writeContents(BufferedWriter writer) {
    writer.writeSLEB128(index);
  }

  ContextVariable.readContents(BufferedReader reader, int startPC)
      : super(startPC) {
    index = reader.readSLEB128();
  }

  @override
  String toString() => 'context variable $index';
}

/// Keeps information about declared local variables.
class LocalVariableTable {
  final scopes = <Scope>[];
  final activeScopes = <Scope>[];
  ContextVariable contextVariable;

  LocalVariableTable();

  void enterScope(int pc, int contextLevel, int position) {
    final scope = new Scope(pc, null, contextLevel, position, null);
    activeScopes.add(scope);
    scopes.add(scope);
  }

  void declareVariable(int pc, bool isCaptured, int index, int nameCpIndex,
      int typeCpIndex, int position, int initializedPosition) {
    final variable = new VariableDeclaration(pc, isCaptured, index, nameCpIndex,
        typeCpIndex, position, initializedPosition);
    activeScopes.last.variables.add(variable);
  }

  void leaveScope(int pc, int endPosition) {
    final scope = activeScopes.removeLast();
    scope.endPC = pc;
    scope.endPosition = endPosition;
    if (scope.variables.isEmpty) {
      scopes.remove(scope);
    }
  }

  void recordContextVariable(int pc, int index) {
    assert(contextVariable == null);
    contextVariable = new ContextVariable(pc, index);
  }

  bool get isEmpty => scopes.isEmpty && contextVariable == null;

  bool get isNotEmpty => !isEmpty;

  bool get hasActiveScopes => activeScopes.isNotEmpty;

  List<LocalVariableEntry> getEntries() {
    final entries = <LocalVariableEntry>[];
    if (contextVariable != null) {
      entries.add(contextVariable);
    }
    for (Scope scope in scopes) {
      entries.add(scope);
      entries.addAll(scope.variables);
    }
    return entries;
  }

  void write(BufferedWriter writer) {
    final entries = getEntries();
    writer.writePackedUInt30(entries.length);
    final encodeStartPC = new SLEB128DeltaEncoder();
    for (var entry in entries) {
      writer.writeByte(entry.kind.index | entry.flags);
      encodeStartPC.write(writer, entry.startPC);
      entry.writeContents(writer);
    }
  }

  LocalVariableTable.read(BufferedReader reader) {
    final int numEntries = reader.readPackedUInt30();
    final decodeStartPC = new SLEB128DeltaDecoder();
    Scope scope;
    for (int i = 0; i < numEntries; ++i) {
      final int kindAndFlags = reader.readByte();
      final LocalVariableEntryKind kind = LocalVariableEntryKind
          .values[kindAndFlags & LocalVariableEntry.KindMask];
      final int flags = kindAndFlags & ~LocalVariableEntry.KindMask;
      final int startPC = decodeStartPC.read(reader);
      switch (kind) {
        case LocalVariableEntryKind.scope:
          scope = new Scope.readContents(reader, startPC);
          scopes.add(scope);
          break;
        case LocalVariableEntryKind.variableDeclaration:
          scope.variables.add(
              new VariableDeclaration.readContents(reader, startPC, flags));
          break;
        case LocalVariableEntryKind.contextVariable:
          contextVariable = new ContextVariable.readContents(reader, startPC);
          break;
        default:
          throw 'Unexpected entry kind ${kind}';
      }
    }
  }

  Map<int, String> getBytecodeAnnotations() {
    final map = <int, String>{};
    for (var entry in getEntries()) {
      final pc = entry.startPC;
      if (map[pc] == null) {
        map[pc] = entry.toString();
      } else {
        map[pc] = "${map[pc]}; $entry";
      }
    }
    return map;
  }
}
