// --------------------------------------------------------------------------- // - 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 (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 (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 (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 (args->getcar ()); if (cons == nilp) throw Exception ("argument-error", "only data member list with class"); while (cons != nilp) { Lexical* lex = dynamic_cast (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"); } }