/* * @file ejsClass.c * @brief EJS class support */ /********************************* Copyright **********************************/ /* * @copy default * * Copyright (c) Mbedthis Software LLC, 2003-2006. All Rights Reserved. * Copyright (c) Michael O'Brien, 1994-1995. All Rights Reserved. * * This software is distributed under commercial and open source licenses. * You may use the GPL open source license described below or you may acquire * a commercial license from Mbedthis Software. You agree to be fully bound * by the terms of either license. Consult the LICENSE.TXT distributed with * this software for full details. * * This software is open source; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the * Free Software Foundation; either version 2 of the License, or (at your * option) any later version. See the GNU General Public License for more * details at: http://www.mbedthis.com/downloads/gplLicense.html * * This program is distributed WITHOUT ANY WARRANTY; without even the * implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. * * This GPL license does NOT permit incorporating this software into * proprietary programs. If you are unable to comply with the GPL, you must * acquire a commercial license to use this software. Commercial licenses * for this software and support services are available from Mbedthis * Software at http://www.mbedthis.com * * @end */ /********************************* Includes ***********************************/ #include "ejs.h" #if BLD_FEATURE_EJS /************************************ Code ************************************/ /* * Internal API * * Routine to create a simple class object. This routine will create a * stand-alone class object. Callers must insert this into the relevant * "global" object for name resolution. From these class objects, instance * objects may be created via the javascript "new" command. * * Users should use ejsDefineClass */ EjsVar *ejsCreateSimpleClass(Ejs *ep, EjsVar *baseClass, const char *className) { EjsProperty *pp; EjsVar *classObj; /* * Create an instance of an Object to act as the static class object */ classObj = ejsCreateSimpleObjUsingClass(ep, baseClass); if (classObj == 0) { mprAssert(classObj); return 0; } ejsSetClassName(ep, classObj, className); /* * Set the propotype property to point to this class. * Note: this is a self reference so the alive bit will not be turned on. */ pp = ejsSetProperty(ep, classObj, "prototype", classObj); ejsMakePropertyEnumerable(pp, 0); return classObj; } /******************************************************************************/ /* * Define a class in the given interpreter. If parentClass is specified, the * class is defined in the parent. Otherwise, the class will be defined * locally/globally. ClassName and extends are full variable specs * (may contain ".") */ EjsVar *ejsDefineClass(Ejs *ep, const char *className, const char *extends, EjsCMethod constructor) { EjsVar *parentClass, *classObj, *baseClass, *vp; char *name; char *cp; /* * If the className is a qualified name (with "."), then get the * parent class name. */ name = mprStrdup(ep, className); cp = strrchr(name, '.'); if (cp != 0) { *cp++ = '\0'; className = cp; parentClass = ejsFindProperty(ep, 0, 0, ep->global, ep->local, name, 0); if (parentClass == 0 || parentClass->type != EJS_TYPE_OBJECT) { mprError(ep, MPR_LOC, "Can't find class's parent class %s", name); mprFree(name); return 0; } } else { /* * Simple class name without a "." so create the class locally * if a local scope exists, otherwise globally. */ parentClass = (ep->local) ? ep->local : ep->global; } if (parentClass == 0) { mprError(ep, MPR_LOC, "Can't find parent class"); mprFree(name); return 0; } /* OPT should use function that doesn't parse [] . */ baseClass = ejsGetClass(ep, 0, extends); if (baseClass == 0) { mprAssert(baseClass); mprFree(name); return 0; } classObj = ejsCreateSimpleClass(ep, baseClass, className); if (classObj == 0) { mprAssert(classObj); mprFree(name); return 0; } if (constructor) { ejsDefineCMethod(ep, classObj, className, constructor, 0); } ejsSetPropertyAndFree(ep, parentClass, className, classObj); vp = ejsGetPropertyAsVar(ep, parentClass, className); mprFree(name); return vp; } /******************************************************************************/ /* * Find a class and return the property defining the class. ClassName may * contain "." and is interpreted relative to obj. Obj is typically some * parent object, ep->local or ep->global. If obj is null, then the global * space is used. */ EjsVar *ejsGetClass(Ejs *ep, EjsVar *obj, const char *className) { EjsVar *vp; mprAssert(ep); /* * Search first for a constructor of the name of class * global may not be defined yet. */ if (obj) { vp = ejsFindProperty(ep, 0, 0, obj, 0, className, 0); } else { mprAssert(ep->global); vp = ejsFindProperty(ep, 0, 0, ep->global, ep->local, className, 0); } if (vp == 0 || vp->type != EJS_TYPE_OBJECT) { return 0; } /* * Return a reference to the prototype (self) reference. This * ensures that even if "obj" is deleted, this reference will remain * usable. */ return ejsGetPropertyAsVar(ep, vp, "prototype"); } /******************************************************************************/ /* * Return the class name of a class or object */ const char *ejsGetClassName(EjsVar *vp) { EjsObj *obj; mprAssert(vp); mprAssert(vp->type == EJS_TYPE_OBJECT); mprAssert(vp->objectState->baseClass); if (vp == 0 || !ejsVarIsObject(vp)) { return 0; } obj = vp->objectState; return obj->className; } /******************************************************************************/ /* * Return the class name of an objects underlying class * If called on an object, it returns the base class. * If called on a class, it returns the base class for the class. */ const char *ejsGetBaseClassName(EjsVar *vp) { EjsObj *obj; mprAssert(vp); mprAssert(vp->type == EJS_TYPE_OBJECT); mprAssert(vp->objectState->baseClass); if (vp == 0 || !ejsVarIsObject(vp)) { return 0; } obj = vp->objectState; if (obj->baseClass == 0) { return 0; } mprAssert(obj->baseClass->objectState); return obj->baseClass->objectState->className; } /******************************************************************************/ EjsVar *ejsGetBaseClass(EjsVar *vp) { if (vp == 0 || !ejsVarIsObject(vp) || vp->objectState == 0) { mprAssert(0); return 0; } return vp->objectState->baseClass; } /******************************************************************************/ void ejsSetBaseClass(EjsVar *vp, EjsVar *baseClass) { if (vp == 0 || !ejsVarIsObject(vp) || vp->objectState == 0) { mprAssert(0); return; } vp->objectState->baseClass = baseClass; } /******************************************************************************/ #else void ejsProcsDummy() {} /******************************************************************************/ #endif /* BLD_FEATURE_EJS */ /* * Local variables: * tab-width: 4 * c-basic-offset: 4 * End: * vim:tw=78 * vim600: sw=4 ts=4 fdm=marker * vim<600: sw=4 ts=4 */