996
|
1 // ActivationRecord.cpp
|
|
2
|
|
3 #include "lib.h"
|
|
4 #include "ActivationRecord.h"
|
|
5 #include "Rail.h"
|
|
6 #include "Error.h"
|
|
7 #include "MultiLexer.h"
|
|
8 #include "StringVar.h"
|
|
9 #include "Action.h"
|
|
10
|
|
11 using namespace std;
|
|
12
|
|
13 ActivationRecord::ActivationRecord()
|
|
14 : function(NULL)
|
|
15 , direction(Dir::north)
|
|
16 {
|
|
17 }
|
|
18
|
|
19 ActivationRecord::ActivationRecord(Board const & source)
|
|
20 : function(&source)
|
|
21 , position(0,0)
|
|
22 , direction(Dir::southeast)
|
|
23 {
|
|
24 }
|
|
25
|
|
26 ActivationRecord::ActivationRecord(Closure const & source)
|
|
27 : environment(source.getEnvironment())
|
|
28 , function(&(source.getFunction()))
|
|
29 , position(source.getPosition())
|
|
30 , direction(source.getDirection())
|
|
31 {
|
|
32 }
|
|
33
|
|
34 ActivationRecord::~ActivationRecord()
|
|
35 {
|
|
36 }
|
|
37
|
|
38 ActivationRecord::ActivationRecord(ActivationRecord const & right)
|
|
39 {
|
|
40 // This is exception-safe because the environment copy is the only
|
|
41 // thing that can fail.
|
|
42 environment = right.environment;
|
|
43 function = right.function;
|
|
44 position = right.position;
|
|
45 direction = right.direction;
|
|
46 }
|
|
47
|
|
48 ActivationRecord & ActivationRecord::operator=(ActivationRecord const & right)
|
|
49 {
|
|
50 environment = right.environment;
|
|
51 function = right.function;
|
|
52 position = right.position;
|
|
53 direction = right.direction;
|
|
54 return *this;
|
|
55 }
|
|
56
|
|
57 void ActivationRecord::move(MultiLexer & multi)
|
|
58 {
|
|
59 if (function == NULL)
|
|
60 {
|
|
61 throw InternalException("ActivationRecord::move(): No board");
|
|
62 }
|
|
63 if (multi.isDone())
|
|
64 {
|
|
65 throw InternalException("ActivationRecord::move(): Move requested when multi is already done");
|
|
66 }
|
|
67 else if (multi.isStarted())
|
|
68 {
|
|
69 position = position + Dir::dirToVec(direction);
|
|
70 if (position.x < function->getMinX() || position.x > function->getMaxX()
|
|
71 || position.y < function->getMinY() || position.y > function->getMaxY())
|
|
72 {
|
|
73 throw CrashException(Error::multiOutOfBounds);
|
|
74 }
|
|
75 }
|
|
76 else
|
|
77 {
|
|
78 normalMove();
|
|
79 }
|
|
80 }
|
|
81
|
|
82 void ActivationRecord::normalMove(void)
|
|
83 {
|
|
84 Vec primPos = position + Dir::dirToVec(direction);
|
|
85 Vec leftPos = position + Dir::dirToVec(Dir::left(direction));
|
|
86 Vec rightPos = position + Dir::dirToVec(Dir::right(direction));
|
|
87
|
|
88 Rail::t sourceRail = Rail::charToRail(function->at(position));
|
|
89 Rail::t primRail = Rail::charToRail(function->at(primPos));
|
|
90 Rail::t leftRail = Rail::charToRail(function->at(leftPos));
|
|
91 Rail::t rightRail = Rail::charToRail(function->at(rightPos));
|
|
92
|
|
93 Rail::t resultRail = Rail::rubble;
|
|
94
|
|
95 if (Rail::isPrimary(sourceRail, primRail, direction))
|
|
96 {
|
|
97 position = primPos;
|
|
98 resultRail = primRail;
|
|
99 }
|
|
100 else
|
|
101 {
|
|
102 bool isLeft = Rail::isLeft(sourceRail, leftRail);
|
|
103 bool isRight = Rail::isRight(sourceRail, rightRail);
|
|
104 if (isLeft && !isRight)
|
|
105 {
|
|
106 position = leftPos;
|
|
107 resultRail = leftRail;
|
|
108 }
|
|
109 else if (!isLeft && isRight)
|
|
110 {
|
|
111 position = rightPos;
|
|
112 resultRail = rightRail;
|
|
113 }
|
|
114 else if (isLeft && isRight)
|
|
115 {
|
|
116 throw CrashException(Error::ambiguousMove);
|
|
117 }
|
|
118 else
|
|
119 {
|
|
120 // !isLeft && !isRight
|
|
121 // cerr << "orig: '" << function->at(position) << "'" << endl;
|
|
122 // cerr << "left: '" << function->at(leftPos) << "'" << endl;
|
|
123 // cerr << "prim: '" << function->at(primPos) << "'" << endl;
|
|
124 // cerr << "right: '" << function->at(rightPos) << "'" << endl;
|
|
125 throw CrashException(Error::noValidMove);
|
|
126 }
|
|
127 }
|
|
128 direction = Rail::correctDirection(resultRail, direction);
|
|
129 }
|
|
130
|
|
131 Action & ActivationRecord::getAction(MultiLexer & multi,
|
|
132 list<Binding> & dataStack)
|
|
133 {
|
|
134 if (function == NULL)
|
|
135 {
|
|
136 throw InternalException("ActivationRecord::act(): No board");
|
|
137 }
|
|
138 if (multi.isDone())
|
|
139 {
|
|
140 throw InternalException("ActivationRecord::getAction(): action requested when multi is already done");
|
|
141 }
|
|
142 else if (multi.isStarted())
|
|
143 {
|
|
144 multi.add(function->at(position));
|
|
145 if (multi.isFunction())
|
|
146 {
|
|
147 dataStack.push_front(Binding(new StringVar(multi.getToken())));
|
|
148 multi.reset();
|
|
149 return CallFunction::v;
|
|
150 }
|
|
151 else if (multi.isConstant())
|
|
152 {
|
|
153 dataStack.push_front(Binding(new StringVar(multi.getToken())));
|
|
154 multi.reset();
|
|
155 return PushConstant::v;
|
|
156 }
|
|
157 else if (multi.isUse())
|
|
158 {
|
|
159 dataStack.push_front(Binding(new StringVar(multi.getToken())));
|
|
160 multi.reset();
|
|
161 return UseVariable::v;
|
|
162 }
|
|
163 else if (multi.isBind())
|
|
164 {
|
|
165 dataStack.push_front(Binding(new StringVar(multi.getToken())));
|
|
166 multi.reset();
|
|
167 return BindVariable::v;
|
|
168 }
|
|
169 else
|
|
170 {
|
|
171 return Nop::v;
|
|
172 }
|
|
173 }
|
|
174 else
|
|
175 {
|
|
176 switch(function->at(position))
|
|
177 {
|
|
178 case '[':
|
|
179 case ']':
|
|
180 case '{':
|
|
181 case '}':
|
|
182 case '(':
|
|
183 case ')':
|
|
184 multi.add(function->at(position));
|
|
185 return Nop::v;
|
|
186 default:
|
|
187 Action * act = Action::charToAction(function->at(position));
|
|
188 if (act == NULL)
|
|
189 {
|
|
190 throw InternalException("ActivationRecord::act(): NULL action");
|
|
191 }
|
|
192 return *act;
|
|
193 }
|
|
194 }
|
|
195 }
|
|
196
|
|
197 std::map<std::string, Binding> const & ActivationRecord::getEnvironment(void)
|
|
198 const
|
|
199 {
|
|
200 return environment;
|
|
201 }
|
|
202
|
|
203 void ActivationRecord::bindVariable(string name, Binding var)
|
|
204 {
|
|
205 environment[name] = var;
|
|
206 }
|
|
207
|
|
208 Board const * ActivationRecord::getFunction(void) const
|
|
209 {
|
|
210 return function;
|
|
211 }
|
|
212
|
|
213 Vec ActivationRecord::getPosition(void) const
|
|
214 {
|
|
215 return position;
|
|
216 }
|
|
217
|
|
218 void ActivationRecord::setPosition(Vec newPosition)
|
|
219 {
|
|
220 position = newPosition;
|
|
221 }
|
|
222
|
|
223 Dir::t ActivationRecord::getDirection(void) const
|
|
224 {
|
|
225 return direction;
|
|
226 }
|
|
227
|
|
228 void ActivationRecord::setDirection(Dir::t newDirection)
|
|
229 {
|
|
230 direction = newDirection;
|
|
231 }
|