diff interps/rail/src/ActivationRecord.cpp @ 996:859f9b4339e6

<Gregor> tar xf egobot.tar.xz
author HackBot
date Sun, 09 Dec 2012 19:30:08 +0000
parents
children
line wrap: on
line diff
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/interps/rail/src/ActivationRecord.cpp	Sun Dec 09 19:30:08 2012 +0000
@@ -0,0 +1,231 @@
+// ActivationRecord.cpp
+
+#include "lib.h"
+#include "ActivationRecord.h"
+#include "Rail.h"
+#include "Error.h"
+#include "MultiLexer.h"
+#include "StringVar.h"
+#include "Action.h"
+
+using namespace std;
+
+ActivationRecord::ActivationRecord()
+  : function(NULL)
+  , direction(Dir::north)
+{
+}
+
+ActivationRecord::ActivationRecord(Board const & source)
+  : function(&source)
+  , position(0,0)
+  , direction(Dir::southeast)
+{
+}
+
+ActivationRecord::ActivationRecord(Closure const & source)
+  : environment(source.getEnvironment())
+  , function(&(source.getFunction()))
+  , position(source.getPosition())
+  , direction(source.getDirection())
+{
+}
+
+ActivationRecord::~ActivationRecord()
+{
+}
+
+ActivationRecord::ActivationRecord(ActivationRecord const & right)
+{
+  // This is exception-safe because the environment copy is the only
+  // thing that can fail.
+  environment = right.environment;
+  function = right.function;
+  position = right.position;
+  direction = right.direction;
+}
+
+ActivationRecord & ActivationRecord::operator=(ActivationRecord const & right)
+{
+  environment = right.environment;
+  function = right.function;
+  position = right.position;
+  direction = right.direction;
+  return *this;
+}
+
+void ActivationRecord::move(MultiLexer & multi)
+{
+  if (function == NULL)
+  {
+    throw InternalException("ActivationRecord::move(): No board");
+  }
+  if (multi.isDone())
+  {
+    throw InternalException("ActivationRecord::move(): Move requested when multi is already done");
+  }
+  else if (multi.isStarted())
+  {
+    position = position + Dir::dirToVec(direction);
+    if (position.x < function->getMinX() || position.x > function->getMaxX()
+      || position.y < function->getMinY() || position.y > function->getMaxY())
+    {
+      throw CrashException(Error::multiOutOfBounds);
+    }
+  }
+  else
+  {
+    normalMove();
+  }
+}
+
+void ActivationRecord::normalMove(void)
+{
+  Vec primPos = position + Dir::dirToVec(direction);
+  Vec leftPos = position + Dir::dirToVec(Dir::left(direction));
+  Vec rightPos = position + Dir::dirToVec(Dir::right(direction));
+
+  Rail::t sourceRail = Rail::charToRail(function->at(position));
+  Rail::t primRail = Rail::charToRail(function->at(primPos));
+  Rail::t leftRail = Rail::charToRail(function->at(leftPos));
+  Rail::t rightRail = Rail::charToRail(function->at(rightPos));
+
+  Rail::t resultRail = Rail::rubble;
+
+  if (Rail::isPrimary(sourceRail, primRail, direction))
+  {
+    position = primPos;
+    resultRail = primRail;
+  }
+  else
+  {
+    bool isLeft = Rail::isLeft(sourceRail, leftRail);
+    bool isRight = Rail::isRight(sourceRail, rightRail);
+    if (isLeft && !isRight)
+    {
+      position = leftPos;
+      resultRail = leftRail;
+    }
+    else if (!isLeft && isRight)
+    {
+      position = rightPos;
+      resultRail = rightRail;
+    }
+    else if (isLeft && isRight)
+    {
+      throw CrashException(Error::ambiguousMove);
+    }
+    else
+    {
+      // !isLeft && !isRight
+//      cerr << "orig:  '" << function->at(position) << "'" << endl;
+//      cerr << "left:  '" << function->at(leftPos) << "'" << endl;
+//      cerr << "prim:  '" << function->at(primPos) << "'" << endl;
+//      cerr << "right: '" << function->at(rightPos) << "'" << endl;
+      throw CrashException(Error::noValidMove);
+    }
+  }
+  direction = Rail::correctDirection(resultRail, direction);
+}
+
+Action & ActivationRecord::getAction(MultiLexer & multi,
+                                     list<Binding> & dataStack)
+{
+  if (function == NULL)
+  {
+    throw InternalException("ActivationRecord::act(): No board");
+  }
+  if (multi.isDone())
+  {
+    throw InternalException("ActivationRecord::getAction(): action requested when multi is already done");
+  }
+  else if (multi.isStarted())
+  {
+    multi.add(function->at(position));
+    if (multi.isFunction())
+    {
+      dataStack.push_front(Binding(new StringVar(multi.getToken())));
+      multi.reset();
+      return CallFunction::v;
+    }
+    else if (multi.isConstant())
+    {
+      dataStack.push_front(Binding(new StringVar(multi.getToken())));
+      multi.reset();
+      return PushConstant::v;
+    }
+    else if (multi.isUse())
+    {
+      dataStack.push_front(Binding(new StringVar(multi.getToken())));
+      multi.reset();
+      return UseVariable::v;
+    }
+    else if (multi.isBind())
+    {
+      dataStack.push_front(Binding(new StringVar(multi.getToken())));
+      multi.reset();
+      return BindVariable::v;
+    }
+    else
+    {
+      return Nop::v;
+    }
+  }
+  else
+  {
+    switch(function->at(position))
+    {
+    case '[':
+    case ']':
+    case '{':
+    case '}':
+    case '(':
+    case ')':
+      multi.add(function->at(position));
+      return Nop::v;
+    default:
+      Action * act = Action::charToAction(function->at(position));
+      if (act == NULL)
+      {
+        throw InternalException("ActivationRecord::act(): NULL action");
+      }
+      return *act;
+    }
+  }
+}
+
+std::map<std::string, Binding> const & ActivationRecord::getEnvironment(void)
+  const
+{
+  return environment;
+}
+
+void ActivationRecord::bindVariable(string name, Binding var)
+{
+  environment[name] = var;
+}
+
+Board const * ActivationRecord::getFunction(void) const
+{
+  return function;
+}
+
+Vec ActivationRecord::getPosition(void) const
+{
+  return position;
+}
+
+void ActivationRecord::setPosition(Vec newPosition)
+{
+  position = newPosition;
+}
+
+Dir::t ActivationRecord::getDirection(void) const
+{
+  return direction;
+}
+
+void ActivationRecord::setDirection(Dir::t newDirection)
+{
+  direction = newDirection;
+}