// ---------------------------------------------------------------------------
// - Class.cpp -
// - afnix engine - class class 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 "Class.hpp"
#include "Method.hpp"
#include "Lexical.hpp"
#include "Boolean.hpp"
#include "Builtin.hpp"
#include "Instance.hpp"
#include "Runnable.hpp"
#include "QuarkZone.hpp"
#include "Exception.hpp"
namespace afnix {
// -------------------------------------------------------------------------
// - class section -
// -------------------------------------------------------------------------
// create a new class object
Class::Class (void) {
p_infer = nilp;
p_defer = nilp;
d_ctinf = false;
d_ctdef = false;
Object::iref (p_cset = new Localset);
}
// destroy this class object
Class::~Class (void) {
Object::dref (p_infer);
Object::dref (p_defer);
Object::dref (p_cset);
}
// return the class name
String Class::repr (void) const {
return "Class";
}
// make this class a shared object
void Class::mksho (void) {
if (p_shared != nilp) return;
Object::mksho ();
if (p_infer != nilp) p_infer->mksho ();
if (p_defer != nilp) p_defer->mksho ();
if (p_cset != nilp) p_cset->mksho ();
}
// add a new data member by quark
void Class::add (const long quark) {
wrlock ();
if (d_mdata.exists (quark) == true) {
unlock ();
throw Exception ("duplicate-error", "duplicate data member name",
String::qmap (quark));
}
try {
d_mdata.add (quark);
unlock ();
} catch (...) {
unlock ();
throw;
}
}
// return the array of data members
const Qarray& Class::getmdata (void) const {
rdlock ();
const Qarray& result = d_mdata;
unlock ();
return result;
}
// return an object in the class but do not evaluate
Object* Class::find (const long quark) const {
rdlock ();
// check in the local set first
Object* result = p_cset->find (quark);
// check in the deferent class
if ((result == nilp) && (p_defer != nilp)) {
result = p_defer->find (quark);
}
unlock ();
return result;
}
// set the class inferent object
Object* Class::setinfer (Object* object, const bool flag) {
// check for a class
Class* infer = dynamic_cast <Class*> (object);
if ((infer == nilp) && (object != nilp)) {
throw Exception ("type-error", "invalid object to set as inferent class",
Object::repr (object));
}
return setinfer (infer, flag);
}
// set the class inferent value
Object* Class::setinfer (Class* infer, const bool flag) {
wrlock ();
if (d_ctinf == true) {
unlock ();
throw Exception ("const-error", "const violation with infer member");
}
Object::iref (infer);
Object::dref (p_infer);
p_infer = infer;
d_ctinf = flag;
unlock ();
return infer;
}
// set the class deferent object
Object* Class::setdefer (Object* object, const bool flag) {
// check for a class
Class* defer = dynamic_cast <Class*> (object);
if ((defer == nilp) && (object != nilp)) {
throw Exception ("type-error", "invalid object to set as deferent class",
Object::repr (object));
}
return setdefer (defer, flag);
}
// set the class deferent value
Object* Class::setdefer (Class* defer, const bool flag) {
wrlock ();
if (d_ctdef == true) {
unlock ();
throw Exception ("const-error", "const violation with defer member");
}
Object::iref (defer);
Object::dref (p_defer);
p_defer = defer;
d_ctdef = flag;
unlock ();
return defer;
}
// -------------------------------------------------------------------------
// - object section -
// -------------------------------------------------------------------------
// the quark zone
static const long QUARK_ZONE_LENGTH = 2;
static QuarkZone zone (QUARK_ZONE_LENGTH);
// the object supported quarks
static const long QUARK_INFER = zone.intern ("infer");
static const long QUARK_DEFER = zone.intern ("defer");
// return true if the given quark is defined
bool Class::isquark (const long quark, const bool hflg) const {
rdlock ();
// check in the quark zone
if (zone.exists(quark) == true) {
unlock ();
return true;
}
// check in the localset
if (p_cset->exists (quark) == true) {
unlock ();
return true;
}
// check in the deferent class
if (p_defer != nilp) {
bool result = p_defer->isquark (quark, hflg);
unlock ();
return result;
}
// check in the class base object
bool result = hflg ? Object::isquark (quark, hflg) : false;
unlock ();
return result;
}
// operate this class with another object
Object* Class::oper (t_oper type, Object* object) {
Class* cobj = dynamic_cast <Class*> (object);
switch (type) {
case Object::EQL:
if (cobj != nilp) return new Boolean (this == cobj);
break;
case Object::NEQ:
if (cobj != nilp) return new Boolean (this != cobj);
break;
default:
throw Exception ("operator-error", "unsupported class operator");
}
throw Exception ("type-error", "invalid operand with class",
Object::repr (object));
}
// create a new class symbol by quark
Object* Class::cdef (Runnable* robj, Nameset* nset, const long quark,
Object* object) {
wrlock ();
try {
// check for reserved quark
if (quark == QUARK_INFER) return setinfer (object, true);
if (quark == QUARK_DEFER) return setdefer (object, true);
// check in the localset
Object* result = p_cset->cdef (robj, nset, quark, object);
robj->post (result);
unlock ();
return result;
} catch (...) {
unlock ();
throw;
}
}
// create or set a new class symbol by quark
Object* Class::vdef (Runnable* robj, Nameset* nset, const long quark,
Object* object) {
wrlock ();
try {
// check for reserved quark
if (quark == QUARK_INFER) return setinfer (object, false);
if (quark == QUARK_DEFER) return setdefer (object, false);
// check in the localset
Object* result = p_cset->vdef (robj, nset, quark, object);
robj->post (result);
unlock ();
return result;
} catch (...) {
unlock ();
throw;
}
}
// evaluate an object member by quark
Object* Class::eval (Runnable* robj, Nameset* nset, const long quark) {
rdlock ();
try {
// check for inferent class
if (quark == QUARK_INFER) {
Object* result = p_infer;
robj->post (result);
unlock ();
return result;
}
// check for deferent class
if (quark == QUARK_DEFER) {
Object* result = p_defer;
robj->post (result);
unlock ();
return result;
}
// look in the local set
Object* obj = p_cset->find (quark);
if (obj != nilp) {
Object* result = obj->eval (robj, nset);
robj->post (result);
unlock ();
return result;
}
// check in the deferent class
if (p_defer != nilp) {
Object* result = p_defer->eval (robj, nset, quark);
robj->post (result);
unlock ();
return result;
}
// last resort is a method
unlock ();
return new Method (quark, this, true);
} catch ( ...) {
unlock ();
throw;
}
}
// apply this object with a set of arguments
Object* Class::apply (Runnable* robj, Nameset* nset, Cons* args) {
rdlock ();
try {
// create an instance with a class
Instance* inst = new Instance (this);
// loop with the inferent class
Class* infer = p_infer;
// check for an inferent class
while (infer != nilp) {
// create an inferent instance
Instance* ii = new Instance (infer);
// set the super instance
ii->setsuper (inst, infer->d_ctinf);
// here is the new result
inst = ii;
// get the next inferent class
infer = infer->p_infer;
};
// call the preset method
Object* result = inst->pdef (robj, nset, args);
robj->post (inst);
Object::cref (result);
unlock ();
return inst;
} catch (...) {
unlock ();
throw;
}
}
// apply a this object function with a set of arguments and a quark
Object* Class::apply (Runnable* robj, Nameset* nset, const long quark,
Cons* args) {
// evaluate the object
Object* obj = eval (robj, nset, quark);
// apply with arguments
return (obj == nilp) ? nilp : obj->apply (robj, nset, args);
}
// -------------------------------------------------------------------------
// - builtin section -
// -------------------------------------------------------------------------
// create a new class object - this is the builtin function
Object* builtin_class (Runnable* robj, Nameset* nset, Cons* args) {
long len = (args == nilp) ? 0 : (args->length ());
// process 0 arguments
if (len == 0) return new Class;
// process data member list
if (len == 1) {
Class* cls = new Class;
Cons* cons = dynamic_cast <Cons*> (args->getcar ());
if (cons == nilp) throw Exception ("argument-error",
"only data member list with class");
while (cons != nilp) {
Lexical* lex = dynamic_cast <Lexical*> (cons->getcar ());
if (lex == nilp)
throw Exception ("argument-error",
"only lexical name with class data memeber list");
cls->add (lex->toquark ());
cons = cons->getcdr ();
}
return cls;
}
throw Exception ("argument-error",
"too many arguments with class definition");
}
}
syntax highlighted by Code2HTML, v. 0.9.1