// ---------------------------------------------------------------------------
// - Operator.cpp -
// - afnix engine - operator builtin 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 "Real.hpp"
#include "Builtin.hpp"
#include "Boolean.hpp"
#include "Runnable.hpp"
#include "QuarkZone.hpp"
#include "Exception.hpp"
namespace afnix {
// this procedure extract and evaluate the calling object for an operator
static inline Object* getobj (Runnable* robj, Nameset* nset, Cons* args,
const char* opname) {
Object* car = nilp;
Object* obj = nilp;
if ((args == nilp) || (args->length () != 2)) {
throw Exception ("argument-error",
"missing or too many arguments with operator", opname);
}
car = args->getcar ();
obj = (car == nilp) ? nilp : car->eval (robj,nset);
if (obj == nilp) {
throw Exception ("type-error", "invalid nil object with operator",
opname);
}
return Object::iref (obj);
}
// this procedure evaluates the cadr and return it
static inline Object* getarg (Runnable* robj, Nameset* nset, Cons* args) {
Object* car = (args == nilp) ? nilp : args->getcadr ();
Object* obj = (car == nilp) ? nilp : car->eval (robj, nset);
return Object::iref (obj);
}
// operator +
Object* builtin_add (Runnable* robj, Nameset* nset, Cons* args) {
// get the objects
Object* obj = getobj (robj, nset, args, "+");
Object* arg = nilp;
try {
arg = getarg (robj, nset, args);
} catch (...) {
Object::dref (obj);
throw;
}
// perform operation
try {
Object* result = obj->oper (Object::ADD, arg);
robj->post (result);
Object::dref (obj);
Object::dref (arg);
return result;
} catch (...) {
Object::dref (obj);
Object::dref (arg);
throw;
}
}
// operator -
Object* builtin_sub (Runnable* robj, Nameset* nset, Cons* args) {
// check arguments
long argc = 0;
if ((args == nilp) || (((argc = args->length ()) != 1) && (argc != 2))) {
throw Exception ("argument-error",
"missing or too many arguments with operator -");
}
// evaluate first argument
Object* car = args->getcar ();
Object* obj = (car == nilp) ? nilp : car->eval (robj, nset);
if (obj == nilp) {
throw Exception ("type-error", "invalid nil object with operator -");
}
Object::iref (obj);
// process unary operator
if (argc == 1) {
try {
Object* result = obj->oper (Object::UMN, (Object*) nilp);
Object::dref (obj);
robj->post (result);
return result;
} catch (...) {
Object::dref (obj);
throw;
}
}
// process normal operator
Object* arg = nilp;
try {
arg = getarg (robj, nset, args);
} catch (...) {
Object::dref (obj);
throw;
}
try {
Object* result = obj->oper (Object::SUB, arg);
robj->post (result);
Object::dref (obj);
Object::dref (arg);
return result;
} catch (...) {
Object::dref (obj);
Object::dref (arg);
throw;
}
}
// operator *
Object* builtin_mul (Runnable* robj, Nameset* nset, Cons* args) {
// get the objects
Object* obj = getobj (robj, nset, args, "*");
Object* arg = nilp;
try {
arg = getarg (robj, nset, args);
} catch (...) {
Object::dref (obj);
throw;
}
// perform operation
try {
Object* result = obj->oper (Object::MUL, arg);
robj->post (result);
Object::dref (obj);
Object::dref (arg);
return result;
} catch (...) {
Object::dref (obj);
Object::dref (arg);
throw;
}
}
// operator /
Object* builtin_div (Runnable* robj, Nameset* nset, Cons* args) {
// get the objects
Object* obj = getobj (robj, nset, args, "/");
Object* arg = nilp;
try {
arg = getarg (robj, nset, args);
} catch (...) {
Object::dref (obj);
throw;
}
// perform operation
try {
Object* result = obj->oper (Object::DIV, arg);
robj->post (result);
Object::dref (obj);
Object::dref (arg);
return result;
} catch (...) {
Object::dref (obj);
Object::dref (arg);
throw;
}
}
// operator ==
Object* builtin_eql (Runnable* robj, Nameset* nset, Cons* args) {
// get the objects
Object* obj = getobj (robj, nset, args, "==");
Object* arg = nilp;
try {
arg = getarg (robj, nset, args);
} catch (...) {
Object::dref (obj);
throw;
}
// perform operation
try {
Object* result = obj->oper (Object::EQL, arg);
robj->post (result);
Object::dref (obj);
Object::dref (arg);
return result;
} catch (...) {
Object::dref (obj);
Object::dref (arg);
throw;
}
}
// operator !=
Object* builtin_neq (Runnable* robj, Nameset* nset, Cons* args) {
// get the objects
Object* obj = getobj (robj, nset, args, "!=");
Object* arg = nilp;
try {
arg = getarg (robj, nset, args);
} catch (...) {
Object::dref (obj);
throw;
}
// perform operation
try {
Object* result = obj->oper (Object::NEQ, arg);
robj->post (result);
Object::dref (obj);
Object::dref (arg);
return result;
} catch (...) {
Object::dref (obj);
Object::dref (arg);
throw;
}
}
// operator >=
Object* builtin_geq (Runnable* robj, Nameset* nset, Cons* args) {
// get the objects
Object* obj = getobj (robj, nset, args, ">=");
Object* arg = nilp;
try {
arg = getarg (robj, nset, args);
} catch (...) {
Object::dref (obj);
throw;
}
// perform operation
try {
Object* result = obj->oper (Object::GEQ, arg);
robj->post (result);
Object::dref (obj);
Object::dref (arg);
return result;
} catch (...) {
Object::dref (obj);
Object::dref (arg);
throw;
}
}
// operator >
Object* builtin_gth (Runnable* robj, Nameset* nset, Cons* args) {
// get the objects
Object* obj = getobj (robj, nset, args, ">");
Object* arg = nilp;
try {
arg = getarg (robj, nset, args);
} catch (...) {
Object::dref (obj);
throw;
}
// perform operation
try {
Object* result = obj->oper (Object::GTH, arg);
robj->post (result);
Object::dref (obj);
Object::dref (arg);
return result;
} catch (...) {
Object::dref (obj);
Object::dref (arg);
throw;
}
}
// operator <=
Object* builtin_leq (Runnable* robj, Nameset* nset, Cons* args) {
// get the objects
Object* obj = getobj (robj, nset, args, "<=");
Object* arg = nilp;
try {
arg = getarg (robj, nset, args);
} catch (...) {
Object::dref (obj);
throw;
}
// perform operation
try {
Object* result = obj->oper (Object::LEQ, arg);
robj->post (result);
Object::dref (obj);
Object::dref (arg);
return result;
} catch (...) {
Object::dref (obj);
Object::dref (arg);
throw;
}
}
// operator <
Object* builtin_lth (Runnable* robj, Nameset* nset, Cons* args) {
// get the objects
Object* obj = getobj (robj, nset, args, "<");
Object* arg = nilp;
try {
arg = getarg (robj, nset, args);
} catch (...) {
Object::dref (obj);
throw;
}
// perform operation
try {
Object* result = obj->oper (Object::LTH, arg);
robj->post (result);
Object::dref (obj);
Object::dref (arg);
return result;
} catch (...) {
Object::dref (obj);
Object::dref (arg);
throw;
}
}
// process an assert command - this does nothing if the assert flag is false
Object* builtin_assert (Runnable* robj, Nameset* nset, Cons* args) {
// process first object
Object* car1 = (args == nilp) ? nilp : args->getcar ();
Object* obj1 = (car1 == nilp) ? nilp : car1->eval (robj, nset);
Object::iref (obj1);
// process object 2
Object* car2 = (args == nilp) ? nilp : args->getcadr ();
Object* obj2 = (car2 == nilp) ? nilp : car2->eval (robj, nset);
Object::iref (obj2);
// check for nil
if ((obj1 == nilp) && (obj2 == nilp)) return nilp;
// do nothing if assert flag is false
if (robj->getasrt () == false) {
Object::dref (obj1);
Object::dref (obj2);
return nilp;
}
// normal compare
bool status = false;
if (obj1 != nilp) {
Object* aobj = obj1->oper (Object::EQL, obj2);
Boolean* bobj = dynamic_cast <Boolean*> (aobj);
status = bobj->toboolean ();
Object::cref (bobj);
}
Object::dref (obj1);
Object::dref (obj2);
if (status == true) return nilp;
Exception e ("assert-error");
e.setabf (true);
throw e;
}
}
syntax highlighted by Code2HTML, v. 0.9.1