// ---------------------------------------------------------------------------
// - While.cpp -
// - afnix engine - builtin do/while loop functions implementation -
// ---------------------------------------------------------------------------
// - This program is free software; you can redistribute it and/or modify -
// - it provided that this copyright notice is kept intact. -
// - -
// - This program is distributed in the hope that it will be useful, but -
// - without any warranty; without even the implied warranty of -
// - merchantability or fitness for a particular purpose. In no event shall -
// - the copyright holder be liable for any direct, indirect, incidental or -
// - special damages arising in any way out of the use of this software. -
// ---------------------------------------------------------------------------
// - copyright (c) 1999-2007 amaury darsch -
// ---------------------------------------------------------------------------
#include "Cons.hpp"
#include "Builtin.hpp"
#include "Boolean.hpp"
#include "Runnable.hpp"
#include "Globalset.hpp"
#include "Exception.hpp"
namespace afnix {
// this procedure evaluate an object and check that we have a boolean. It
// returns the boolean value
static inline bool check_cond (Runnable* robj, Nameset* nset, Object* obj) {
bool result = false;
Object* object = (obj == nilp) ? nilp : obj->eval (robj, nset);
Boolean* bval = dynamic_cast <Boolean*> (object);
if (bval == nilp)
throw Exception ("type-error", "illegal object in loop condition",
Object::repr (object));
result = bval->toboolean ();
Object::cref (bval);
return result;
}
// run the while loop
Object* builtin_while (Runnable* robj, Nameset* nset, Cons* args) {
// check for nil
if (args == nilp) return nilp;
// extract argument count and check
long argc = args->length ();
if (argc > 3)
throw Exception ("argument-error",
"missing or too many arguments with while loop");
// the simple case is with 2 arguments
if (argc == 2) {
// extract condition and form
Object* cond = args->getcar ();
Object* form = args->getcadr ();
// loop until false condition
Object* result = nilp;
while (check_cond (robj, nset, cond) == true) {
Object::dref (result);
result = (form == nilp) ? nilp : form->eval (robj, nset);
Object::iref (result);
}
robj->post (result);
Object::tref (result);
return result;
}
// here we have 3 arguments - this indicates the existence of a
// starting condition that is executed only once
Object* sobj = args->getcar ();
Object* cond = args->getcadr ();
Object* form = args->getcaddr ();
// create a new nameset and link it with parent
Nameset* lset = new Globalset (nset);
try {
// call the initial condition
if (sobj != nilp) Object::cref (sobj->eval (robj, lset));
// loop until false condition
Object* result = nilp;
while (check_cond (robj, lset, cond) == true) {
Object::dref (result);
result = (form == nilp) ? nilp : form->eval (robj, lset);
Object::iref (result);
}
lset->reset ();
delete lset;
robj->post (result);
Object::tref (result);
return result;
} catch (...) {
lset->reset ();
delete lset;
throw;
}
}
// run the do loop
Object* builtin_do (Runnable* robj, Nameset* nset, Cons* args) {
// check for nil
if (args == nilp) return nilp;
// extract argument count and check
long argc = args->length ();
if (argc > 3)
throw Exception ("argument-error",
"missing or too many arguments with while loop");
// the simple case is with 2 arguments
if (argc == 2) {
// extract form and condition
Object* form = args->getcar ();
Object* cond = args->getcadr ();
// loop until false condition
Object* result = nilp;
do {
Object::dref (result);
result = (form == nilp) ? nilp : form->eval (robj, nset);
Object::iref (result);
} while (check_cond (robj, nset, cond) == true);
robj->post (result);
Object::tref (result);
return result;
}
// here we have 3 arguments - this indicates the existence of a
// starting condition that is executed only once
Object* sobj = args->getcar ();
Object* form = args->getcadr ();
Object* cond = args->getcaddr ();
// create a new nameset and link it with parent
Nameset* lset = new Globalset (nset);
try {
// call the initial condition
if (sobj != nilp) Object::cref (sobj->eval (robj, lset));
// loop until false condition
Object* result = nilp;
do {
Object::dref (result);
result = (form == nilp) ? nilp : form->eval (robj, nset);
Object::iref (result);
} while (check_cond (robj, nset, cond) == true);
lset->reset ();
delete lset;
robj->post (result);
Object::tref (result);
return result;
} catch (...) {
lset->reset ();
delete lset;
throw;
}
}
// run the 'loop' loop
Object* builtin_loop (Runnable* robj, Nameset* nset, Cons* args) {
// trivial check first
if ((args == nilp) || (args->length () != 4))
throw Exception ("argument-error",
"missing or too many arguments with loop");
// extract start, end step and form
Object* sobj = args->getcar ();
Object* eobj = args->getcadr ();
Object* step = args->getcaddr ();
Object* form = args->getcadddr ();
// create a new nameset and link it with parent
Nameset* lset = new Globalset (nset);
try {
// call the initial condition
if (sobj != nilp) Object::cref (sobj->eval (robj, lset));
// loop until false condition
Object* result = nilp;
while (check_cond (robj, lset, eobj) == true) {
Object::dref (result);
result = (form == nilp) ? nilp : form->eval (robj, lset);
Object::iref (result);
if (step != nilp) Object::cref (step->eval (robj, lset));
}
lset->reset ();
delete lset;
robj->post (result);
Object::tref (result);
return result;
} catch (...) {
lset->reset ();
delete lset;
throw;
}
}
}
syntax highlighted by Code2HTML, v. 0.9.1