/*
* Copyright (c) 1998-2011 Caucho Technology -- all rights reserved
*
* This file is part of Resin(R) Open Source
*
* Each copy or derived work must preserve the copyright notice and this
* notice unmodified.
*
* Resin Open Source is free software; 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.
*
* Resin Open Source is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE, or any warranty
* of NON-INFRINGEMENT. See the GNU General Public License for more
* details.
*
* You should have received a copy of the GNU General Public License
* along with Resin Open Source; if not, write to the
* Free SoftwareFoundation, Inc.
* 59 Temple Place, Suite 330
* Boston, MA 02111-1307 USA
*
* @author Scott Ferguson
*/
package com.caucho.es;
import java.util.Enumeration;
import java.util.Iterator;
/**
* Implementation class representing a call context.
*/
public final class Call extends ESBase {
static ESId ARGUMENTS = ESId.intern("arguments");
static ESId ARRAY = ESId.intern("Array");
Call caller;
ESObject callThis;
int callLength;
ESBase callee;
public ESBase []stack;
int top;
public ESGlobal global;
ESBase []scope;
int scopeLength;
public ESBase []values;
ESObject aux;
Call child; // just a cache
/**
* Create a new context object
*/
Call()
{
prototype = esBase;
stack = new ESBase[64];
scope = new ESBase[16];
values = new ESBase[64];
top = 0;
}
void clear()
{
aux = null;
child = null;
top = 0;
}
public Call getCall()
{
Call child = this.child;
if (child == null)
child = this.child = new Call();
child.caller = this;
child.global = global;
return child;
}
Global getGlobalProto() { return Global.getGlobalProto(); }
public ESBase wrap(Object o) throws Throwable { return Global.wrap(o); }
public ESBase wrap(long n) throws Throwable
{
return ESNumber.create(n);
}
public ESBase wrapClass(Class cl) throws Throwable
{
return Global.getGlobalProto().classWrap(cl);
}
// public ESGlobal getGlobal() { return Global.getGlobal().global; }
final ESBase getArg(int i)
{
return stack[top + i];
}
public final ESBase getArg(int i, int len)
{
return i < len ? stack[top + i] : esUndefined;
}
public final int getArgInt32(int i, int len) throws Throwable
{
return i < len ? stack[top + i].toInt32() : 0;
}
public final double getArgNum(int i, int len) throws Throwable
{
return i < len ? stack[top + i].toNum() : (0.0/0.0);
}
public final String getArgString(int i, int len) throws Throwable
{
return i < len ? stack[top + i].toJavaString() : null;
}
public final Object getArgObject(int i, int len) throws Throwable
{
return i < len ? stack[top + i].toJavaObject() : null;
}
public ESObject createObject()
{
return new ESObject("Object", getGlobalProto().objProto);
}
public ESBase createDate(long time)
{
return new ESDate(time, getGlobalProto().dateProto);
}
public String printf(int length)
throws Throwable
{
return Printf.sprintf(this, length);
}
void setArg(int i, ESBase obj)
{
stack[top + i] = obj;
}
public final ESObject getThis() throws Throwable
{
return stack[top - 1].toObject();
}
public final Object getThisWrapper() throws Throwable
{
return stack[top - 1].toJavaObject();
}
void setThis(ESBase obj)
{
stack[top - 1] = obj;
}
public ESGlobal getGlobal()
{
return global;
}
public final ESObject getCallThis() throws Throwable
{
ESBase obj = caller.stack[caller.top - 1];
return obj.toObject();
}
ESBase getContext()
{
return scope[scopeLength - 1];
}
ESBase getFunctionContext()
{
if (caller == null || caller.scopeLength == 0)
return global;
else
return caller.scope[caller.scopeLength - 1];
}
public void pushScope(ESBase value)
{
scope[scopeLength++] = value;
}
public void popScope()
{
scopeLength--;
}
public ESObject getEval()
{
return (ESObject) scope[scopeLength - 1];
}
public ESObject createArg(ESId []args, int length)
throws Throwable
{
ESObject arg = ESArguments.create(args, this, length);
scope[scopeLength++] = arg;
return arg;
}
public void setProperty(ESString name, ESBase value) throws Throwable
{
//setProperty(name, value);
}
public ESBase delete(ESString key) throws Throwable
{
return aux == null ? ESBoolean.FALSE : aux.delete(key);
}
public ESBase findScopeProperty(ESString id) throws Throwable
{
for (int i = scopeLength - 1; i > 0; i--) {
if (scope[i].getProperty(id) != esEmpty)
return scope[i];
}
return global;
}
public ESBase scopeTypeof(ESString id) throws Throwable
{
for (int i = scopeLength - 1; i >= 0; i--) {
ESBase value;
if ((value = scope[i].getProperty(id)) != esEmpty)
return value.typeof();
}
return esEmpty.typeof();
}
public static ESBase setProperty(ESBase base, ESString field, ESBase value)
throws Throwable
{
base.setProperty(field, value);
return value;
}
public static ESBase doVoid(ESBase value)
{
return ESBase.esUndefined;
}
public ESBase array(ESBase value)
throws Throwable
{
ESBase array = call(global, ARRAY, 0);
array.setProperty(0, value);
return array;
}
public static ESBase comma(ESBase left, ESBase right)
{
return right;
}
public static ESBase _first(ESBase left, ESBase right)
throws Throwable
{
// This is only used for postfix
if (! (left instanceof ESNumber))
return ESNumber.create(left.toNum());
else
return left;
}
public static double _first(double left, double right)
throws Throwable
{
return left;
}
/**
* Returns the first value in a tuple. Used
*
* @param left the first value
* @param right the right value
*
* @return the first value.
*/
public static int _first(int left, int right)
throws Throwable
{
return left;
}
public static double _pre(ESBase expr, ESString field, int inc)
throws Throwable
{
double oldVal = expr.getProperty(field).toNum();
ESNumber newVal = ESNumber.create(oldVal + inc);
expr.setProperty(field, newVal);
return oldVal + inc;
}
public static double _post(ESBase expr, ESString field, int inc)
throws Throwable
{
double oldVal = expr.getProperty(field).toNum();
ESNumber newVal = ESNumber.create(oldVal + inc);
expr.setProperty(field, newVal);
return oldVal;
}
public double _pre(ESString field, int inc)
throws Throwable
{
double oldVal = getScopeProperty(field).toNum();
ESNumber newVal = ESNumber.create(oldVal + inc);
setScopeProperty(field, newVal);
return oldVal + inc;
}
public double _post(ESString field, int inc)
throws Throwable
{
double oldVal = getScopeProperty(field).toNum();
ESNumber newVal = ESNumber.create(oldVal + inc);
setScopeProperty(field, newVal);
return oldVal;
}
public ESBase setGlobalProperty(ESString id, ESBase value) throws Throwable
{
global.setProperty(id, value);
return value;
}
/**
* Returns the global variable of the id, throwing an exception if
* the it's undefined.
*/
public ESBase getGlobalVariable(ESString id) throws Throwable
{
ESBase value = global.getProperty(id);
if (value == ESBase.esEmpty)
throw new ESUndefinedException("undefined variable `" + id + "'");
return value;
}
public ESBase getScopeProperty(ESString id) throws Throwable
{
for (int i = scopeLength - 1; i >= 0; i--) {
ESBase value;
if ((value = scope[i].getProperty(id)) != esEmpty) {
return value;
}
}
throw new ESUndefinedException("undefined variable `" + id + "'");
}
public void fillScope()
{
if (callee instanceof ESClosure) {
ESClosure closure = (ESClosure) callee;
if (closure.scopeLength == 0) {
scope[0] = caller.global;
scopeLength = 1;
return;
}
for (int i = 0; i < closure.scopeLength; i++) {
scope[i] = closure.scope[i];
}
scopeLength = closure.scopeLength;
}
else {
scope[0] = caller.global;
scopeLength = 1;
}
}
public ESBase hasScopeProperty(ESString id) throws Throwable
{
for (int i = scopeLength - 1; i >= 0; i--) {
ESBase value;
if ((value = scope[i].getProperty(id)) != esEmpty)
return value;
}
return esEmpty;
}
public ESBase setScopeProperty(ESString id, ESBase value) throws Throwable
{
if (value == esEmpty)
value = esUndefined;
for (int i = scopeLength - 1; i > 0; i--) {
if (scope[i].getProperty(id) != esEmpty) {
scope[i].setProperty(id, value);
return value;
}
}
global.setProperty(id, value);
return value;
}
public ESBase deleteScopeProperty(ESString id) throws Throwable
{
for (int i = scopeLength - 1; i > 0; i--) {
if (scope[i].getProperty(id) != esEmpty)
return scope[i].delete(id);
}
return global.delete(id);
}
/*
public ESBase startCallScopeProperty(ESString id, int i) throws Throwable
{
top = i + 1;
for (int j = scopeLength - 1; j >= 0; j--) {
ESBase value;
if ((value = scope[j].getProperty(id)) != esEmpty) {
stack[i] = global;
return value;
}
}
throw new ESUndefinedException("undefined call `" + id + "'");
}
*/
public int arg(int i, ESBase arg)
{
stack[i + 1] = arg;
return 1;
}
public ESBase callScope(ESString id, int i) throws Throwable
{
top = i + 1;
int scopeLength = caller.scopeLength;
ESBase []scope = caller.scope;
for (int j = scopeLength - 1; j >= 0; j--) {
ESBase value;
if ((value = scope[j].getProperty(id)) != esEmpty) {
callee = value;
stack[i] = scope[j];
return value.call(this, 0);
}
}
throw new ESUndefinedException("undefined call `" + id + "'");
}
public ESBase callScope(ESString id, int i, ESBase a) throws Throwable
{
top = i + 1;
int scopeLength = caller.scopeLength;
ESBase []scope = caller.scope;
for (int j = scopeLength - 1; j >= 0; j--) {
ESBase value;
if ((value = scope[j].getProperty(id)) != esEmpty) {
callee = value;
stack[i] = scope[j];
stack[i + 1] = a;
return value.call(this, 1);
}
}
throw new ESUndefinedException("undefined call `" + id + "'");
}
public ESBase callScope(ESString id, int i, ESBase a, ESBase b)
throws Throwable
{
top = i + 1;
int scopeLength = caller.scopeLength;
ESBase []scope = caller.scope;
for (int j = scopeLength - 1; j >= 0; j--) {
ESBase value;
if ((value = scope[j].getProperty(id)) != esEmpty) {
callee = value;
stack[i] = scope[j];
stack[i + 1] = a;
stack[i + 2] = b;
return value.call(this, 2);
}
}
throw new ESUndefinedException("undefined call `" + id + "'");
}
public ESBase callScope(ESString id, int i, ESBase a, ESBase b, ESBase c,
int length)
throws Throwable
{
top = i + 1;
int scopeLength = caller.scopeLength;
ESBase []scope = caller.scope;
for (int j = scopeLength - 1; j >= 0; j--) {
ESBase value;
if ((value = scope[j].getProperty(id)) != esEmpty) {
callee = value;
stack[i] = scope[j];
stack[i + 1] = a;
stack[i + 2] = b;
stack[i + 3] = c;
return value.call(this, length);
}
}
throw new ESUndefinedException("undefined call `" + id + "'");
}
public ESBase call(ESBase base, ESString name, int i)
throws Throwable
{
top = i + 1;
stack[i] = base;
return base.call(this, 0, name);
}
public ESBase call(ESBase base, ESString name, int i, ESBase a)
throws Throwable
{
top = i + 1;
stack[i] = base;
stack[i + 1] = a;
return base.call(this, 1, name);
}
public ESBase call(ESBase base, ESString name, int i, ESBase a, ESBase b)
throws Throwable
{
top = i + 1;
stack[i] = base;
stack[i + 1] = a;
stack[i + 2] = b;
return base.call(this, 2, name);
}
public ESBase call(ESBase base, ESString name, int i,
ESBase a, ESBase b, ESBase c, int length)
throws Throwable
{
top = i + 1;
stack[i] = base;
stack[i + 1] = a;
stack[i + 2] = b;
stack[i + 3] = c;
return base.call(this, length, name);
}
public ESBase call(ESBase base, int i)
throws Throwable
{
top = i + 1;
stack[i] = global;
callee = base;
return base.call(this, 0);
}
public ESBase call(ESBase base, int i, ESBase a)
throws Throwable
{
top = i + 1;
stack[i + 1] = a;
stack[i] = global;
callee = base;
return base.call(this, 1);
}
public ESBase call(ESBase base, int i, ESBase a, ESBase b)
throws Throwable
{
top = i + 1;
stack[i] = base;
stack[i + 1] = a;
stack[i + 2] = b;
stack[i] = global;
callee = base;
return base.call(this, 2);
}
public ESBase call(ESBase base, int i,
ESBase a, ESBase b, ESBase c, int length)
throws Throwable
{
top = i + 1;
stack[i] = base;
stack[i + 1] = a;
stack[i + 2] = b;
stack[i + 3] = c;
stack[i] = global;
callee = base;
return base.call(this, length);
}
public ESBase newScope(ESString id, int i) throws Throwable
{
top = i + 1;
int scopeLength = caller.scopeLength;
ESBase []scope = caller.scope;
for (int j = scopeLength - 1; j >= 0; j--) {
ESBase value;
if ((value = scope[j].getProperty(id)) != esEmpty) {
callee = value;
stack[i] = global;
return value.construct(this, 0);
}
}
throw new ESUndefinedException("undefined constructor `" + id + "'");
}
public ESBase newScope(ESString id, int i, ESBase a) throws Throwable
{
top = i + 1;
int scopeLength = caller.scopeLength;
ESBase []scope = caller.scope;
for (int j = scopeLength - 1; j >= 0; j--) {
ESBase value;
if ((value = scope[j].getProperty(id)) != esEmpty) {
callee = value;
stack[i] = global;
stack[i + 1] = a;
return value.construct(this, 1);
}
}
throw new ESUndefinedException("undefined constructor `" + id + "'");
}
public ESBase newScope(ESString id, int i, ESBase a, ESBase b)
throws Throwable
{
top = i + 1;
int scopeLength = caller.scopeLength;
ESBase []scope = caller.scope;
for (int j = scopeLength - 1; j >= 0; j--) {
ESBase value;
if ((value = scope[j].getProperty(id)) != esEmpty) {
callee = value;
stack[i] = global;
stack[i + 1] = a;
stack[i + 2] = b;
return value.construct(this, 2);
}
}
throw new ESUndefinedException("undefined constructor `" + id + "'");
}
public ESBase newScope(ESString id, int i, ESBase a, ESBase b, ESBase c,
int length)
throws Throwable
{
top = i + 1;
int scopeLength = caller.scopeLength;
ESBase []scope = caller.scope;
for (int j = scopeLength - 1; j >= 0; j--) {
ESBase value;
if ((value = scope[j].getProperty(id)) != esEmpty) {
callee = value;
stack[i] = global;
stack[i + 1] = a;
stack[i + 2] = b;
stack[i + 3] = c;
return value.construct(this, length);
}
}
throw new ESUndefinedException("undefined constructor `" + id + "'");
}
public ESBase doNew(ESBase base, ESString name, int i)
throws Throwable
{
top = i + 1;
ESBase obj = base.getProperty(name);
stack[i] = base;
callee = obj;
if (obj != esEmpty)
return obj.construct(this, 0);
else
throw new ESUndefinedException("undefined constructor `" + name + "'");
}
public ESBase doNew(ESBase base, ESString name, int i, ESBase a)
throws Throwable
{
top = i + 1;
stack[i] = base;
stack[i + 1] = a;
ESBase obj = base.getProperty(name);
callee = obj;
if (obj != esEmpty)
return obj.construct(this, 1);
else
throw new ESUndefinedException("undefined constructor `" + name + "'");
}
public ESBase doNew(ESBase base, ESString name, int i, ESBase a, ESBase b)
throws Throwable
{
top = i + 1;
stack[i] = base;
stack[i + 1] = a;
stack[i + 2] = b;
ESBase obj = base.getProperty(name);
callee = obj;
if (obj != esEmpty)
return obj.construct(this, 2);
else
throw new ESUndefinedException("undefined constructor `" + name + "'");
}
public ESBase doNew(ESBase base, ESString name, int i,
ESBase a, ESBase b, ESBase c, int length)
throws Throwable
{
top = i + 1;
stack[i] = base;
stack[i + 1] = a;
stack[i + 2] = b;
stack[i + 3] = c;
ESBase obj = base.getProperty(name);
callee = obj;
if (obj != esEmpty)
return obj.construct(this, length);
else
throw new ESUndefinedException("undefined constructor `" + name + "'");
}
public ESBase doNew(ESBase base, int i)
throws Throwable
{
top = i + 1;
stack[i] = global;
callee = base;
return base.construct(this, 0);
}
public ESBase doNew(ESBase base, int i, ESBase a)
throws Throwable
{
top = i + 1;
stack[i] = global;
stack[i + 1] = a;
callee = base;
return base.construct(this, 1);
}
public ESBase doNew(ESBase base, int i, ESBase a, ESBase b)
throws Throwable
{
top = i + 1;
stack[i] = global;
stack[i + 1] = a;
stack[i + 2] = b;
callee = base;
return base.construct(this, 2);
}
public ESBase doNew(ESBase base, int i,
ESBase a, ESBase b, ESBase c, int length)
throws Throwable
{
top = i + 1;
stack[i] = global;
stack[i + 1] = a;
stack[i + 2] = b;
stack[i + 3] = c;
callee = base;
return base.construct(this, length);
}
public void free()
{
clear();
for (int i = stack.length - 1; i >= 0; i--)
stack[i] = null;
for (int i = scope.length - 1; i >= 0; i--)
scope[i] = null;
for (int i = values.length - 1; i >= 0; i--)
values[i] = null;
global = null;
}
public static Iterator toESIterator(Iterator i)
{
return new ESIterator(i);
}
public static Iterator toESIterator(Enumeration e)
{
return new ESEnumIterator(e);
}
public static boolean matchException(ESBase test, Exception e)
{
String testString;
try {
testString = test.toStr().toString();
} catch (Throwable foo) {
testString = "undefined";
}
Class eClass = e.getClass();
String dotted = "." + test;
for (; eClass != null; eClass = eClass.getSuperclass()) {
String eString = eClass.getName();
if (testString.equals(eString) || eString.endsWith(dotted))
return true;
}
return false;
}
static class ESIterator implements Iterator {
Global resin;
Iterator i;
public boolean hasNext()
{
return i != null && i.hasNext();
}
public Object next()
{
Object value = i == null ? null : i.next();
Object result;
try {
if (value == null)
result = ESBase.esNull;
else
result = resin.objectWrap(value);
} catch (Throwable e) {
result = ESBase.esNull;
}
return result;
}
public void remove() { throw new RuntimeException(); }
ESIterator(Iterator i)
{
this.i = i;
this.resin = Global.getGlobalProto();
}
}
static class ESEnumIterator implements Iterator {
Global resin;
Enumeration e;
public boolean hasNext()
{
return e != null && e.hasMoreElements();
}
public Object next()
{
Object value = e != null ? e.nextElement() : null;;
try {
if (value == null)
return ESBase.esNull;
else
return resin.objectWrap(value);
} catch (Throwable e) {
return ESBase.esNull;
}
}
public void remove() { throw new RuntimeException(); }
ESEnumIterator(Enumeration e)
{
this.e = e;
this.resin = Global.getGlobalProto();
}
}
}