001: /*
002: * Copyright (c) 1998-2006 Caucho Technology -- all rights reserved
003: *
004: * This file is part of Resin(R) Open Source
005: *
006: * Each copy or derived work must preserve the copyright notice and this
007: * notice unmodified.
008: *
009: * Resin Open Source is free software; you can redistribute it and/or modify
010: * it under the terms of the GNU General Public License as published by
011: * the Free Software Foundation; either version 2 of the License, or
012: * (at your option) any later version.
013: *
014: * Resin Open Source is distributed in the hope that it will be useful,
015: * but WITHOUT ANY WARRANTY; without even the implied warranty of
016: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE, or any warranty
017: * of NON-INFRINGEMENT. See the GNU General Public License for more
018: * details.
019: *
020: * You should have received a copy of the GNU General Public License
021: * along with Resin Open Source; if not, write to the
022: * Free SoftwareFoundation, Inc.
023: * 59 Temple Place, Suite 330
024: * Boston, MA 02111-1307 USA
025: *
026: * @author Scott Ferguson
027: */
028:
029: package com.caucho.es;
030:
031: import java.util.Enumeration;
032: import java.util.Iterator;
033:
034: /**
035: * Implementation class representing a call context.
036: */
037: public final class Call extends ESBase {
038: static ESId ARGUMENTS = ESId.intern("arguments");
039: static ESId ARRAY = ESId.intern("Array");
040:
041: Call caller;
042: ESObject callThis;
043: int callLength;
044: ESBase callee;
045:
046: public ESBase[] stack;
047: int top;
048:
049: public ESGlobal global;
050: ESBase[] scope;
051: int scopeLength;
052:
053: public ESBase[] values;
054:
055: ESObject aux;
056:
057: Call child; // just a cache
058:
059: /**
060: * Create a new context object
061: */
062: Call() {
063: prototype = esBase;
064:
065: stack = new ESBase[64];
066: scope = new ESBase[16];
067: values = new ESBase[64];
068: top = 0;
069: }
070:
071: void clear() {
072: aux = null;
073: child = null;
074: top = 0;
075: }
076:
077: public Call getCall() {
078: Call child = this .child;
079:
080: if (child == null)
081: child = this .child = new Call();
082:
083: child.caller = this ;
084:
085: child.global = global;
086:
087: return child;
088: }
089:
090: Global getGlobalProto() {
091: return Global.getGlobalProto();
092: }
093:
094: public ESBase wrap(Object o) throws Throwable {
095: return Global.wrap(o);
096: }
097:
098: public ESBase wrap(long n) throws Throwable {
099: return ESNumber.create(n);
100: }
101:
102: public ESBase wrapClass(Class cl) throws Throwable {
103: return Global.getGlobalProto().classWrap(cl);
104: }
105:
106: // public ESGlobal getGlobal() { return Global.getGlobal().global; }
107:
108: final ESBase getArg(int i) {
109: return stack[top + i];
110: }
111:
112: public final ESBase getArg(int i, int len) {
113: return i < len ? stack[top + i] : esUndefined;
114: }
115:
116: public final int getArgInt32(int i, int len) throws Throwable {
117: return i < len ? stack[top + i].toInt32() : 0;
118: }
119:
120: public final double getArgNum(int i, int len) throws Throwable {
121: return i < len ? stack[top + i].toNum() : (0.0 / 0.0);
122: }
123:
124: public final String getArgString(int i, int len) throws Throwable {
125: return i < len ? stack[top + i].toJavaString() : null;
126: }
127:
128: public final Object getArgObject(int i, int len) throws Throwable {
129: return i < len ? stack[top + i].toJavaObject() : null;
130: }
131:
132: public ESObject createObject() {
133: return new ESObject("Object", getGlobalProto().objProto);
134: }
135:
136: public ESBase createDate(long time) {
137: return new ESDate(time, getGlobalProto().dateProto);
138: }
139:
140: public String printf(int length) throws Throwable {
141: return Printf.sprintf(this , length);
142: }
143:
144: void setArg(int i, ESBase obj) {
145: stack[top + i] = obj;
146: }
147:
148: public final ESObject getThis() throws Throwable {
149: return stack[top - 1].toObject();
150: }
151:
152: public final Object getThisWrapper() throws Throwable {
153: return stack[top - 1].toJavaObject();
154: }
155:
156: void setThis(ESBase obj) {
157: stack[top - 1] = obj;
158: }
159:
160: public ESGlobal getGlobal() {
161: return global;
162: }
163:
164: public final ESObject getCallThis() throws Throwable {
165: ESBase obj = caller.stack[caller.top - 1];
166:
167: return obj.toObject();
168: }
169:
170: ESBase getContext() {
171: return scope[scopeLength - 1];
172: }
173:
174: ESBase getFunctionContext() {
175: if (caller == null || caller.scopeLength == 0)
176: return global;
177: else
178: return caller.scope[caller.scopeLength - 1];
179: }
180:
181: public void pushScope(ESBase value) {
182: scope[scopeLength++] = value;
183: }
184:
185: public void popScope() {
186: scopeLength--;
187: }
188:
189: public ESObject getEval() {
190: return (ESObject) scope[scopeLength - 1];
191: }
192:
193: public ESObject createArg(ESId[] args, int length) throws Throwable {
194: ESObject arg = ESArguments.create(args, this , length);
195:
196: scope[scopeLength++] = arg;
197:
198: return arg;
199: }
200:
201: public void setProperty(ESString name, ESBase value)
202: throws Throwable {
203: //setProperty(name, value);
204: }
205:
206: public ESBase delete(ESString key) throws Throwable {
207: return aux == null ? ESBoolean.FALSE : aux.delete(key);
208: }
209:
210: public ESBase findScopeProperty(ESString id) throws Throwable {
211: for (int i = scopeLength - 1; i > 0; i--) {
212: if (scope[i].getProperty(id) != esEmpty)
213: return scope[i];
214: }
215:
216: return global;
217: }
218:
219: public ESBase scopeTypeof(ESString id) throws Throwable {
220: for (int i = scopeLength - 1; i >= 0; i--) {
221: ESBase value;
222: if ((value = scope[i].getProperty(id)) != esEmpty)
223: return value.typeof();
224: }
225:
226: return esEmpty.typeof();
227: }
228:
229: public static ESBase setProperty(ESBase base, ESString field,
230: ESBase value) throws Throwable {
231: base.setProperty(field, value);
232:
233: return value;
234: }
235:
236: public static ESBase doVoid(ESBase value) {
237: return ESBase.esUndefined;
238: }
239:
240: public ESBase array(ESBase value) throws Throwable {
241: ESBase array = call(global, ARRAY, 0);
242: array.setProperty(0, value);
243: return array;
244: }
245:
246: public static ESBase comma(ESBase left, ESBase right) {
247: return right;
248: }
249:
250: public static ESBase _first(ESBase left, ESBase right)
251: throws Throwable {
252: // This is only used for postfix
253: if (!(left instanceof ESNumber))
254: return ESNumber.create(left.toNum());
255: else
256: return left;
257: }
258:
259: public static double _first(double left, double right)
260: throws Throwable {
261: return left;
262: }
263:
264: /**
265: * Returns the first value in a tuple. Used
266: *
267: * @param left the first value
268: * @param right the right value
269: *
270: * @return the first value.
271: */
272: public static int _first(int left, int right) throws Throwable {
273: return left;
274: }
275:
276: public static double _pre(ESBase expr, ESString field, int inc)
277: throws Throwable {
278: double oldVal = expr.getProperty(field).toNum();
279: ESNumber newVal = ESNumber.create(oldVal + inc);
280:
281: expr.setProperty(field, newVal);
282:
283: return oldVal + inc;
284: }
285:
286: public static double _post(ESBase expr, ESString field, int inc)
287: throws Throwable {
288: double oldVal = expr.getProperty(field).toNum();
289: ESNumber newVal = ESNumber.create(oldVal + inc);
290:
291: expr.setProperty(field, newVal);
292:
293: return oldVal;
294: }
295:
296: public double _pre(ESString field, int inc) throws Throwable {
297: double oldVal = getScopeProperty(field).toNum();
298: ESNumber newVal = ESNumber.create(oldVal + inc);
299:
300: setScopeProperty(field, newVal);
301:
302: return oldVal + inc;
303: }
304:
305: public double _post(ESString field, int inc) throws Throwable {
306: double oldVal = getScopeProperty(field).toNum();
307: ESNumber newVal = ESNumber.create(oldVal + inc);
308:
309: setScopeProperty(field, newVal);
310:
311: return oldVal;
312: }
313:
314: public ESBase setGlobalProperty(ESString id, ESBase value)
315: throws Throwable {
316: global.setProperty(id, value);
317:
318: return value;
319: }
320:
321: /**
322: * Returns the global variable of the id, throwing an exception if
323: * the it's undefined.
324: */
325: public ESBase getGlobalVariable(ESString id) throws Throwable {
326: ESBase value = global.getProperty(id);
327: if (value == ESBase.esEmpty)
328: throw new ESUndefinedException("undefined variable `" + id
329: + "'");
330:
331: return value;
332: }
333:
334: public ESBase getScopeProperty(ESString id) throws Throwable {
335: for (int i = scopeLength - 1; i >= 0; i--) {
336: ESBase value;
337: if ((value = scope[i].getProperty(id)) != esEmpty) {
338: return value;
339: }
340: }
341:
342: throw new ESUndefinedException("undefined variable `" + id
343: + "'");
344: }
345:
346: public void fillScope() {
347: if (callee instanceof ESClosure) {
348: ESClosure closure = (ESClosure) callee;
349:
350: if (closure.scopeLength == 0) {
351: scope[0] = caller.global;
352: scopeLength = 1;
353: return;
354: }
355: for (int i = 0; i < closure.scopeLength; i++) {
356: scope[i] = closure.scope[i];
357: }
358: scopeLength = closure.scopeLength;
359: } else {
360: scope[0] = caller.global;
361: scopeLength = 1;
362: }
363: }
364:
365: public ESBase hasScopeProperty(ESString id) throws Throwable {
366: for (int i = scopeLength - 1; i >= 0; i--) {
367: ESBase value;
368: if ((value = scope[i].getProperty(id)) != esEmpty)
369: return value;
370: }
371:
372: return esEmpty;
373: }
374:
375: public ESBase setScopeProperty(ESString id, ESBase value)
376: throws Throwable {
377: if (value == esEmpty)
378: value = esUndefined;
379:
380: for (int i = scopeLength - 1; i > 0; i--) {
381: if (scope[i].getProperty(id) != esEmpty) {
382: scope[i].setProperty(id, value);
383: return value;
384: }
385: }
386:
387: global.setProperty(id, value);
388:
389: return value;
390: }
391:
392: public ESBase deleteScopeProperty(ESString id) throws Throwable {
393: for (int i = scopeLength - 1; i > 0; i--) {
394: if (scope[i].getProperty(id) != esEmpty)
395: return scope[i].delete(id);
396: }
397:
398: return global.delete(id);
399: }
400:
401: /*
402: public ESBase startCallScopeProperty(ESString id, int i) throws Throwable
403: {
404: top = i + 1;
405:
406: for (int j = scopeLength - 1; j >= 0; j--) {
407: ESBase value;
408:
409: if ((value = scope[j].getProperty(id)) != esEmpty) {
410: stack[i] = global;
411: return value;
412: }
413: }
414:
415: throw new ESUndefinedException("undefined call `" + id + "'");
416: }
417: */
418:
419: public int arg(int i, ESBase arg) {
420: stack[i + 1] = arg;
421:
422: return 1;
423: }
424:
425: public ESBase callScope(ESString id, int i) throws Throwable {
426: top = i + 1;
427:
428: int scopeLength = caller.scopeLength;
429: ESBase[] scope = caller.scope;
430: for (int j = scopeLength - 1; j >= 0; j--) {
431: ESBase value;
432:
433: if ((value = scope[j].getProperty(id)) != esEmpty) {
434: callee = value;
435: stack[i] = scope[j];
436: return value.call(this , 0);
437: }
438: }
439:
440: throw new ESUndefinedException("undefined call `" + id + "'");
441: }
442:
443: public ESBase callScope(ESString id, int i, ESBase a)
444: throws Throwable {
445: top = i + 1;
446:
447: int scopeLength = caller.scopeLength;
448: ESBase[] scope = caller.scope;
449: for (int j = scopeLength - 1; j >= 0; j--) {
450: ESBase value;
451:
452: if ((value = scope[j].getProperty(id)) != esEmpty) {
453: callee = value;
454: stack[i] = scope[j];
455: stack[i + 1] = a;
456: return value.call(this , 1);
457: }
458: }
459:
460: throw new ESUndefinedException("undefined call `" + id + "'");
461: }
462:
463: public ESBase callScope(ESString id, int i, ESBase a, ESBase b)
464: throws Throwable {
465: top = i + 1;
466:
467: int scopeLength = caller.scopeLength;
468: ESBase[] scope = caller.scope;
469: for (int j = scopeLength - 1; j >= 0; j--) {
470: ESBase value;
471:
472: if ((value = scope[j].getProperty(id)) != esEmpty) {
473: callee = value;
474: stack[i] = scope[j];
475: stack[i + 1] = a;
476: stack[i + 2] = b;
477: return value.call(this , 2);
478: }
479: }
480:
481: throw new ESUndefinedException("undefined call `" + id + "'");
482: }
483:
484: public ESBase callScope(ESString id, int i, ESBase a, ESBase b,
485: ESBase c, int length) throws Throwable {
486: top = i + 1;
487:
488: int scopeLength = caller.scopeLength;
489: ESBase[] scope = caller.scope;
490: for (int j = scopeLength - 1; j >= 0; j--) {
491: ESBase value;
492: if ((value = scope[j].getProperty(id)) != esEmpty) {
493: callee = value;
494: stack[i] = scope[j];
495: stack[i + 1] = a;
496: stack[i + 2] = b;
497: stack[i + 3] = c;
498: return value.call(this , length);
499: }
500: }
501:
502: throw new ESUndefinedException("undefined call `" + id + "'");
503: }
504:
505: public ESBase call(ESBase base, ESString name, int i)
506: throws Throwable {
507: top = i + 1;
508:
509: stack[i] = base;
510:
511: return base.call(this , 0, name);
512: }
513:
514: public ESBase call(ESBase base, ESString name, int i, ESBase a)
515: throws Throwable {
516: top = i + 1;
517:
518: stack[i] = base;
519: stack[i + 1] = a;
520:
521: return base.call(this , 1, name);
522: }
523:
524: public ESBase call(ESBase base, ESString name, int i, ESBase a,
525: ESBase b) throws Throwable {
526: top = i + 1;
527:
528: stack[i] = base;
529: stack[i + 1] = a;
530: stack[i + 2] = b;
531:
532: return base.call(this , 2, name);
533: }
534:
535: public ESBase call(ESBase base, ESString name, int i, ESBase a,
536: ESBase b, ESBase c, int length) throws Throwable {
537: top = i + 1;
538:
539: stack[i] = base;
540: stack[i + 1] = a;
541: stack[i + 2] = b;
542: stack[i + 3] = c;
543:
544: return base.call(this , length, name);
545: }
546:
547: public ESBase call(ESBase base, int i) throws Throwable {
548: top = i + 1;
549:
550: stack[i] = global;
551: callee = base;
552:
553: return base.call(this , 0);
554: }
555:
556: public ESBase call(ESBase base, int i, ESBase a) throws Throwable {
557: top = i + 1;
558:
559: stack[i + 1] = a;
560: stack[i] = global;
561: callee = base;
562: return base.call(this , 1);
563: }
564:
565: public ESBase call(ESBase base, int i, ESBase a, ESBase b)
566: throws Throwable {
567: top = i + 1;
568:
569: stack[i] = base;
570: stack[i + 1] = a;
571: stack[i + 2] = b;
572: stack[i] = global;
573: callee = base;
574: return base.call(this , 2);
575: }
576:
577: public ESBase call(ESBase base, int i, ESBase a, ESBase b,
578: ESBase c, int length) throws Throwable {
579: top = i + 1;
580:
581: stack[i] = base;
582: stack[i + 1] = a;
583: stack[i + 2] = b;
584: stack[i + 3] = c;
585: stack[i] = global;
586: callee = base;
587: return base.call(this , length);
588: }
589:
590: public ESBase newScope(ESString id, int i) throws Throwable {
591: top = i + 1;
592:
593: int scopeLength = caller.scopeLength;
594: ESBase[] scope = caller.scope;
595: for (int j = scopeLength - 1; j >= 0; j--) {
596: ESBase value;
597:
598: if ((value = scope[j].getProperty(id)) != esEmpty) {
599: callee = value;
600: stack[i] = global;
601: return value.construct(this , 0);
602: }
603: }
604:
605: throw new ESUndefinedException("undefined constructor `" + id
606: + "'");
607: }
608:
609: public ESBase newScope(ESString id, int i, ESBase a)
610: throws Throwable {
611: top = i + 1;
612:
613: int scopeLength = caller.scopeLength;
614: ESBase[] scope = caller.scope;
615: for (int j = scopeLength - 1; j >= 0; j--) {
616: ESBase value;
617:
618: if ((value = scope[j].getProperty(id)) != esEmpty) {
619: callee = value;
620: stack[i] = global;
621: stack[i + 1] = a;
622: return value.construct(this , 1);
623: }
624: }
625:
626: throw new ESUndefinedException("undefined constructor `" + id
627: + "'");
628: }
629:
630: public ESBase newScope(ESString id, int i, ESBase a, ESBase b)
631: throws Throwable {
632: top = i + 1;
633:
634: int scopeLength = caller.scopeLength;
635: ESBase[] scope = caller.scope;
636: for (int j = scopeLength - 1; j >= 0; j--) {
637: ESBase value;
638:
639: if ((value = scope[j].getProperty(id)) != esEmpty) {
640: callee = value;
641: stack[i] = global;
642: stack[i + 1] = a;
643: stack[i + 2] = b;
644: return value.construct(this , 2);
645: }
646: }
647:
648: throw new ESUndefinedException("undefined constructor `" + id
649: + "'");
650: }
651:
652: public ESBase newScope(ESString id, int i, ESBase a, ESBase b,
653: ESBase c, int length) throws Throwable {
654: top = i + 1;
655:
656: int scopeLength = caller.scopeLength;
657: ESBase[] scope = caller.scope;
658: for (int j = scopeLength - 1; j >= 0; j--) {
659: ESBase value;
660:
661: if ((value = scope[j].getProperty(id)) != esEmpty) {
662: callee = value;
663: stack[i] = global;
664: stack[i + 1] = a;
665: stack[i + 2] = b;
666: stack[i + 3] = c;
667: return value.construct(this , length);
668: }
669: }
670:
671: throw new ESUndefinedException("undefined constructor `" + id
672: + "'");
673: }
674:
675: public ESBase doNew(ESBase base, ESString name, int i)
676: throws Throwable {
677: top = i + 1;
678:
679: ESBase obj = base.getProperty(name);
680: stack[i] = base;
681: callee = obj;
682: if (obj != esEmpty)
683: return obj.construct(this , 0);
684: else
685: throw new ESUndefinedException("undefined constructor `"
686: + name + "'");
687: }
688:
689: public ESBase doNew(ESBase base, ESString name, int i, ESBase a)
690: throws Throwable {
691: top = i + 1;
692:
693: stack[i] = base;
694: stack[i + 1] = a;
695:
696: ESBase obj = base.getProperty(name);
697: callee = obj;
698: if (obj != esEmpty)
699: return obj.construct(this , 1);
700: else
701: throw new ESUndefinedException("undefined constructor `"
702: + name + "'");
703: }
704:
705: public ESBase doNew(ESBase base, ESString name, int i, ESBase a,
706: ESBase b) throws Throwable {
707: top = i + 1;
708:
709: stack[i] = base;
710: stack[i + 1] = a;
711: stack[i + 2] = b;
712:
713: ESBase obj = base.getProperty(name);
714: callee = obj;
715: if (obj != esEmpty)
716: return obj.construct(this , 2);
717: else
718: throw new ESUndefinedException("undefined constructor `"
719: + name + "'");
720: }
721:
722: public ESBase doNew(ESBase base, ESString name, int i, ESBase a,
723: ESBase b, ESBase c, int length) throws Throwable {
724: top = i + 1;
725:
726: stack[i] = base;
727: stack[i + 1] = a;
728: stack[i + 2] = b;
729: stack[i + 3] = c;
730:
731: ESBase obj = base.getProperty(name);
732: callee = obj;
733: if (obj != esEmpty)
734: return obj.construct(this , length);
735: else
736: throw new ESUndefinedException("undefined constructor `"
737: + name + "'");
738: }
739:
740: public ESBase doNew(ESBase base, int i) throws Throwable {
741: top = i + 1;
742:
743: stack[i] = global;
744: callee = base;
745: return base.construct(this , 0);
746: }
747:
748: public ESBase doNew(ESBase base, int i, ESBase a) throws Throwable {
749: top = i + 1;
750:
751: stack[i] = global;
752: stack[i + 1] = a;
753: callee = base;
754:
755: return base.construct(this , 1);
756: }
757:
758: public ESBase doNew(ESBase base, int i, ESBase a, ESBase b)
759: throws Throwable {
760: top = i + 1;
761:
762: stack[i] = global;
763: stack[i + 1] = a;
764: stack[i + 2] = b;
765: callee = base;
766:
767: return base.construct(this , 2);
768: }
769:
770: public ESBase doNew(ESBase base, int i, ESBase a, ESBase b,
771: ESBase c, int length) throws Throwable {
772: top = i + 1;
773:
774: stack[i] = global;
775: stack[i + 1] = a;
776: stack[i + 2] = b;
777: stack[i + 3] = c;
778: callee = base;
779:
780: return base.construct(this , length);
781: }
782:
783: public void free() {
784: clear();
785:
786: for (int i = stack.length - 1; i >= 0; i--)
787: stack[i] = null;
788: for (int i = scope.length - 1; i >= 0; i--)
789: scope[i] = null;
790: for (int i = values.length - 1; i >= 0; i--)
791: values[i] = null;
792: global = null;
793: }
794:
795: public static Iterator toESIterator(Iterator i) {
796: return new ESIterator(i);
797: }
798:
799: public static Iterator toESIterator(Enumeration e) {
800: return new ESEnumIterator(e);
801: }
802:
803: public static boolean matchException(ESBase test, Exception e) {
804: String testString;
805: try {
806: testString = test.toStr().toString();
807: } catch (Throwable foo) {
808: testString = "undefined";
809: }
810:
811: Class eClass = e.getClass();
812: String dotted = "." + test;
813:
814: for (; eClass != null; eClass = eClass.getSuperclass()) {
815: String eString = eClass.getName();
816:
817: if (testString.equals(eString) || eString.endsWith(dotted))
818: return true;
819: }
820:
821: return false;
822: }
823:
824: static class ESIterator implements Iterator {
825: Global resin;
826: Iterator i;
827:
828: public boolean hasNext() {
829: return i != null && i.hasNext();
830: }
831:
832: public Object next() {
833: Object value = i == null ? null : i.next();
834:
835: Object result;
836: try {
837: if (value == null)
838: result = ESBase.esNull;
839: else
840: result = resin.objectWrap(value);
841: } catch (Throwable e) {
842: result = ESBase.esNull;
843: }
844:
845: return result;
846: }
847:
848: public void remove() {
849: throw new RuntimeException();
850: }
851:
852: ESIterator(Iterator i) {
853: this .i = i;
854: this .resin = Global.getGlobalProto();
855: }
856: }
857:
858: static class ESEnumIterator implements Iterator {
859: Global resin;
860: Enumeration e;
861:
862: public boolean hasNext() {
863: return e != null && e.hasMoreElements();
864: }
865:
866: public Object next() {
867: Object value = e != null ? e.nextElement() : null;
868: ;
869:
870: try {
871: if (value == null)
872: return ESBase.esNull;
873: else
874: return resin.objectWrap(value);
875: } catch (Throwable e) {
876: return ESBase.esNull;
877: }
878: }
879:
880: public void remove() {
881: throw new RuntimeException();
882: }
883:
884: ESEnumIterator(Enumeration e) {
885: this.e = e;
886: this.resin = Global.getGlobalProto();
887: }
888: }
889: }
|