//===- Tree.cpp -----------------------------------------------*- C++ -*-=====//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
#include "clang/Tooling/Syntax/Tree.h"
#include "clang/Basic/TokenKinds.h"
#include "clang/Tooling/Syntax/Nodes.h"
#include "llvm/ADT/BitVector.h"
#include "llvm/Support/raw_ostream.h"
#include <cassert>

using namespace clang;

namespace {
static void traverse(const syntax::Node *N,
                     llvm::function_ref<void(const syntax::Node *)> Visit) {
  if (auto *T = dyn_cast<syntax::Tree>(N)) {
    for (const syntax::Node &C : T->getChildren())
      traverse(&C, Visit);
  }
  Visit(N);
}
static void traverse(syntax::Node *N,
                     llvm::function_ref<void(syntax::Node *)> Visit) {
  traverse(static_cast<const syntax::Node *>(N), [&](const syntax::Node *N) {
    Visit(const_cast<syntax::Node *>(N));
  });
}
} // namespace

syntax::Leaf::Leaf(syntax::TokenManager::Key K) : Node(NodeKind::Leaf), K(K) {}

syntax::Node::Node(NodeKind Kind)
    : Parent(nullptr), NextSibling(nullptr), PreviousSibling(nullptr),
      Kind(static_cast<unsigned>(Kind)), Role(0), Original(false),
      CanModify(false) {
  this->setRole(NodeRole::Detached);
}

bool syntax::Node::isDetached() const {
  return getRole() == NodeRole::Detached;
}

void syntax::Node::setRole(NodeRole NR) {
  this->Role = static_cast<unsigned>(NR);
}

void syntax::Tree::appendChildLowLevel(Node *Child, NodeRole Role) {
  assert(Child->getRole() == NodeRole::Detached);
  assert(Role != NodeRole::Detached);

  Child->setRole(Role);
  appendChildLowLevel(Child);
}

void syntax::Tree::appendChildLowLevel(Node *Child) {
  assert(Child->Parent == nullptr);
  assert(Child->NextSibling == nullptr);
  assert(Child->PreviousSibling == nullptr);
  assert(Child->getRole() != NodeRole::Detached);

  Child->Parent = this;
  if (this->LastChild) {
    Child->PreviousSibling = this->LastChild;
    this->LastChild->NextSibling = Child;
  } else
    this->FirstChild = Child;

  this->LastChild = Child;
}

void syntax::Tree::prependChildLowLevel(Node *Child, NodeRole Role) {
  assert(Child->getRole() == NodeRole::Detached);
  assert(Role != NodeRole::Detached);

  Child->setRole(Role);
  prependChildLowLevel(Child);
}

void syntax::Tree::prependChildLowLevel(Node *Child) {
  assert(Child->Parent == nullptr);
  assert(Child->NextSibling == nullptr);
  assert(Child->PreviousSibling == nullptr);
  assert(Child->getRole() != NodeRole::Detached);

  Child->Parent = this;
  if (this->FirstChild) {
    Child->NextSibling = this->FirstChild;
    this->FirstChild->PreviousSibling = Child;
  } else
    this->LastChild = Child;

  this->FirstChild = Child;
}

void syntax::Tree::replaceChildRangeLowLevel(Node *Begin, Node *End,
                                             Node *New) {
  assert((!Begin || Begin->Parent == this) &&
         "`Begin` is not a child of `this`.");
  assert((!End || End->Parent == this) && "`End` is not a child of `this`.");
  assert(canModify() && "Cannot modify `this`.");

#ifndef NDEBUG
  for (auto *N = New; N; N = N->NextSibling) {
    assert(N->Parent == nullptr);
    assert(N->getRole() != NodeRole::Detached && "Roles must be set");
    // FIXME: validate the role.
  }

  auto Reachable = [](Node *From, Node *N) {
    if (!N)
      return true;
    for (auto *It = From; It; It = It->NextSibling)
      if (It == N)
        return true;
    return false;
  };
  assert(Reachable(FirstChild, Begin) && "`Begin` is not reachable.");
  assert(Reachable(Begin, End) && "`End` is not after `Begin`.");
#endif

  if (!New && Begin == End)
    return;

  // Mark modification.
  for (auto *T = this; T && T->Original; T = T->Parent)
    T->Original = false;

  // Save the node before the range to be removed. Later we insert the `New`
  // range after this node.
  auto *BeforeBegin = Begin ? Begin->PreviousSibling : LastChild;

  // Detach old nodes.
  for (auto *N = Begin; N != End;) {
    auto *Next = N->NextSibling;

    N->setRole(NodeRole::Detached);
    N->Parent = nullptr;
    N->NextSibling = nullptr;
    N->PreviousSibling = nullptr;
    if (N->Original)
      traverse(N, [](Node *C) { C->Original = false; });

    N = Next;
  }

  // Attach new range.
  auto *&NewFirst = BeforeBegin ? BeforeBegin->NextSibling : FirstChild;
  auto *&NewLast = End ? End->PreviousSibling : LastChild;

  if (!New) {
    NewFirst = End;
    NewLast = BeforeBegin;
    return;
  }

  New->PreviousSibling = BeforeBegin;
  NewFirst = New;

  Node *LastInNew;
  for (auto *N = New; N != nullptr; N = N->NextSibling) {
    LastInNew = N;
    N->Parent = this;
  }
  LastInNew->NextSibling = End;
  NewLast = LastInNew;
}

namespace {
static void dumpNode(raw_ostream &OS, const syntax::Node *N,
                     const syntax::TokenManager &TM, llvm::BitVector IndentMask) {
  auto DumpExtraInfo = [&OS](const syntax::Node *N) {
    if (N->getRole() != syntax::NodeRole::Unknown)
      OS << " " << N->getRole();
    if (!N->isOriginal())
      OS << " synthesized";
    if (!N->canModify())
      OS << " unmodifiable";
  };

  assert(N);
  if (const auto *L = dyn_cast<syntax::Leaf>(N)) {
    OS << "'";
    OS << TM.getText(L->getTokenKey());
    OS << "'";
    DumpExtraInfo(N);
    OS << "\n";
    return;
  }

  const auto *T = cast<syntax::Tree>(N);
  OS << T->getKind();
  DumpExtraInfo(N);
  OS << "\n";

  for (const syntax::Node &It : T->getChildren()) {
    for (unsigned Idx = 0; Idx < IndentMask.size(); ++Idx) {
      if (IndentMask[Idx])
        OS << "| ";
      else
        OS << "  ";
    }
    if (!It.getNextSibling()) {
      OS << "`-";
      IndentMask.push_back(false);
    } else {
      OS << "|-";
      IndentMask.push_back(true);
    }
    dumpNode(OS, &It, TM, IndentMask);
    IndentMask.pop_back();
  }
}
} // namespace

std::string syntax::Node::dump(const TokenManager &TM) const {
  std::string Str;
  llvm::raw_string_ostream OS(Str);
  dumpNode(OS, this, TM, /*IndentMask=*/{});
  return std::move(OS.str());
}

std::string syntax::Node::dumpTokens(const TokenManager &TM) const {
  std::string Storage;
  llvm::raw_string_ostream OS(Storage);
  traverse(this, [&](const syntax::Node *N) {
    if (const auto *L = dyn_cast<syntax::Leaf>(N)) {
      OS << TM.getText(L->getTokenKey());
      OS << " ";
    }
  });
  return Storage;
}

void syntax::Node::assertInvariants() const {
#ifndef NDEBUG
  if (isDetached())
    assert(getParent() == nullptr);
  else
    assert(getParent() != nullptr);

  const auto *T = dyn_cast<Tree>(this);
  if (!T)
    return;
  for (const Node &C : T->getChildren()) {
    if (T->isOriginal())
      assert(C.isOriginal());
    assert(!C.isDetached());
    assert(C.getParent() == T);
    const auto *Next = C.getNextSibling();
    assert(!Next || &C == Next->getPreviousSibling());
    if (!C.getNextSibling())
      assert(&C == T->getLastChild() &&
             "Last child is reachable by advancing from the first child.");
  }

  const auto *L = dyn_cast<List>(T);
  if (!L)
    return;
  for (const Node &C : T->getChildren()) {
    assert(C.getRole() == NodeRole::ListElement ||
           C.getRole() == NodeRole::ListDelimiter);
    if (C.getRole() == NodeRole::ListDelimiter) {
      assert(isa<Leaf>(C));
      // FIXME: re-enable it when there is way to retrieve token kind in Leaf.
      // assert(cast<Leaf>(C).getToken()->kind() == L->getDelimiterTokenKind());
    }
  }

#endif
}

void syntax::Node::assertInvariantsRecursive() const {
#ifndef NDEBUG
  traverse(this, [&](const syntax::Node *N) { N->assertInvariants(); });
#endif
}

const syntax::Leaf *syntax::Tree::findFirstLeaf() const {
  for (const Node &C : getChildren()) {
    if (const auto *L = dyn_cast<syntax::Leaf>(&C))
      return L;
    if (const auto *L = cast<syntax::Tree>(C).findFirstLeaf())
      return L;
  }
  return nullptr;
}

const syntax::Leaf *syntax::Tree::findLastLeaf() const {
  for (const auto *C = getLastChild(); C; C = C->getPreviousSibling()) {
    if (const auto *L = dyn_cast<syntax::Leaf>(C))
      return L;
    if (const auto *L = cast<syntax::Tree>(C)->findLastLeaf())
      return L;
  }
  return nullptr;
}

const syntax::Node *syntax::Tree::findChild(NodeRole R) const {
  for (const Node &C : getChildren()) {
    if (C.getRole() == R)
      return &C;
  }
  return nullptr;
}

std::vector<syntax::List::ElementAndDelimiter<syntax::Node>>
syntax::List::getElementsAsNodesAndDelimiters() {
  if (!getFirstChild())
    return {};

  std::vector<syntax::List::ElementAndDelimiter<Node>> Children;
  syntax::Node *ElementWithoutDelimiter = nullptr;
  for (Node &C : getChildren()) {
    switch (C.getRole()) {
    case syntax::NodeRole::ListElement: {
      if (ElementWithoutDelimiter) {
        Children.push_back({ElementWithoutDelimiter, nullptr});
      }
      ElementWithoutDelimiter = &C;
      break;
    }
    case syntax::NodeRole::ListDelimiter: {
      Children.push_back({ElementWithoutDelimiter, cast<syntax::Leaf>(&C)});
      ElementWithoutDelimiter = nullptr;
      break;
    }
    default:
      llvm_unreachable(
          "A list can have only elements and delimiters as children.");
    }
  }

  switch (getTerminationKind()) {
  case syntax::List::TerminationKind::Separated: {
    Children.push_back({ElementWithoutDelimiter, nullptr});
    break;
  }
  case syntax::List::TerminationKind::Terminated:
  case syntax::List::TerminationKind::MaybeTerminated: {
    if (ElementWithoutDelimiter) {
      Children.push_back({ElementWithoutDelimiter, nullptr});
    }
    break;
  }
  }

  return Children;
}

// Almost the same implementation of `getElementsAsNodesAndDelimiters` but
// ignoring delimiters
std::vector<syntax::Node *> syntax::List::getElementsAsNodes() {
  if (!getFirstChild())
    return {};

  std::vector<syntax::Node *> Children;
  syntax::Node *ElementWithoutDelimiter = nullptr;
  for (Node &C : getChildren()) {
    switch (C.getRole()) {
    case syntax::NodeRole::ListElement: {
      if (ElementWithoutDelimiter) {
        Children.push_back(ElementWithoutDelimiter);
      }
      ElementWithoutDelimiter = &C;
      break;
    }
    case syntax::NodeRole::ListDelimiter: {
      Children.push_back(ElementWithoutDelimiter);
      ElementWithoutDelimiter = nullptr;
      break;
    }
    default:
      llvm_unreachable("A list has only elements or delimiters.");
    }
  }

  switch (getTerminationKind()) {
  case syntax::List::TerminationKind::Separated: {
    Children.push_back(ElementWithoutDelimiter);
    break;
  }
  case syntax::List::TerminationKind::Terminated:
  case syntax::List::TerminationKind::MaybeTerminated: {
    if (ElementWithoutDelimiter) {
      Children.push_back(ElementWithoutDelimiter);
    }
    break;
  }
  }

  return Children;
}

clang::tok::TokenKind syntax::List::getDelimiterTokenKind() const {
  switch (this->getKind()) {
  case NodeKind::NestedNameSpecifier:
    return clang::tok::coloncolon;
  case NodeKind::CallArguments:
  case NodeKind::ParameterDeclarationList:
  case NodeKind::DeclaratorList:
    return clang::tok::comma;
  default:
    llvm_unreachable("This is not a subclass of List, thus "
                     "getDelimiterTokenKind() cannot be called");
  }
}

syntax::List::TerminationKind syntax::List::getTerminationKind() const {
  switch (this->getKind()) {
  case NodeKind::NestedNameSpecifier:
    return TerminationKind::Terminated;
  case NodeKind::CallArguments:
  case NodeKind::ParameterDeclarationList:
  case NodeKind::DeclaratorList:
    return TerminationKind::Separated;
  default:
    llvm_unreachable("This is not a subclass of List, thus "
                     "getTerminationKind() cannot be called");
  }
}

bool syntax::List::canBeEmpty() const {
  switch (this->getKind()) {
  case NodeKind::NestedNameSpecifier:
    return false;
  case NodeKind::CallArguments:
    return true;
  case NodeKind::ParameterDeclarationList:
    return true;
  case NodeKind::DeclaratorList:
    return true;
  default:
    llvm_unreachable("This is not a subclass of List, thus canBeEmpty() "
                     "cannot be called");
  }
}
