Main Page | Class Hierarchy | Alphabetical List | Class List | Directories | File List | Class Members | File Members

conteval.cpp

Go to the documentation of this file.
00001 // +-------------------------------------------------------------------------+
00002 // |               I__n__t__e__L__i__b           0.6.10 development          |
00003 // | Copyright (c) Andrey Vikt. Stolyarov <crocodil_AT_croco.net> 2000-2007. |
00004 // |                                                                         |
00005 // | This is free software. The library part is available under              |
00006 // |                               GNU LESSER GENERAL PUBLIC LICENSE v.2.1.  |
00007 // | GNU LGPL v2.1 is found in docs/gnu_gpl2.txt,  or at  http://www.gnu.org |
00008 // |     Please see also docs/readme.txt and visit http://www.intelib.org    |
00009 // |                                                                         |
00010 // | !!! THERE IS NO WARRANTY OF ANY KIND, NEITHER EXPRESSED NOR IMPLIED !!! |
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     //result_stack_size = other.result_stack_size;
00045     result_stack_size = other.result_stack_pointer+1; // that's enough
00046     result_stack_pointer = other.result_stack_pointer;
00047     result_stack = new SReference[result_stack_size];
00048 
00049     //todo_stack_size = other.todo_stack_size;
00050     todo_stack_size = other.todo_stack_pointer+1; // that's enough
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) { // this means function call
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                 // this is effectively just a no-op
00146                 break;
00147             case cond_clause:
00148                 EvaluateCondClause(param);
00149                 break;
00150             case bail_on_false:
00151                 BailOnFalse(); // param is ignored
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(); // param is ignored
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     // this hack works around the problem with wasting stack
00202     //     (specially in tail contexts) by the restore-context
00203     //     commands; two consequent set_context commands are
00204     //     senseless anyway, so if there's already one there,
00205     //     this won't let the second one go to the stack
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         // resize
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         // resize
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     // result_stack_pointer is the first FREE position, so
00336     // the function object should be at r_s_p - 1 - paramscount
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     // take the value on top of the result stack
00358     // if it is true, then
00359     //     remove all the stuff from the ToDo stack
00360     //     until the end_of_clauses mark, and then add the expr as
00361     //     progn to todo
00362     // otherwise,
00363     //     just do nothing    
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     // take the value on top of the result stack
00381     // if it is false, then
00382     //     remove all the stuff from the ToDo stack
00383     //     until the end_of_clauses mark, and then 
00384     //     return the result value back to stack
00385     // otherwise,
00386     //     just do nothing    
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     // first, take a location from stack, check if it is really a location
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 &param)
00418 {
00419     SExpressionGenericIterator *iter =
00420         static_cast<SExpressionGenericIterator*>(param.GetPtr()); 
00421     if(iter->NeedAnotherIteration(*this)) {
00422             // return it to the stack
00423         PushTodo(generic_iteration, param);
00424             // schedule the callback
00425         PushTodo(iteration_callback, param);
00426             // let the iteration plan execution of its body
00427         iter->ScheduleIteration(*this);
00428     } else {
00429             // no more iterations, just compute the final value
00430         iter->ReturnFinalValue(*this);
00431     }
00432 }
00433 
00434 void IntelibContinuation::IterationCallback(const SReference &param)
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         // we don't check the list for correctness, so
00461         // for dotted lists, the last element is just ignored.
00462         // may be this chould change once...
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 

Generated on Tue Dec 18 00:39:43 2007 for InteLib by  doxygen 1.4.1