// --------------------------------------------------------------------------- // - Qualified.cpp - // - afnix engine - qualified name 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 "Engsid.hxx" #include "Vector.hpp" #include "Strvec.hpp" #include "Lexical.hpp" #include "Integer.hpp" #include "Nameset.hpp" #include "Runnable.hpp" #include "Qualified.hpp" #include "QuarkZone.hpp" #include "Exception.hpp" namespace afnix { // ------------------------------------------------------------------------- // - private section - // ------------------------------------------------------------------------- // this procedure returns a new qualified object for deserialization static Serial* mksob (void) { return new Qualified; } // register this qualified serial id static const t_byte SERIAL_ID = Serial::setsid (SERIAL_QUAL_ID, mksob); // this procedure update the qualified length and quark array by name static void qualified_update (const String& name, long& ql, long** qa) { // clean the old quark array if (*qa != nilp) delete [] (*qa); // extract the name Strvec path = Strvec::split (name, ":"); ql = path.length (); if (ql < 2) throw Exception ("syntax-error", "invalid qualified name", name); // build the quarks *qa = new long[ql]; for (long i = 0; i < ql; i++) { String data = path.get (i); if (Lexical::valid (data) == false) { delete [] *qa; throw Exception ("syntax-error", "invalid qualified name", name); } (*qa)[i] = data.toquark (); } } // ------------------------------------------------------------------------- // - class section - // ------------------------------------------------------------------------- // create a default qualified Qualified::Qualified (void) { d_lnum = 0; d_length = 0; p_quarks = nilp; } // create a qualified with a name Qualified::Qualified (const String& name) { // save data value d_name = name; d_lnum = 0; // update the qualified p_quarks = nilp; qualified_update (name, d_length, &p_quarks); } // create a qualified with a name and a line number Qualified::Qualified (const String& name, const long lnum) { // save data value d_name = name; d_lnum = lnum; // update the qualified p_quarks = nilp; qualified_update (name, d_length, &p_quarks); } // copy constructor for this qualified Qualified::Qualified (const Qualified& that) { that.rdlock (); // save data value d_name = that.d_name; d_lnum = that.d_lnum; // update the qualified p_quarks = nilp; qualified_update (d_name, d_length, &p_quarks); that.unlock (); } // destroy this qualified Qualified::~Qualified (void) { delete [] p_quarks; } // return the class name String Qualified::repr (void) const { return "Qualified"; } // return a literal representation of this qualified String Qualified::toliteral (void) const { rdlock (); String result = d_name; unlock (); return result; } // return a string representation of this qualified String Qualified::tostring (void) const { rdlock (); String result = d_name; unlock (); return result; } // return a clone of this qualified Object* Qualified::clone (void) const { return new Qualified (*this); } // return the qualified serial code t_byte Qualified::serialid (void) const { return SERIAL_QUAL_ID; } // serialize this qualified void Qualified::wrstream (Output& os) const { rdlock (); Integer lnum (d_lnum); d_name.wrstream (os); lnum.wrstream (os); unlock (); } // deserialize this qualified void Qualified::rdstream (Input& is) { wrlock (); String sval; Integer ival; sval.rdstream (is); ival.rdstream (is); d_name = sval; d_lnum = ival.tointeger (); qualified_update (d_name, d_length, &p_quarks); unlock (); } // this procedure performs a partial evaluation and return the object static inline Object* eval_partial (Runnable* robj, Nameset* nset, const long len, long* quarks) { Object* obj = nilp; obj = nset->eval (robj, nset, quarks[0]); for (long i = 1; i < len; i++) { if (obj == nilp) return nilp; obj = obj->eval (robj, nset, quarks[i]); } return obj; } // the length of the qualified name path long Qualified::length (void) const { rdlock (); long result = d_length; unlock (); return result; } // return a partial name by index String Qualified::getname (const long index) const { rdlock (); if ((index < 0) || (index >= d_length )) { unlock (); throw Exception ("index-error", "out of bound qualified index"); } try { String result = String::qmap (p_quarks[index]); unlock (); return result; } catch (...) { unlock (); throw; } } // return the qualified line number long Qualified::getlnum (void) const { rdlock (); long result = d_lnum; unlock (); return result; } // ------------------------------------------------------------------------- // - object section - // ------------------------------------------------------------------------- // the quark zone static const long QUARK_ZONE_LENGTH = 4; static QuarkZone zone (QUARK_ZONE_LENGTH); // the qualified quarks static const long QUARK_MAP = zone.intern ("map"); static const long QUARK_LENGTH = zone.intern ("length"); static const long QUARK_GETNAME = zone.intern ("get-name"); static const long QUARK_GETLNUM = zone.intern ("get-lnum"); // create a qualified in a generic way Object* Qualified::mknew (Vector* argv) { // get the number of arguments long argc = (argv == nilp) ? 0 : argv->length (); // check for 0 argument if (argc == 0) return new Qualified; // check for 1 argument if (argc == 1) { String name = argv->getstring (0); return new Qualified (name); } // illegal arguments throw Exception ("argument-error", "too many arguments with qualified"); } // return true if the given quark is defined bool Qualified::isquark (const long quark, const bool hflg) const { rdlock (); if (zone.exists (quark) == true) { unlock (); return true; } bool result = hflg ? Object::isquark (quark, hflg) : false; unlock (); return result; } // set a constant object to thsi object Object* Qualified::cdef (Runnable* robj, Nameset* nset, Object* object) { // lock and protect called object as it might be in the runnable // which is changed during the eval partial wrlock (); Object::iref (object); try { long plen = d_length - 1; Object* obj = eval_partial (robj, nset, plen, p_quarks); if (obj == nilp) { unlock (); throw Exception ("eval-error", "nil object with qualified name", d_name); } Object* result = obj->cdef (robj, nset, p_quarks[plen], object); robj->post (result); Object::tref (object); unlock (); return result; } catch (...) { Object::tref (object); unlock (); throw; } } // set an object to this object Object* Qualified::vdef (Runnable* robj, Nameset* nset, Object* object) { // lock and protect called object as it might be in the runnable // which is changed during the eval partial wrlock (); Object::iref (object); try { long plen = d_length - 1; Object* obj = eval_partial (robj, nset, plen, p_quarks); if (obj == nilp) { unlock (); throw Exception ("eval-error", "nil object with qualified name", d_name); } Object* result = obj->vdef (robj, nset, p_quarks[plen], object); robj->post (result); Object::tref (object); unlock (); return result; } catch (...) { Object::tref (object); unlock (); throw; } } // evaluate this object Object* Qualified::eval (Runnable* robj, Nameset* nset) { rdlock (); try { long plen = d_length - 1; Object* obj = eval_partial (robj, nset, plen, p_quarks); if (obj == nilp) { unlock (); throw Exception ("eval-error", "nil object with qualified name", d_name); } Object* result = obj->eval (robj, nset, p_quarks[plen]); robj->post (result); unlock (); return result; } catch (...) { unlock (); throw; } } // apply this object with a set of arguments and a quark Object* Qualified::apply (Runnable* robj, Nameset* nset, const long quark, Vector* argv) { // get the number of arguments long argc = (argv == nilp) ? 0 : argv->length (); // dispatch 0 argument if (argc == 0) { if (quark == QUARK_LENGTH) return new Integer (length ()); if (quark == QUARK_GETLNUM) return new Integer (getlnum ()); if (quark == QUARK_MAP) { long qrk = p_quarks[d_length - 1]; Object* result = (nset == nilp) ? nilp : nset->find (qrk); robj->post (result); return result; } } // check for 1 argument if (argc == 1) { if (quark == QUARK_GETNAME) { long index = argv->getint (0); return new String (getname (index)); } } // call the literal method return Literal::apply (robj, nset, quark, argv); } }