Skip to content
Snippets Groups Projects
Action.cpp 9.46 KiB
Newer Older
#include "Action.hpp"

Action::Action(Action::Type type, std::function<void(Config & config, Action & action)> apply, std::function<void(Config & config, Action & action)> undo, std::function<bool(const Config & config, const Action & action)> appliable)
{
  this->type = type;
  this->apply = apply;
  this->undo = undo;
  this->appliable = appliable;
}

Action Action::addLinesIfNeeded(int nbLines)
{
  auto apply = [nbLines](Config & config, Action &)
  {
    config.addLines(1);
  };

  auto undo = [](Config &, Action &)
  {
  };

  auto appliable = [](const Config &, const Action &)
  {
    return true;
  };

  return {Type::AddLines, apply, undo, appliable};
}

Action Action::moveWordIndex(int movement)
{
  auto apply = [movement](Config & config, Action &)
  {
    config.moveWordIndex(movement);
  };

  auto undo = [movement](Config & config, Action &)
  {
    config.moveWordIndex(-movement);
  auto appliable = [movement](const Config & config, const Action &)
    return config.canMoveWordIndex(movement);
  };

  return {Type::MoveWord, apply, undo, appliable};
}

Action Action::moveCharacterIndex(int movement)
{
  auto apply = [movement](Config & config, Action &)
  {
    config.moveCharacterIndex(movement);
  };

  auto undo = [movement](Config & config, Action &)
  {
    config.moveCharacterIndex(-movement);
  auto appliable = [movement](const Config & config, const Action &)
    return config.canMoveCharacterIndex(movement);
  };

  return {Type::MoveChar, apply, undo, appliable};
}

Action Action::addHypothesis(const std::string & colName, std::size_t lineIndex, const std::string & hypothesis)
{
  auto apply = [colName, lineIndex, hypothesis](Config & config, Action &)
  {
    config.getFirstEmpty(colName, lineIndex) = hypothesis;
  };

  auto undo = [colName, lineIndex](Config & config, Action &)
  {
    config.getLastNotEmpty(colName, lineIndex) = "";
  };

  auto appliable = [colName, lineIndex](const Config & config, const Action &)
  {
    return config.has(colName, lineIndex, 0);
  };

  return {Type::Write, apply, undo, appliable}; 
}

Action Action::addHypothesisRelative(const std::string & colName, Object object, int relativeIndex, const std::string & hypothesis)
{
  auto apply = [colName, object, relativeIndex, hypothesis](Config & config, Action & a)
  {
    int lineIndex = 0;
    if (object == Object::Buffer)
      lineIndex = config.getWordIndex() + relativeIndex;
    else
      lineIndex = config.getStack(relativeIndex);

Franck Dary's avatar
Franck Dary committed
    return addHypothesis(colName, lineIndex, hypothesis).apply(config, a);
  };

  auto undo = [colName, object, relativeIndex](Config & config, Action & a)
  {
    int lineIndex = 0;
    if (object == Object::Buffer)
      lineIndex = config.getWordIndex() + relativeIndex;
    else
      lineIndex = config.getStack(relativeIndex);

    return addHypothesis(colName, lineIndex, "").undo(config, a);
  };

  auto appliable = [colName, object, relativeIndex](const Config & config, const Action & a)
  {
    int lineIndex = 0;
    if (object == Object::Buffer)
      lineIndex = config.getWordIndex() + relativeIndex;
    else if (config.hasStack(relativeIndex))
      lineIndex = config.getStack(relativeIndex);
    else
      return false;

    return addHypothesis(colName, lineIndex, "").appliable(config, a);
  };

  return {Type::Write, apply, undo, appliable}; 
}

Action Action::pushWordIndexOnStack()
{
  auto apply = [](Config & config, Action &)
  {
    config.addToStack(config.getWordIndex());
  };

  auto undo = [](Config & config, Action &)
  {
    config.popStack();
  };

  auto appliable = [](const Config & config, const Action &)
    if (config.hasStack(0) and config.getStack(0) == config.getWordIndex())
      return false;

    return (int)config.getWordIndex() != config.getLastPoppedStack();
  };

  return {Type::Push, apply, undo, appliable}; 
}

Action Action::popStack()
{
  auto apply = [](Config & config, Action & a)
  {
    auto toSave = config.getStack(0);
    a.data.push_back(std::to_string(toSave));
    config.popStack();
  };

  auto undo = [](Config & config, Action & a)
  {
    config.addToStack(std::stoi(a.data.back()));
  };

  auto appliable = [](const Config & config, const Action &)
  {
    return config.hasStack(0);
  };

  return {Type::Pop, apply, undo, appliable}; 
}

Franck Dary's avatar
Franck Dary committed
Action Action::emptyStack()
{
  auto apply = [](Config & config, Action & a)
  {
    while (config.hasStack(0))
    {
      a.data.push_back(std::to_string(config.getStack(0)));
      config.popStack();
    }
  };

  auto undo = [](Config & config, Action & a)
  {
    while (a.data.size())
    {
      config.addToStack(std::stoi(a.data.back()));
      a.data.pop_back();
    }
  };

  auto appliable = [](const Config & config, const Action &)
  {
    return true;
  };

  return {Type::Pop, apply, undo, appliable}; 
}

Action Action::setRoot()
{
  auto apply = [](Config & config, Action & a)
  {
    int rootIndex = -1;

    for (int i = config.getStack(0); true; --i)
Franck Dary's avatar
Franck Dary committed
    {
      if (!config.has(0, i, 0))
      {
        if (i < 0)
          break;
        util::myThrow("The current sentence is too long to be completly held by the data strucure. Consider increasing SubConfig::SpanSize");
      }
      if (!config.isToken(i))
        continue;

      if (config.getLastNotEmptyHypConst(Config::EOSColName, i) == Config::EOSSymbol1)
        break;

      if (util::isEmpty(config.getLastNotEmptyHypConst(Config::headColName, i)))
      {
        rootIndex = i;
        a.data.push_back(std::to_string(i));
      }
    }

    for (int i = config.getStack(0); true; --i)
Franck Dary's avatar
Franck Dary committed
    {
      if (!config.has(0, i, 0))
      {
        if (i < 0)
          break;
        util::myThrow("The current sentence is too long to be completly held by the data strucure. Consider increasing SubConfig::SpanSize");
      }
      if (!config.isToken(i))
        continue;

      if (config.getLastNotEmptyHypConst(Config::EOSColName, i) == Config::EOSSymbol1)
        break;

      if (util::isEmpty(config.getLastNotEmptyHypConst(Config::headColName, i)))
Franck Dary's avatar
Franck Dary committed
      {
        if (i == rootIndex)
        {
          config.getFirstEmpty(Config::headColName, i) = "0";
          config.getFirstEmpty(Config::deprelColName, i) = "root";
        }
        else
        {
          config.getFirstEmpty(Config::headColName, i) = std::to_string(rootIndex);
Franck Dary's avatar
Franck Dary committed
        }
      }
    }

  };

  auto undo = [](Config & config, Action & a)
  {
    while (a.data.size())
    {
      config.getLastNotEmptyHyp(Config::headColName, std::stoi(a.data.back())) = "";
      a.data.pop_back();
    }
  };

  auto appliable = [](const Config & config, const Action &)
  {
    return config.hasStack(0);
  };

  return {Type::Write, apply, undo, appliable}; 
}

Action Action::updateIds()
{
  auto apply = [](Config & config, Action & a)
  {
    int firstIndexOfSentence = -1;
    for (int i = config.getStack(0); true; --i)
    {
      if (!config.has(0, i, 0))
      {
        if (i < 0)
          break;
        util::myThrow("The current sentence is too long to be completly held by the data strucure. Consider increasing SubConfig::SpanSize");
      }
      if (!config.isToken(i))
        continue;

      if (config.getLastNotEmptyHypConst(Config::EOSColName, i) == Config::EOSSymbol1)
        break;

      firstIndexOfSentence = i;
    }

    if (firstIndexOfSentence < 0)
      util::myThrow("could not find any token in current sentence");

    for (unsigned int i = firstIndexOfSentence, currentId = 1; i <= config.getStack(0); ++i)
    {
      if (!config.isToken(i))
        continue;

      if (config.getLastNotEmptyHypConst(Config::EOSColName, i) == Config::EOSSymbol1)
        break;

      config.getFirstEmpty(Config::idColName, i) = fmt::format("{}", currentId);
      ++currentId;
    }
  };

  auto undo = [](Config & config, Action & a)
  {
    // TODO : undo this
  };

  auto appliable = [](const Config &, const Action &)
  {
    return true;
  };

  return {Type::Write, apply, undo, appliable}; 
}

Action Action::attach(Object governorObject, int governorIndex, Object dependentObject, int dependentIndex)
{
  auto apply = [governorObject, governorIndex, dependentObject, dependentIndex](Config & config, Action & a)
  {
    int lineIndex = 0;
    if (governorObject == Object::Buffer)
      lineIndex = config.getWordIndex() + governorIndex;
    else
      lineIndex = config.getStack(governorIndex);
    addHypothesisRelative(Config::headColName, dependentObject, dependentIndex, std::to_string(lineIndex)).apply(config, a);
  };

  auto undo = [governorObject, governorIndex, dependentObject, dependentIndex](Config & config, Action & a)
  {
    addHypothesisRelative(Config::headColName, dependentObject, dependentIndex, "").undo(config, a);
  };

  auto appliable = [governorObject, governorIndex, dependentObject, dependentIndex](const Config & config, const Action & action)
  {
    int govLineIndex = 0;
    if (governorObject == Object::Buffer)
    {
      govLineIndex = config.getWordIndex() + governorIndex;
      if (!config.has(0, govLineIndex, 0))
        return false;
    }
    else
    {
      if (!config.hasStack(governorIndex))
        return false;
      govLineIndex = config.getStack(governorIndex);
    }

    return addHypothesisRelative(Config::headColName, dependentObject, dependentIndex, std::to_string(govLineIndex)).appliable(config, action);
  };

  return {Type::Write, apply, undo, appliable}; 
}

Action::Object Action::str2object(const std::string & s)
{
  if (s == "b")
    return Object::Buffer;
  if (s == "s")
    return Object::Stack;

  util::myThrow(fmt::format("Invalid object '{}'", s));
  return Object::Buffer;
}