00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016 #include "../sexpress/sexpress.hpp"
00017 #include "../sexpress/slocatn.hpp"
00018 #include "lispform.hpp"
00019 #include "conteval.hpp"
00020
00021 static const int initial_result_stack_size = 1024;
00022 static const int initial_task_stack_size = 1024;
00023
00025
00026 IntelibTypeId SExpressionSetfAgent::TypeId(&SExpression::TypeId, false);
00027
00029
00030 IntelibContinuation::IntelibContinuation()
00031 {
00032 result_stack_size = initial_result_stack_size;
00033 result_stack_pointer = 0;
00034 result_stack = new SReference[result_stack_size];
00035
00036 todo_stack_size = initial_task_stack_size;
00037 todo_stack_pointer = 0;
00038 todo_stack = new TodoItem[todo_stack_size];
00039 }
00040
00041 IntelibContinuation::
00042 IntelibContinuation(const IntelibContinuation &other, bool ignored)
00043 {
00044
00045 result_stack_size = other.result_stack_pointer+1;
00046 result_stack_pointer = other.result_stack_pointer;
00047 result_stack = new SReference[result_stack_size];
00048
00049
00050 todo_stack_size = other.todo_stack_pointer+1;
00051 todo_stack_pointer = other.todo_stack_pointer;
00052 todo_stack = new TodoItem[todo_stack_size];
00053
00054 int i;
00055 for(i=0; i<other.result_stack_pointer; i++)
00056 result_stack[i] = other.result_stack[i];
00057 for(i=0; i<other.todo_stack_pointer; i++)
00058 todo_stack[i] = other.todo_stack[i];
00059
00060 current_context = other.current_context;
00061 }
00062
00063 IntelibContinuation::~IntelibContinuation()
00064 {
00065 delete[] result_stack;
00066 delete[] todo_stack;
00067 }
00068
00069 void IntelibContinuation::
00070 ReplaceContinuation(const IntelibContinuation &other)
00071 {
00072 delete[] result_stack;
00073 delete[] todo_stack;
00074
00075 int i;
00076
00077 result_stack_size = initial_result_stack_size;
00078 while(result_stack_size <= other.result_stack_pointer)
00079 result_stack_size *= 2;
00080 result_stack_pointer = other.result_stack_pointer;
00081 result_stack = new SReference[result_stack_size];
00082 for(i=0; i<other.result_stack_pointer; i++)
00083 result_stack[i] = other.result_stack[i];
00084
00085 todo_stack_size = initial_task_stack_size;
00086 while(todo_stack_size <= other.todo_stack_pointer)
00087 todo_stack_size *= 2;
00088 todo_stack_pointer = other.todo_stack_pointer;
00089 todo_stack = new TodoItem[todo_stack_size];
00090 for(i=0; i<other.todo_stack_pointer; i++)
00091 todo_stack[i] = other.todo_stack[i];
00092
00093 current_context = other.current_context;
00094 }
00095
00096 SReference IntelibContinuation::Get()
00097 {
00098 if(result_stack_pointer < 1) {
00099 SReference unbound;
00100 return unbound;
00101 }
00102 return result_stack[(result_stack_pointer--) - 1];
00103 }
00104
00105 bool IntelibContinuation::Step()
00106 {
00107 if(pending_interruption && !interruptions_suspended) {
00108 pending_interruption = false;
00109 throw Interruption();
00110 }
00111 int opcode;
00112 SReference param;
00113 #if INTELIB_CONTINUATION_KEEPS_STACK_INFO == 1
00114 SReference save_stack_info =
00115 todo_stack_pointer > 0 ?
00116 todo_stack[todo_stack_pointer-1].stack_info : SReference();
00117 #endif
00118 if(!PopTodo(opcode, param)) return false;
00119 try {
00120 if(opcode >= 0) {
00121 FunctionCall(opcode);
00122 } else
00123 switch(opcode) {
00124 case just_evaluate:
00125 JustEvaluate(param);
00126 break;
00127 case evaluate_prepared:
00128 EvaluatePrepared(param);
00129 break;
00130 case evaluate_progn:
00131 PlacePrognToStack(param);
00132 break;
00133 case quote_parameter:
00134 PushResult(param);
00135 break;
00136 case drop_result: {
00137 SReference r;
00138 PopResult(r);
00139 break;
00140 }
00141 case return_unspecified:
00142 ReturnUnspecified();
00143 break;
00144 case end_of_clauses:
00145
00146 break;
00147 case cond_clause:
00148 EvaluateCondClause(param);
00149 break;
00150 case bail_on_false:
00151 BailOnFalse();
00152 break;
00153 case set_context:
00154 current_context = param;
00155 break;
00156 case assign_to: {
00157 SReference r;
00158 PopResult(r);
00159 static_cast<SExpressionLocation*>(param.GetPtr())->Assign(r);
00160 break;
00161 }
00162 case assign_location:
00163 AssignLocation();
00164 break;
00165 case generic_iteration:
00166 GenericIteration(param);
00167 break;
00168 case iteration_callback:
00169 IterationCallback(param);
00170 break;
00171 default:
00172 CustomCommand(opcode, param);
00173 }
00174 }
00175 catch(IntelibX &ex) {
00176 SReference reslist = *PTheEmptyList;
00177 for(int k = 0; k < result_stack_pointer; k++)
00178 reslist, result_stack[k];
00179 SListConstructor L;
00180 ex.AddStack((L|reslist, opcode,
00181 param.GetPtr() ? param : *PTheEmptyList));
00182 #if INTELIB_CONTINUATION_KEEPS_STACK_INFO == 1
00183 if(save_stack_info.GetPtr())
00184 ex.AddStack(save_stack_info);
00185 for(int i = todo_stack_pointer - 1; i>=0; i--)
00186 if(todo_stack[i].stack_info.GetPtr())
00187 ex.AddStack(todo_stack[i].stack_info);
00188 #endif
00189 throw ex;
00190 }
00191 return true;
00192 }
00193
00194 void IntelibContinuation::CustomCommand(int opcode, const SReference& param)
00195 {
00196 throw IntelibX_continuation_unknown_operation(opcode);
00197 }
00198
00199 void IntelibContinuation::PushTodo(int opcode, const SReference& param)
00200 {
00201
00202
00203
00204
00205
00206 if(opcode == set_context) {
00207 if(todo_stack_pointer > 0 &&
00208 todo_stack[todo_stack_pointer - 1].opcode == set_context)
00209 {
00210 return;
00211 }
00212 }
00213
00214 if(todo_stack_pointer >= todo_stack_size) {
00215
00216 TodoItem *np = new TodoItem[todo_stack_size*2];
00217 for(int i = 0; i<todo_stack_pointer; i++)
00218 np[i] = todo_stack[i];
00219 delete[] todo_stack;
00220 todo_stack = np;
00221 todo_stack_size *= 2;
00222 }
00223 TodoItem *p = todo_stack + todo_stack_pointer;
00224 p->opcode = opcode;
00225 p->param = param;
00226 todo_stack_pointer++;
00227 }
00228
00229 void IntelibContinuation::PushTodo(int opcode)
00230 {
00231 SReference unbound;
00232 PushTodo(opcode, unbound);
00233 }
00234
00235 bool IntelibContinuation::PopTodo(int &opcode, SReference& param)
00236 {
00237 if(todo_stack_pointer <= 0) return false;
00238 todo_stack_pointer--;
00239 TodoItem *p = todo_stack + todo_stack_pointer;
00240 opcode = p->opcode;
00241 param = p->param;
00242 p->param = SReference();
00243 #if INTELIB_COINTINUATION_KEEPS_STACK_INFO == 1
00244 p->stack_info = SReference();
00245 #endif
00246 return true;
00247 }
00248
00249 void IntelibContinuation::PushResult(const SReference& r)
00250 {
00251 if(result_stack_pointer >= result_stack_size) {
00252
00253 SReference *np = new SReference[result_stack_size*2];
00254 for(int i = 0; i<result_stack_pointer; i++)
00255 np[i] = result_stack[i];
00256 delete[] result_stack;
00257 result_stack = np;
00258 result_stack_size *= 2;
00259 }
00260 result_stack[result_stack_pointer] = r;
00261 result_stack_pointer++;
00262 }
00263
00264 bool IntelibContinuation::PopResult(SReference& r)
00265 {
00266 if(result_stack_pointer <= 0) return false;
00267 result_stack_pointer--;
00268 r = result_stack[result_stack_pointer];
00269 result_stack[result_stack_pointer] = SReference();
00270 return true;
00271 }
00272
00273 void IntelibContinuation::RegularReturn(const SReference &ref)
00274 {
00275 PushResult(ref);
00276 }
00277
00278 bool IntelibContinuation::AcceptsLocation() const
00279 {
00280 return
00281 todo_stack_pointer > 0 &&
00282 (
00283 todo_stack[todo_stack_pointer-1].opcode == assign_location ||
00284 todo_stack[todo_stack_pointer-1].opcode == set_context &&
00285 todo_stack_pointer > 1 &&
00286 todo_stack[todo_stack_pointer-2].opcode == assign_location
00287 );
00288 }
00289
00290 void IntelibContinuation::ReferenceReturn(SReference &ref,
00291 const SReference &superstruct)
00292 {
00293 if(AcceptsLocation()) {
00294 PushResult(SReference(new SExpressionLocation(superstruct, &ref)));
00295 } else {
00296 PushResult(ref);
00297 }
00298 }
00299
00300 void IntelibContinuation::AgentReturn(const SReference &val,
00301 const SExpressionSetfAgent *agent)
00302 {
00303 if(AcceptsLocation()) {
00304 PushResult(agent);
00305 } else {
00306 PushResult(val);
00307 }
00308 }
00309
00310 void IntelibContinuation::TailReturn(const SReference &ref)
00311 {
00312 PushTodo(just_evaluate, ref);
00313 }
00314
00315 void IntelibContinuation::ReturnUnspecified()
00316 {
00317 static SLabel unspecified("#<unspecified>");
00318 RegularReturn(unspecified);
00319 }
00320
00321 void IntelibContinuation::EvaluatePrepared(const SReference& expr)
00322 {
00323 int len = 0;
00324 const SReference *t = &expr;
00325 do {
00326 PushResult(t->Car());
00327 t = &(t->Cdr());
00328 len++;
00329 } while(!t->IsEmptyList());
00330 FunctionCall(len-1);
00331 }
00332
00333 void IntelibContinuation::FunctionCall(int paramscount)
00334 {
00335
00336
00337 int fun_pos = result_stack_pointer - 1 - paramscount;
00338 if(fun_pos < 0) throw IntelibX_bug();
00339 SReference save_fun = result_stack[fun_pos];
00340 result_stack_pointer = fun_pos;
00341
00342 #if 1
00343 DoFunctionCall(save_fun, paramscount, result_stack+fun_pos+1);
00344 #else
00345 SchExpressionFunction *fun =
00346 save_fun.DynamicCastGetPtr<SchExpressionFunction>();
00347 if(!fun) {
00348 throw IntelibX_not_a_function(save_fun);
00349 }
00350 fun->Apply(paramscount, result_stack+fun_pos+1, *this);
00351 #endif
00352 }
00353
00354
00355 void IntelibContinuation::EvaluateCondClause(const SReference& expr)
00356 {
00357
00358
00359
00360
00361
00362
00363
00364 SReference pres;
00365 PopResult(pres);
00366 if(IsTrue(pres)) {
00367 int op;
00368 SReference parm;
00369 while(PopTodo(op, parm) && op != end_of_clauses) {}
00370 if(expr.IsEmptyList()) {
00371 PushResult(pres);
00372 } else {
00373 PlacePrognToStack(expr);
00374 }
00375 }
00376 }
00377
00378 void IntelibContinuation::BailOnFalse()
00379 {
00380
00381
00382
00383
00384
00385
00386
00387 SReference pres;
00388 PopResult(pres);
00389 if(!IsTrue(pres)) {
00390 int op;
00391 SReference parm;
00392 while(PopTodo(op, parm) && op != end_of_clauses) {}
00393 PushResult(pres);
00394 }
00395 }
00396
00397 void IntelibContinuation::AssignLocation()
00398 {
00399
00400 SReference loc;
00401 PopResult(loc);
00402 SReference val;
00403 PopResult(val);
00404 SExpressionLocation *lc = loc.SimpleCastGetPtr<SExpressionLocation>();
00405 if(!lc) {
00406 SExpressionSetfAgent *ag =
00407 loc.DynamicCastGetPtr<SExpressionSetfAgent>();
00408 if(ag) {
00409 ag->Setf(val);
00410 return;
00411 }
00412 throw IntelibX_not_a_location(loc);
00413 }
00414 lc->Assign(val);
00415 }
00416
00417 void IntelibContinuation::GenericIteration(const SReference ¶m)
00418 {
00419 SExpressionGenericIterator *iter =
00420 static_cast<SExpressionGenericIterator*>(param.GetPtr());
00421 if(iter->NeedAnotherIteration(*this)) {
00422
00423 PushTodo(generic_iteration, param);
00424
00425 PushTodo(iteration_callback, param);
00426
00427 iter->ScheduleIteration(*this);
00428 } else {
00429
00430 iter->ReturnFinalValue(*this);
00431 }
00432 }
00433
00434 void IntelibContinuation::IterationCallback(const SReference ¶m)
00435 {
00436 SExpressionGenericIterator *iter =
00437 static_cast<SExpressionGenericIterator*>(param.GetPtr());
00438 iter->CollectResultOfIteration(*this);
00439 }
00440
00441 void IntelibContinuation::PlacePrognToStack(const SReference &rest)
00442 {
00443 if(rest.IsEmptyList()) return;
00444 SReference tail = rest.Cdr();
00445 if(!tail.IsEmptyList()) {
00446 PlacePrognToStack(tail);
00447 PushTodo(drop_result);
00448 }
00449 PushTodo(just_evaluate, rest.Car());
00450 }
00451
00452 void IntelibContinuation::PlaceFormToStack(const SExpressionCons *form,
00453 int len)
00454 {
00455 SExpressionCons *cdr =
00456 form->Cdr().DynamicCastGetPtr<SExpressionCons>();
00457 if(cdr) {
00458 PlaceFormToStack(cdr, len+1);
00459 } else {
00460
00461
00462
00463 PushTodo(len);
00464 }
00465 PushTodo(just_evaluate, form->Car());
00466 }
00467
00468 void IntelibContinuation::DoFunctionCall(const SReference &fun_ref,
00469 int paramscount,
00470 const SReference *paramsvector)
00471 {
00472 SExpressionFunction *fun =
00473 fun_ref.DynamicCastGetPtr<SExpressionFunction>();
00474 if(!fun) {
00475 throw IntelibX_not_a_function(fun_ref);
00476 }
00477 fun->Apply(paramscount, paramsvector, *this);
00478 }
00479
00480
00481 bool IntelibContinuation::pending_interruption = false;
00482 bool IntelibContinuation::interruptions_suspended = false;
00483
00484
00485
00486 IntelibX_continuation_unknown_operation::
00487 IntelibX_continuation_unknown_operation(SReference a_param)
00488 : IntelibX("continuation: unknown operation code", a_param) {}
00489
00490 IntelibX_not_a_function::
00491 IntelibX_not_a_function(SReference a_param)
00492 : IntelibX("not a function", a_param) {}
00493