5 /********************************* Copyright **********************************/
9 * Copyright (c) Mbedthis Software LLC, 2003-2006. All Rights Reserved.
10 * Copyright (c) Michael O'Brien, 1994-1995. All Rights Reserved.
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.
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
24 * This program is distributed WITHOUT ANY WARRANTY; without even the
25 * implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
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
35 /********************************** Includes **********************************/
41 /****************************** Forward Declarations **************************/
46 static void formatVar(Ejs *ep, MprBuf *bp, EjsVar *vp);
48 /******************************************************************************/
50 * Routine to create an object of the desired class. Class name may
53 * The created object will be a stand-alone class NOT entered into the
54 * properties of any other object. Callers must do this if required. ClassName
55 * may contain "." and is interpreted relative to "obj" if supplied.
57 * Note: this does not call the constructors for the various objects and base
61 EjsVar *ejsCreateSimpleObjInternal(EJS_LOC_DEC(ep, loc), const char *className)
65 if (className && *className) {
66 baseClass = ejsGetClass(ep, 0, className);
68 mprError(ep, MPR_LOC, "Can't find base class %s", className);
75 return ejsCreateSimpleObjUsingClassInt(EJS_LOC_PASS(ep, loc),
79 /******************************************************************************/
81 * Create an object based upon the specified base class object. It will be a
82 * stand-alone class not entered into the properties of any other object.
83 * Callers must do this if required.
85 * Note: this does not call the constructors for the various objects and base
89 EjsVar *ejsCreateSimpleObjUsingClassInt(EJS_LOC_DEC(ep, loc),
97 mprError(ep, MPR_LOC, "Missing base class\n");
101 vp = ejsCreateObjVarInternal(EJS_LOC_PASS(ep, loc));
106 ejsSetBaseClass(vp, baseClass);
109 * This makes all internal method accesses faster
110 * NOTE: this code is duplicated in ejsCreateSimpleClass
112 mprAssert(vp->objectState);
113 vp->objectState->methods = baseClass->objectState->methods;
118 /******************************************************************************/
120 void ejsSetMethods(Ejs *ep, EjsVar *op)
122 op->objectState->methods = ep->global->objectState->methods;
125 /******************************************************************************/
126 /******************************** Internal Methods ****************************/
127 /******************************************************************************/
129 static EjsVar *createObjProperty(Ejs *ep, EjsVar *obj, const char *property)
131 return ejsGetVarPtr(ejsCreateSimpleProperty(ep, obj, property));
134 /******************************************************************************/
136 static int deleteObjProperty(Ejs *ep, EjsVar *obj, const char *property)
138 return ejsDeleteProperty(ep, obj, property);
141 /******************************************************************************/
143 static EjsVar *getObjProperty(Ejs *ep, EjsVar *obj, const char *property)
145 return ejsGetVarPtr(ejsGetSimpleProperty(ep, obj, property));
148 /******************************************************************************/
150 * Set the value of a property. Create if it does not exist
153 static EjsVar *setObjProperty(Ejs *ep, EjsVar *obj, const char *property,
159 pp = ejsCreateSimpleProperty(ep, obj, property);
164 vp = ejsGetVarPtr(pp);
165 if (ejsWriteVar(ep, vp, value, EJS_SHALLOW_COPY) < 0) {
169 return ejsGetVarPtr(pp);
172 /******************************************************************************/
173 /*********************************** Constructors *****************************/
174 /******************************************************************************/
177 * Object constructor. We don't use this for speed. Think very carefully if
178 * you add an object constructor.
181 int ejsObjectConstructor(Ejs *ep, EjsVar *thisObj, int argc, EjsVar **argv)
187 /******************************************************************************/
188 /******************************** Visible Methods *****************************/
189 /******************************************************************************/
191 static int cloneMethod(Ejs *ep, EjsVar *thisObj, int argc, EjsVar **argv)
195 copyDepth = EJS_DEEP_COPY;
197 if (argc == 1 && ejsVarToBoolean(argv[0])) {
198 copyDepth = EJS_RECURSIVE_DEEP_COPY;
201 ejsWriteVar(ep, ep->result, thisObj, copyDepth);
206 /******************************************************************************/
208 static int toStringMethod(Ejs *ep, EjsVar *thisObj, int argc, EjsVar **argv)
211 int saveMaxDepth, saveDepth, saveFlags;
213 saveMaxDepth = ep->maxDepth;
216 ep->maxDepth = ejsVarToInteger(argv[0]);
217 } else if (ep->maxDepth == 0) {
218 ep->maxDepth = MAXINT;
221 saveFlags = ep->flags;
223 if (ejsVarToBoolean(argv[1])) {
224 ep->flags |= EJS_FLAGS_ENUM_HIDDEN;
228 if (ejsVarToBoolean(argv[2])) {
229 ep->flags |= EJS_FLAGS_ENUM_BASE;
233 bp = mprCreateBuf(ep, 0, 0);
235 saveDepth = ep->depth;
237 formatVar(ep, bp, thisObj);
239 ep->depth = saveDepth;
240 ep->maxDepth = saveMaxDepth;
244 ejsWriteVarAsString(ep, ep->result, mprGetBufStart(bp));
247 ep->flags = saveFlags;
252 /******************************************************************************/
254 static int valueOfMethod(Ejs *ep, EjsVar *thisObj, int argc, EjsVar **argv)
261 switch (thisObj->type) {
263 case EJS_TYPE_UNDEFINED:
265 case EJS_TYPE_CMETHOD:
266 case EJS_TYPE_OBJECT:
267 case EJS_TYPE_METHOD:
268 case EJS_TYPE_STRING_CMETHOD:
269 ejsWriteVar(ep, ep->result, thisObj, EJS_SHALLOW_COPY);
272 case EJS_TYPE_STRING:
273 ejsWriteVarAsInteger(ep, ep->result, atoi(thisObj->string));
278 #if BLD_FEATURE_INT64
281 #if BLD_FEATURE_FLOATING_POINT
284 ejsWriteVar(ep, ep->result, thisObj, EJS_SHALLOW_COPY);
290 /******************************************************************************/
292 static int hashGetAccessor(Ejs *ejs, EjsVar *thisObj, int argc, EjsVar **argv)
294 ejsSetReturnValueToInteger(ejs, (int) thisObj->objectState);
298 /******************************************************************************/
300 static int classGetAccessor(Ejs *ejs, EjsVar *thisObj, int argc, EjsVar **argv)
302 if (thisObj->objectState == 0 || thisObj->objectState->baseClass == 0) {
303 ejsSetReturnValueToString(ejs, "object");
305 ejsSetReturnValueToString(ejs,
306 thisObj->objectState->baseClass->objectState->className);
311 /******************************************************************************/
313 * Format an object. Called recursively to format properties and contained
317 static void formatVar(Ejs *ep, MprBuf *bp, EjsVar *vp)
319 EjsProperty *pp, *first;
320 EjsVar *propVar, *baseClass;
324 if (vp->type == EJS_TYPE_OBJECT) {
325 if (!vp->objectState->visited) {
327 mprPutStringToBuf(bp, vp->isArray ? "[\n" : "{\n");
330 vp->objectState->visited = 1;
332 if (ep->depth <= ep->maxDepth) {
333 first = ejsGetFirstProperty(vp, EJS_ENUM_ALL);
335 if (ep->flags & EJS_FLAGS_ENUM_BASE) {
336 baseClass = vp->objectState->baseClass;
338 for (i = 0; i < ep->depth; i++) {
339 mprPutStringToBuf(bp, " ");
341 mprPutStringToBuf(bp, baseClass->objectState->objName);
342 mprPutStringToBuf(bp, ": /* Base Class */ ");
343 if (baseClass->objectState == vp->objectState) {
345 } else if (ejsRunMethodCmd(ep, baseClass, "toString",
346 "%d", ep->maxDepth) < 0) {
347 value = "[object Object]";
349 mprAssert(ejsVarIsString(ep->result));
350 value = ep->result->string;
352 mprPutStringToBuf(bp, value);
354 mprPutStringToBuf(bp, ",\n");
361 if (! pp->dontEnumerate ||
362 ep->flags & EJS_FLAGS_ENUM_HIDDEN) {
363 for (i = 0; i < ep->depth; i++) {
364 mprPutStringToBuf(bp, " ");
368 mprPutStringToBuf(bp, pp->name);
369 mprPutStringToBuf(bp, ": ");
372 propVar = ejsGetVarPtr(pp);
373 if (propVar->type == EJS_TYPE_OBJECT) {
374 if (pp->var.objectState == vp->objectState) {
376 } else if (ejsRunMethodCmd(ep, propVar,
377 "toString", "%d", ep->maxDepth) < 0) {
378 value = "[object Object]";
380 mprAssert(ejsVarIsString(ep->result));
381 value = ep->result->string;
383 mprPutStringToBuf(bp, value);
386 formatVar(ep, bp, &pp->var);
389 pp = ejsGetNextProperty(pp, EJS_ENUM_ALL);
391 mprPutStringToBuf(bp, ",\n");
394 pp = ejsGetNextProperty(pp, EJS_ENUM_ALL);
398 vp->objectState->visited = 0;
400 mprPutCharToBuf(bp, '\n');
403 for (i = 0; i < ep->depth; i++) {
404 mprPutStringToBuf(bp, " ");
406 mprPutCharToBuf(bp, vp->isArray ? ']' : '}');
409 } else if (vp->type == EJS_TYPE_METHOD) {
411 mprPutStringToBuf(bp, "function (");
412 for (i = 0; i < vp->method.args->length; i++) {
413 mprPutStringToBuf(bp, vp->method.args->items[i]);
414 if ((i + 1) < vp->method.args->length) {
415 mprPutStringToBuf(bp, ", ");
418 mprPutStringToBuf(bp, ") {");
419 mprPutStringToBuf(bp, vp->method.body);
420 for (i = 0; i < ep->depth; i++) {
421 mprPutStringToBuf(bp, " ");
423 mprPutStringToBuf(bp, "}");
427 if (vp->type == EJS_TYPE_STRING) {
428 mprPutCharToBuf(bp, '\"');
432 * We don't use ejsVarToString for arrays, objects and strings.
433 * This is because ejsVarToString does not call "obj.toString"
434 * and it is not required for strings.
437 buf = ejsVarToString(ep, vp);
438 mprPutStringToBuf(bp, buf);
440 if (vp->type == EJS_TYPE_STRING) {
441 mprPutCharToBuf(bp, '\"');
446 /******************************************************************************/
448 * mixin code. Blends code at the "thisObj" level.
451 static int mixinMethod(Ejs *ep, EjsVar *thisObj, int argc, EjsVar **argv)
460 * Create a variable scope block set to the current object
463 fid = ejsSetBlock(ep, thisObj);
465 for (i = 0; i < argc; i++) {
467 if (ejsVarIsString(argv[i])) {
468 rc = ejsEvalScript(ep, argv[i]->string, 0);
470 } else if (ejsVarIsObject(argv[i])) {
472 /* MOB -- OPT. When we have proper scope chains, we should just
473 refer to the module and not copy */
474 pp = ejsGetFirstProperty(argv[i], EJS_ENUM_ALL);
476 ejsSetProperty(ep, thisObj, pp->name, ejsGetVarPtr(pp));
477 pp = ejsGetNextProperty(pp, EJS_ENUM_ALL);
482 buf = ejsVarToString(ep, argv[i]);
483 rc = ejsEvalScript(ep, buf, 0);
487 ejsCloseBlock(ep, fid);
491 ejsCloseBlock(ep, fid);
495 /******************************************************************************/
497 * Create the object class
500 int ejsDefineObjectClass(Ejs *ep)
503 EjsProperty *objectProp, *protoProp;
504 EjsVar *op, *globalClass;
507 * Must specially hand-craft the object class as it is the base class
510 op = ejsCreateObjVar(ep);
512 return MPR_ERR_CANT_CREATE;
514 ejsSetClassName(ep, op, "Object");
517 * Don't use a constructor for objects for speed
519 ejsMakeClassNoConstructor(op);
522 * MOB -- should mark properties as public / private and class or instance.
524 ejsDefineCMethod(ep, op, "clone", cloneMethod, EJS_NO_LOCAL);
525 ejsDefineCMethod(ep, op, "toString", toStringMethod, EJS_NO_LOCAL);
526 ejsDefineCMethod(ep, op, "valueOf", valueOfMethod, EJS_NO_LOCAL);
527 ejsDefineCMethod(ep, op, "mixin", mixinMethod, EJS_NO_LOCAL);
529 ejsDefineCAccessors(ep, op, "hash", hashGetAccessor, 0, EJS_NO_LOCAL);
530 ejsDefineCAccessors(ep, op, "baseClass", classGetAccessor, 0, EJS_NO_LOCAL);
533 * MOB -- make this an accessor
535 protoProp = ejsSetProperty(ep, op, "prototype", op);
536 if (protoProp == 0) {
538 return MPR_ERR_CANT_CREATE;
542 * Setup the internal methods. Most classes will never override these.
543 * The XML class will. We rely on talloc to free internal. Use "ep" as
544 * the parent as we need "methods" to live while the interpreter lives.
546 methods = mprAllocTypeZeroed(ep, EjsMethods);
547 op->objectState->methods = methods;
549 methods->createProperty = createObjProperty;
550 methods->deleteProperty = deleteObjProperty;
551 methods->getProperty = getObjProperty;
552 methods->setProperty = setObjProperty;
554 objectProp = ejsSetPropertyAndFree(ep, ep->global, "Object", op);
557 * Change the global class to use Object's methods
559 globalClass = ep->service->globalClass;
560 globalClass->objectState->methods = methods;
561 globalClass->objectState->baseClass = ejsGetVarPtr(protoProp);
563 ep->objectClass = ejsGetVarPtr(objectProp);
565 if (ejsObjHasErrors(ejsGetVarPtr(objectProp))) {
567 return MPR_ERR_CANT_CREATE;
572 /******************************************************************************/
575 void ejsObjectDummy() {}
577 /******************************************************************************/
578 #endif /* BLD_FEATURE_EJS */
586 * vim600: sw=4 ts=4 fdm=marker