r7124: fixed a bug in array construction (see ECMA standard section 15.4.2.2)
[samba.git] / source / lib / ejs / ejsProcs.c
1 /*
2  *      @file   ejsProc.c
3  *      @brief  EJS support functions
4  */
5 /********************************* Copyright **********************************/
6 /*
7  *      @copy   default.g
8  *      
9  *      Copyright (c) Mbedthis Software LLC, 2003-2005. All Rights Reserved.
10  *      Portions Copyright (c) GoAhead Software, 1995-2000. 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        "lib/ejs/ejsInternal.h"
38
39 #if BLD_FEATURE_EJS
40
41 /****************************** Forward Declarations **************************/
42 /*
43  *      Object constructors
44  */
45 static int              objectConsProc(EjsHandle eid, int argc, MprVar **argv);
46 static int              arrayConsProc(EjsHandle eid, int argc, MprVar **argv);
47 static int              booleanConsProc(EjsHandle eid, int argc, MprVar **agv);
48 static int              numberConsProc(EjsHandle eid, int argc, MprVar **argv);
49 static int              stringConsProc(EjsHandle eid, int argc, MprVar **argv);
50
51 /*
52  *      Core functions
53  */
54 static int              toStringProc(EjsHandle eid, int argc, MprVar **argv);
55 static int              valueOfProc(EjsHandle eid, int argc, MprVar **argv);
56
57 /*
58  *      Triggers
59  */
60 static MprVarTriggerStatus lengthTrigger(MprVarTriggerOp op, 
61         MprProperties *parentProperties, MprVar *prop, MprVar *newValue,
62         bool copyRef);
63
64 /******************************************************************************/
65 /*
66  *      Routine to create the base common to all object types
67  */
68
69 MprVar ejsCreateObj(const char *name, int hashSize)
70 {
71         MprVar  o;
72
73         o = mprCreateObjVar(name, hashSize);
74         if (o.type == MPR_TYPE_UNDEFINED) {
75                 mprAssert(0);
76                 return o;
77         }
78
79         mprCreatePropertyValue(&o, "toString", 
80                 mprCreateCFunctionVar(toStringProc, 0, MPR_VAR_SCRIPT_HANDLE));
81         mprCreatePropertyValue(&o, "valueOf", 
82                 mprCreateCFunctionVar(valueOfProc, 0, MPR_VAR_SCRIPT_HANDLE));
83         return o;
84 }
85
86 /******************************************************************************/
87 /*
88  *      Routine to destroy a variable
89  */
90
91 bool ejsDestroyVar(MprVar *obj)
92 {
93         return mprDestroyVar(obj);
94 }
95
96 /******************************************************************************/
97 /*
98  *      Routine to create the base array type
99  */
100
101 MprVar ejsCreateArray(const char *name, int size)
102 {
103         MprVar  obj, *lp, undef;
104         char    idx[16];
105         int             i;
106
107         /*      Sanity limit for size of hash table */
108
109         obj = ejsCreateObj(name, max(size, 503));
110         if (obj.type == MPR_TYPE_UNDEFINED) {
111                 mprAssert(0);
112                 return obj;
113         }
114
115         undef = mprCreateUndefinedVar();
116         for (i = 0; i < size; i++) {
117                 mprItoa(i, idx, sizeof(idx));
118                 mprCreateProperty(&obj, idx, &undef);
119         }
120
121         lp = mprCreatePropertyValue(&obj, "length", mprCreateIntegerVar(size));
122         mprAssert(lp);
123
124         mprSetVarReadonly(lp, 1);
125         mprAddVarTrigger(lp, lengthTrigger);
126
127         return obj;
128 }
129
130 /******************************************************************************/
131 /******************************** Constructors ********************************/
132 /******************************************************************************/
133 /*
134  *      Object constructor. Nothing really done here. For future expansion.
135  */
136
137 static int objectConsProc(EjsHandle eid, int argc, MprVar **argv)
138 {
139 #if XX_UNUSED_XX
140         MprVar  *obj;
141         Ejs             *ep;
142
143         if((ep = ejsPtr(eid)) == NULL) {
144                 return -1;
145         }
146
147         obj = mprGetProperty(ep->local, "this", 0);
148         mprAssert(obj);
149 #endif
150         return 0;
151 }
152
153 /******************************************************************************/
154 /*
155  *      Array constructor
156  */
157
158 static int arrayConsProc(EjsHandle eid, int argc, MprVar **argv)
159 {
160         MprVar  *obj, *lp, undef;
161         Ejs             *ep;
162         char    idx[16];
163         int             i, max;
164
165         objectConsProc(eid, argc, argv);
166
167         if((ep = ejsPtr(eid)) == NULL) {
168                 return -1;
169         }
170         obj = mprGetProperty(ep->local, "this", 0);
171         mprAssert(obj);
172
173
174         if (argc == 1 && mprVarIsNumber(argv[0]->type)) {
175                 /*
176                  *      x = new Array(size);
177                  */
178                 undef = mprCreateUndefinedVar();
179                 max = (int) mprVarToInteger(argv[0]);
180                 for (i = 0; i < max; i++) {
181                         mprItoa(i, idx, sizeof(idx));
182                         mprCreateProperty(obj, idx, &undef);
183                 }
184         } else {
185                 /*
186                  *      x = new Array(element0, element1, ..., elementN):
187                  */
188                 max = argc;
189                 for (i = 0; i < max; i++) {
190                         mprItoa(i, idx, sizeof(idx));
191                         mprCreateProperty(obj, idx, argv[i]);
192                 }
193         }
194
195         lp = mprCreatePropertyValue(obj, "length", mprCreateIntegerVar(max));
196         mprAssert(lp);
197
198         mprSetVarReadonly(lp, 1);
199         mprAddVarTrigger(lp, lengthTrigger);
200
201         return 0;
202 }
203
204 /******************************************************************************/
205 /*
206  *      Boolean constructor
207  */
208
209 static int booleanConsProc(EjsHandle eid, int argc, MprVar **argv)
210 {
211         objectConsProc(eid, argc, argv);
212         return 0;
213 }
214
215 /******************************************************************************/
216 #if FUTURE
217 /*
218  *      Date constructor
219  */
220
221 static int dateConsProc(EjsHandle eid, int argc, MprVar **argv)
222 {
223         objectConsProc(eid, argc, argv);
224         return 0;
225 }
226
227 #endif
228 /******************************************************************************/
229 /*
230  *      Number constructor
231  */
232
233 static int numberConsProc(EjsHandle eid, int argc, MprVar **argv)
234 {
235         objectConsProc(eid, argc, argv);
236         return 0;
237 }
238
239 /******************************************************************************/
240 /*
241  *      String constructor
242  */
243
244 static int stringConsProc(EjsHandle eid, int argc, MprVar **argv)
245 {
246         objectConsProc(eid, argc, argv);
247         return 0;
248 }
249
250 /******************************************************************************/
251 /********************************** Functions *********************************/
252 /******************************************************************************/
253
254 static int toStringProc(EjsHandle eid, int argc, MprVar **argv)
255 {
256         MprVar  *obj;
257         Ejs             *ep;
258         char    *buf;
259         int             radix;
260
261         if (argc == 0) {
262                 radix = 10;
263
264         } else if (argc == 1) {
265                 radix = (int) mprVarToInteger(argv[0]);
266
267         } else {
268                 mprAssert(0);
269                 return -1;
270         }
271
272         if((ep = ejsPtr(eid)) == NULL) {
273                 return -1;
274         }
275
276         obj = mprGetProperty(ep->local, "this", 0);
277         mprAssert(obj);
278
279         mprVarToString(&buf, MPR_MAX_STRING, 0, obj);
280         mprCopyVarValue(&ep->result, mprCreateStringVar(buf, 0), MPR_SHALLOW_COPY);
281         mprFree(buf);
282
283         return 0;
284 }
285
286 /******************************************************************************/
287
288 static int valueOfProc(EjsHandle eid, int argc, MprVar **argv)
289 {
290         MprVar  *obj;
291         Ejs             *ep;
292
293         if (argc != 0) {
294                 mprAssert(0);
295                 return -1;
296         }
297
298         if((ep = ejsPtr(eid)) == NULL) {
299                 return -1;
300         }
301
302         obj = mprGetProperty(ep->local, "this", 0);
303         mprAssert(obj);
304
305         switch (obj->type) {
306         default:
307         case MPR_TYPE_UNDEFINED:
308         case MPR_TYPE_NULL:
309         case MPR_TYPE_CFUNCTION:
310         case MPR_TYPE_OBJECT:
311         case MPR_TYPE_FUNCTION:
312         case MPR_TYPE_STRING_CFUNCTION:
313                 mprCopyVar(&ep->result, obj, MPR_SHALLOW_COPY);
314                 break;
315
316         case MPR_TYPE_STRING:
317                 mprCopyVarValue(&ep->result, mprCreateIntegerVar(atoi(obj->string)), 0);
318                 break;
319
320         case MPR_TYPE_BOOL:
321         case MPR_TYPE_INT:
322 #if BLD_FEATURE_INT64
323         case MPR_TYPE_INT64:
324 #endif
325 #if BLD_FEATURE_FLOATING_POINT
326         case MPR_TYPE_FLOAT:
327 #endif
328                 mprCopyVar(&ep->result, obj, 0);
329                 break;
330         } 
331         return 0;
332 }
333
334 /******************************************************************************/
335 /*
336  *      Var access trigger on the Array.length property. Return the count of
337  *      enumerable properties (don't count functions).
338  */
339
340 static MprVarTriggerStatus lengthTrigger(MprVarTriggerOp op, 
341         MprProperties *parentProperties, MprVar *prop, MprVar *newValue, 
342         bool copyRef)
343 {
344         switch (op) {
345         case MPR_VAR_READ:
346                 /*
347                  *      Subtract one for the length property
348                  *      FUTURE -- need an API to access parentProperties
349                  *      FUTURE -- contradiction to be read-only yet allow USE_NEW_VALUE.
350                  *              API needs finer control.
351                  */
352                 *newValue = mprCreateIntegerVar(parentProperties->numDataItems - 1);
353                 return MPR_TRIGGER_USE_NEW_VALUE;
354
355         case MPR_VAR_WRITE:
356                 return MPR_TRIGGER_ABORT;
357
358         case MPR_VAR_CREATE_PROPERTY:
359         case MPR_VAR_DELETE_PROPERTY:
360         case MPR_VAR_DELETE:
361         default:
362                 break;
363         }
364         return MPR_TRIGGER_PROCEED;
365 }
366
367 /******************************************************************************/
368 /**************************** Extension Functions *****************************/
369 /******************************************************************************/
370 /*
371  *      Assert 
372  */
373
374 static int assertProc(EjsHandle eid, int argc, MprVar **argv)
375 {
376         bool    b;
377
378         if (argc < 1) {
379                 ejsSetErrorMsg(eid, "usage: assert(condition)\n");
380                 return -1;
381         }
382         b = mprVarToBool(argv[0]);
383         if (b == 0) {
384                 ejsSetErrorMsg(eid, "Assertion failure\n");
385                 return -1;
386         }
387         ejsSetReturnValue(eid, mprCreateBoolVar(b));
388         return 0;
389 }
390
391 /******************************************************************************/
392 /*
393  *      Exit 
394  */
395
396 static int exitProc(EjsHandle eid, int argc, MprVar **argv)
397 {
398         int                     status;
399
400         if (argc < 1) {
401                 ejsSetErrorMsg(eid, "usage: exit(status)\n");
402                 return -1;
403         }
404         status = (int) mprVarToInteger(argv[0]);
405         ejsSetExitStatus(eid, status);
406
407         ejsSetReturnValue(eid, mprCreateStringVar("", 0));
408         return 0;
409 }
410
411 /******************************************************************************/
412
413 static void printVar(MprVar *vp, int recurseCount, int indent)
414 {
415         MprVar  *np;
416         char    *buf;
417         int             i;
418
419         if (recurseCount > 5) {
420                 write(1, "Skipping - recursion too deep\n", 29);
421                 return;
422         }
423
424         for (i = 0; i < indent; i++) {
425                 write(1, "  ", 2);
426         }
427
428         if (vp->type == MPR_TYPE_OBJECT) {
429                 if (vp->name) {
430                         write(1, vp->name, strlen(vp->name));
431                 } else {
432                         write(1, "unknown", 7);
433                 }
434                 write(1, ": {\n", 4);
435                 np = mprGetFirstProperty(vp, MPR_ENUM_DATA);
436                 while (np) {
437                         if (strcmp(np->name, "local") == 0 ||
438                                         strcmp(np->name, "global") == 0 ||
439                                         strcmp(np->name, "this") == 0) {
440                                 np = mprGetNextProperty(vp, np, MPR_ENUM_DATA);
441                                 continue;
442                         }
443                         printVar(np, recurseCount + 1, indent + 1);
444                         np = mprGetNextProperty(vp, np, MPR_ENUM_DATA);
445                         if (np) {
446                                 write(1, ",\n", 2);
447                         }
448                 }
449                 write(1, "\n", 1);
450                 for (i = 0; i < indent; i++) {
451                         write(1, "  ", 2);
452                 }
453                 write(1, "}", 1);
454
455         } else {
456                 if (vp->name) {
457                         write(1, vp->name, strlen(vp->name));
458                 } else {
459                         write(1, "unknown", 7);
460                 }
461                 write(1, ": ", 2);
462
463                 /*      FUTURE -- other types ? */
464                 mprVarToString(&buf, MPR_MAX_STRING, 0, vp);
465                 if (vp->type == MPR_TYPE_STRING) {
466                         write(1, "\"", 1);
467                 }
468                 write(1, buf, strlen(buf));
469                 if (vp->type == MPR_TYPE_STRING) {
470                         write(1, "\"", 1);
471                 }
472                 mprFree(buf);
473         }
474 }
475
476 /******************************************************************************/
477 /*
478  *      Print the args to stdout
479  */
480
481 static int printVarsProc(EjsHandle eid, int argc, MprVar **argv)
482 {
483         MprVar  *vp;
484         char    *buf;
485         int             i;
486
487         for (i = 0; i < argc; i++) {
488                 vp = argv[i];
489                 switch (vp->type) {
490                 case MPR_TYPE_OBJECT:
491                         printVar(vp, 0, 0);
492                         break;
493                 default:
494                         mprVarToString(&buf, MPR_MAX_STRING, 0, vp);
495                         write(1, buf, strlen(buf));
496                         mprFree(buf);
497                         break;
498                 }
499         }
500         write(1, "\n", 1);
501
502         ejsSetReturnValue(eid, mprCreateStringVar("", 0));
503         return 0;
504 }
505
506 /******************************************************************************/
507 /*
508  *      Print the args to stdout
509  */
510
511 static int printProc(EjsHandle eid, int argc, MprVar **argv)
512 {
513         char    *buf;
514         int             i;
515
516         for (i = 0; i < argc; i++) {
517                 mprVarToString(&buf, MPR_MAX_STRING, 0, argv[i]);
518                 write(1, buf, strlen(buf));
519                 mprFree(buf);
520         }
521         return 0;
522 }
523
524 /******************************************************************************/
525 /*
526  *      println
527  */
528
529 static int printlnProc(EjsHandle eid, int argc, MprVar **argv)
530 {
531         printProc(eid, argc, argv);
532         write(1, "\n", 1);
533         return 0;
534 }
535
536 /******************************************************************************/
537 /*
538  *      Trace 
539  */
540
541 static int traceProc(EjsHandle eid, int argc, char **argv)
542 {
543         if (argc == 1) {
544                 mprLog(0, "%s", argv[0]);
545
546         } else if (argc == 2) {
547                 mprLog(atoi(argv[0]), "%s", argv[1]);
548
549         } else {
550                 ejsSetErrorMsg(eid, "Usage: trace([level], message)");
551                 return -1;
552         }
553         ejsSetReturnString(eid, "");
554         return 0;
555 }
556
557 /******************************************************************************/
558 /*
559  *      Return the object reference count
560  */
561
562 static int refCountProc(EjsHandle eid, int argc, MprVar **argv)
563 {
564         MprVar          *vp;
565         int                     count;
566
567         vp = argv[0];
568         if (vp->type == MPR_TYPE_OBJECT) {
569                 count = mprGetVarRefCount(vp);
570                 ejsSetReturnValue(eid, mprCreateIntegerVar(count));
571         } else {
572                 ejsSetReturnValue(eid, mprCreateIntegerVar(0));
573         }
574
575         return 0;
576 }
577
578 /******************************************************************************/
579 /*
580  *      Evaluate a sub-script. It is evaluated in the same variable scope as
581  *      the calling script / function.
582  */
583
584 static int evalScriptProc(EjsHandle eid, int argc, MprVar **argv)
585 {
586         MprVar          *arg;
587         char            *emsg;
588         int                     i;
589
590         ejsSetReturnValue(eid, mprCreateUndefinedVar());
591
592         for (i = 0; i < argc; i++) {
593                 arg = argv[i];
594                 if (arg->type != MPR_TYPE_STRING) {
595                         continue;
596                 }
597                 if (ejsEvalScript(eid, arg->string, 0, &emsg) < 0) {
598                         ejsSetErrorMsg(eid, "%s", emsg);
599                         mprFree(emsg);
600                         return -1;
601                 }
602         }
603         /*
604          *      Return with the value of the last expression
605          */
606         return 0;
607 }
608
609 /******************************************************************************/
610 /******************************************************************************/
611 /******************************************************************************/
612 /*
613  *      Define the standard properties and functions inherited by all script engines.
614  */
615
616 int ejsDefineStandardProperties(MprVar *obj)
617 {
618 #if BLD_FEATURE_FLOATING_POINT
619         double  d = 0.0;
620
621         /*      FUTURE - this generates warnings on some systems. This is okay. */
622
623         mprCreatePropertyValue(obj, "NaN", mprCreateFloatVar(0.0 / d));
624         d = MAX_FLOAT;
625         mprCreatePropertyValue(obj, "Infinity", mprCreateFloatVar(d * d));
626 #endif
627         mprCreatePropertyValue(obj, "null", mprCreateNullVar());
628         mprCreatePropertyValue(obj, "undefined", mprCreateUndefinedVar());
629         mprCreatePropertyValue(obj, "true", mprCreateBoolVar(1));
630         mprCreatePropertyValue(obj, "false", mprCreateBoolVar(0));
631
632 #if BLD_FEATURE_LEGACY_API
633         /*
634          *      DEPRECATED: 2.0.
635          *      So that ESP/ASP can ignore "language=javascript" statements
636          */
637         mprCreatePropertyValue(obj, "javascript", mprCreateIntegerVar(0));
638 #endif
639
640         /*
641          *      Extension functions
642          */
643         mprCreatePropertyValue(obj, "assert", 
644                 mprCreateCFunctionVar(assertProc, 0, MPR_VAR_SCRIPT_HANDLE));
645         mprCreatePropertyValue(obj, "eval", 
646                 mprCreateCFunctionVar(evalScriptProc, 0, MPR_VAR_SCRIPT_HANDLE));
647         mprCreatePropertyValue(obj, "exit", 
648                 mprCreateCFunctionVar(exitProc, 0, MPR_VAR_SCRIPT_HANDLE));
649         mprCreatePropertyValue(obj, "refCount", 
650                 mprCreateCFunctionVar(refCountProc, 0, MPR_VAR_SCRIPT_HANDLE));
651         mprCreatePropertyValue(obj, "print", 
652                 mprCreateCFunctionVar(printProc, 0, MPR_VAR_SCRIPT_HANDLE));
653         mprCreatePropertyValue(obj, "println", 
654                 mprCreateCFunctionVar(printlnProc, 0, MPR_VAR_SCRIPT_HANDLE));
655         mprCreatePropertyValue(obj, "printVars", 
656                 mprCreateCFunctionVar(printVarsProc,0, MPR_VAR_SCRIPT_HANDLE));
657         mprCreatePropertyValue(obj, "trace", 
658                 mprCreateStringCFunctionVar(traceProc, 0, MPR_VAR_SCRIPT_HANDLE));
659
660         /*
661          *      Constructors
662          */
663         mprCreatePropertyValue(obj, "Array", 
664                 mprCreateCFunctionVar(arrayConsProc, 0, MPR_VAR_SCRIPT_HANDLE));
665         mprCreatePropertyValue(obj, "Boolean",
666                 mprCreateCFunctionVar(booleanConsProc, 0, MPR_VAR_SCRIPT_HANDLE));
667         mprCreatePropertyValue(obj, "Object", 
668                 mprCreateCFunctionVar(objectConsProc, 0, MPR_VAR_SCRIPT_HANDLE));
669         mprCreatePropertyValue(obj, "Number", 
670                 mprCreateCFunctionVar(numberConsProc, 0, MPR_VAR_SCRIPT_HANDLE));
671         mprCreatePropertyValue(obj, "String", 
672                 mprCreateCFunctionVar(stringConsProc, 0, MPR_VAR_SCRIPT_HANDLE));
673
674         /*      mprCreatePropertyValue(obj, "Date", 
675          *              mprCreateCFunctionVar(dateConsProc, 0, MPR_VAR_SCRIPT_HANDLE));
676          *      mprCreatePropertyValue(obj, "Regexp", 
677          *              mprCreateCFunctionVar(regexpConsProc, 0, MPR_VAR_SCRIPT_HANDLE));
678          */
679
680         /*
681          *      Can we use on var x = "string text";
682          */
683         return 0;
684 }
685
686 /******************************************************************************/
687
688 #else
689 void ejsProcsDummy() {}
690
691 /******************************************************************************/
692 #endif /* BLD_FEATURE_EJS */
693
694 /*
695  * Local variables:
696  * tab-width: 4
697  * c-basic-offset: 4
698  * End:
699  * vim:tw=78
700  * vim600: sw=4 ts=4 fdm=marker
701  * vim<600: sw=4 ts=4
702  */