1 /*
2 * @file ejsClass.c
3 * @brief EJS class support
4 */
5 /********************************* Copyright **********************************/
6 /*
7 * @copy default
8 *
9 * Copyright (c) Mbedthis Software LLC, 2003-2006. All Rights Reserved.
10 * Copyright (c) Michael O'Brien, 1994-1995. All Rights Reserved.
11 *
12 * This software is distributed under commercial and open source licenses.
13 * You may use the GPL open source license described below or you may acquire
14 * a commercial license from Mbedthis Software. You agree to be fully bound
15 * by the terms of either license. Consult the LICENSE.TXT distributed with
16 * this software for full details.
17 *
18 * This software is open source; you can redistribute it and/or modify it
19 * under the terms of the GNU General Public License as published by the
20 * Free Software Foundation; either version 2 of the License, or (at your
21 * option) any later version. See the GNU General Public License for more
22 * details at: http://www.mbedthis.com/downloads/gplLicense.html
23 *
24 * This program is distributed WITHOUT ANY WARRANTY; without even the
25 * implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
26 *
27 * This GPL license does NOT permit incorporating this software into
28 * proprietary programs. If you are unable to comply with the GPL, you must
29 * acquire a commercial license to use this software. Commercial licenses
30 * for this software and support services are available from Mbedthis
31 * Software at http://www.mbedthis.com
32 *
33 * @end
34 */
35 /********************************* Includes ***********************************/
36
37 #include "ejs.h"
38
39 #if BLD_FEATURE_EJS
40
41 /************************************ Code ************************************/
42 /*
43 * Internal API
44 *
45 * Routine to create a simple class object. This routine will create a
46 * stand-alone class object. Callers must insert this into the relevant
47 * "global" object for name resolution. From these class objects, instance
48 * objects may be created via the javascript "new" command.
49 *
50 * Users should use ejsDefineClass
51 */
52
ejsCreateSimpleClass(Ejs * ep,EjsVar * baseClass,const char * className)53 EjsVar *ejsCreateSimpleClass(Ejs *ep, EjsVar *baseClass, const char *className)
54 {
55 EjsProperty *pp;
56 EjsVar *classObj;
57
58 /*
59 * Create an instance of an Object to act as the static class object
60 */
61 classObj = ejsCreateSimpleObjUsingClass(ep, baseClass);
62 if (classObj == 0) {
63 mprAssert(classObj);
64 return 0;
65 }
66 ejsSetClassName(ep, classObj, className);
67
68 /*
69 * Set the propotype property to point to this class.
70 * Note: this is a self reference so the alive bit will not be turned on.
71 */
72 pp = ejsSetProperty(ep, classObj, "prototype", classObj);
73 ejsMakePropertyEnumerable(pp, 0);
74
75 return classObj;
76 }
77
78 /******************************************************************************/
79 /*
80 * Define a class in the given interpreter. If parentClass is specified, the
81 * class is defined in the parent. Otherwise, the class will be defined
82 * locally/globally. ClassName and extends are full variable specs
83 * (may contain ".")
84 */
85
ejsDefineClass(Ejs * ep,const char * className,const char * extends,EjsCMethod constructor)86 EjsVar *ejsDefineClass(Ejs *ep, const char *className, const char *extends,
87 EjsCMethod constructor)
88 {
89 EjsVar *parentClass, *classObj, *baseClass, *vp;
90 char *name;
91 char *cp;
92
93 /*
94 * If the className is a qualified name (with "."), then get the
95 * parent class name.
96 */
97 name = mprStrdup(ep, className);
98 cp = strrchr(name, '.');
99 if (cp != 0) {
100 *cp++ = '\0';
101 className = cp;
102 parentClass = ejsFindProperty(ep, 0, 0, ep->global, ep->local, name, 0);
103 if (parentClass == 0 || parentClass->type != EJS_TYPE_OBJECT) {
104 mprError(ep, MPR_LOC, "Can't find class's parent class %s", name);
105 mprFree(name);
106 return 0;
107 }
108
109 } else {
110 /*
111 * Simple class name without a "." so create the class locally
112 * if a local scope exists, otherwise globally.
113 */
114 parentClass = (ep->local) ? ep->local : ep->global;
115 }
116
117 if (parentClass == 0) {
118 mprError(ep, MPR_LOC, "Can't find parent class");
119 mprFree(name);
120 return 0;
121 }
122
123 /* OPT should use function that doesn't parse [] . */
124 baseClass = ejsGetClass(ep, 0, extends);
125 if (baseClass == 0) {
126 mprAssert(baseClass);
127 mprFree(name);
128 return 0;
129 }
130
131 classObj = ejsCreateSimpleClass(ep, baseClass, className);
132 if (classObj == 0) {
133 mprAssert(classObj);
134 mprFree(name);
135 return 0;
136 }
137
138 if (constructor) {
139 ejsDefineCMethod(ep, classObj, className, constructor, 0);
140 }
141
142 ejsSetPropertyAndFree(ep, parentClass, className, classObj);
143
144 vp = ejsGetPropertyAsVar(ep, parentClass, className);
145 mprFree(name);
146
147 return vp;
148 }
149
150 /******************************************************************************/
151 /*
152 * Find a class and return the property defining the class. ClassName may
153 * contain "." and is interpreted relative to obj. Obj is typically some
154 * parent object, ep->local or ep->global. If obj is null, then the global
155 * space is used.
156 */
157
ejsGetClass(Ejs * ep,EjsVar * obj,const char * className)158 EjsVar *ejsGetClass(Ejs *ep, EjsVar *obj, const char *className)
159 {
160 EjsVar *vp;
161
162 mprAssert(ep);
163
164 /*
165 * Search first for a constructor of the name of class
166 * global may not be defined yet.
167 */
168 if (obj) {
169 vp = ejsFindProperty(ep, 0, 0, obj, 0, className, 0);
170
171 } else {
172 mprAssert(ep->global);
173 vp = ejsFindProperty(ep, 0, 0, ep->global, ep->local, className, 0);
174 }
175 if (vp == 0 || vp->type != EJS_TYPE_OBJECT) {
176 return 0;
177 }
178
179 /*
180 * Return a reference to the prototype (self) reference. This
181 * ensures that even if "obj" is deleted, this reference will remain
182 * usable.
183 */
184 return ejsGetPropertyAsVar(ep, vp, "prototype");
185 }
186
187 /******************************************************************************/
188 /*
189 * Return the class name of a class or object
190 */
191
ejsGetClassName(EjsVar * vp)192 const char *ejsGetClassName(EjsVar *vp)
193 {
194 EjsObj *obj;
195
196 mprAssert(vp);
197 mprAssert(vp->type == EJS_TYPE_OBJECT);
198 mprAssert(vp->objectState->baseClass);
199
200 if (vp == 0 || !ejsVarIsObject(vp)) {
201 return 0;
202 }
203 obj = vp->objectState;
204
205 return obj->className;
206 }
207
208 /******************************************************************************/
209 /*
210 * Return the class name of an objects underlying class
211 * If called on an object, it returns the base class.
212 * If called on a class, it returns the base class for the class.
213 */
214
ejsGetBaseClassName(EjsVar * vp)215 const char *ejsGetBaseClassName(EjsVar *vp)
216 {
217 EjsObj *obj;
218
219 mprAssert(vp);
220 mprAssert(vp->type == EJS_TYPE_OBJECT);
221 mprAssert(vp->objectState->baseClass);
222
223 if (vp == 0 || !ejsVarIsObject(vp)) {
224 return 0;
225 }
226 obj = vp->objectState;
227 if (obj->baseClass == 0) {
228 return 0;
229 }
230 mprAssert(obj->baseClass->objectState);
231
232 return obj->baseClass->objectState->className;
233 }
234
235 /******************************************************************************/
236
ejsGetBaseClass(EjsVar * vp)237 EjsVar *ejsGetBaseClass(EjsVar *vp)
238 {
239 if (vp == 0 || !ejsVarIsObject(vp) || vp->objectState == 0) {
240 mprAssert(0);
241 return 0;
242 }
243 return vp->objectState->baseClass;
244 }
245
246 /******************************************************************************/
247
ejsSetBaseClass(EjsVar * vp,EjsVar * baseClass)248 void ejsSetBaseClass(EjsVar *vp, EjsVar *baseClass)
249 {
250 if (vp == 0 || !ejsVarIsObject(vp) || vp->objectState == 0) {
251 mprAssert(0);
252 return;
253 }
254 vp->objectState->baseClass = baseClass;
255 }
256
257 /******************************************************************************/
258
259 #else
ejsProcsDummy()260 void ejsProcsDummy() {}
261
262 /******************************************************************************/
263 #endif /* BLD_FEATURE_EJS */
264
265 /*
266 * Local variables:
267 * tab-width: 4
268 * c-basic-offset: 4
269 * End:
270 * vim:tw=78
271 * vim600: sw=4 ts=4 fdm=marker
272 * vim<600: sw=4 ts=4
273 */
274