/*
* 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 com.caucho.util.IntMap;
import java.util.HashMap;
import java.util.Iterator;
/**
* Implementation class for the base of the JavaScript object hierarchy.
*/
public class ESBase {
private static ESFactory factory;
String className;
ESBase prototype;
public static ESBase esBase;
public static ESBase esNull;
public static ESBase esUndefined;
public static ESBase esEmpty;
final static int NONE = 0;
final static int STRING = 1;
final static int NUMBER = 2;
public static final int READ_ONLY = 0x1;
public static final int DONT_DELETE = 0x2;
public static final int DONT_ENUM = 0x4;
static final int WATCH = 0x8;
static void init(ESFactory factory)
{
if (esBase != null)
return;
esBase = new ESBase(null);
esBase.prototype = esBase;
esBase.className = "base";
ESBase.factory = factory;
if (factory != null) {
esNull = factory.createNull();
esUndefined = factory.createUndefined();
esEmpty = factory.createUndefined();
} else {
esNull = new ESNull();
esUndefined = new ESUndefined();
esEmpty = new ESUndefined();
}
}
/**
* Create a new object based on a prototype
*/
protected ESBase()
{
}
/**
* Create a new object based on a prototype
*/
ESBase(ESBase prototype)
{
if (prototype == null)
prototype = esBase;
this.prototype = prototype;
}
public ESBase typeof() throws ESException
{
throw new ESException("no typeof");
}
public Class getJavaType()
{
return void.class;
}
public ESBase getProperty(ESString key) throws Throwable
{
return esEmpty;
}
boolean canPut(ESString name)
{
return true;
}
/**
* Sets the named property
*/
public void setProperty(ESString key, ESBase value) throws Throwable
{
}
public ESBase delete(ESString key) throws Throwable
{
return ESBoolean.TRUE;
}
public ESBase toPrimitive(int type) throws Throwable
{
return this;
}
public ESBase toPrimitive() throws Throwable
{
return toPrimitive(NONE);
}
public boolean isBoolean()
{
return false;
}
public boolean toBoolean()
{
return false;
}
public boolean isNum()
{
return false;
}
public double toNum() throws Throwable
{
throw new ESException("no number: " + getClass().getName());
}
public boolean isString()
{
return false;
}
public ESString toStr() throws Throwable
{
throw new ESException("no string: " + getClass().getName());
}
public ESBase valueOf() throws Throwable
{
return toPrimitive(NONE);
}
public ESString toSource(IntMap map, boolean isLoopPass) throws Throwable
{
if (isLoopPass)
return null;
return toStr();
}
public ESObject toObject() throws ESException
{
throw new ESNullException(className + " has no properties");
}
public Object toJavaObject() throws ESException
{
return null;
}
Object copy(HashMap refs)
{
return this;
}
public ESBase call(Call eval, int length) throws Throwable
{
throw new ESNullException(toStr() + " is not a function");
}
public ESBase call(Call eval, int length, ESString key) throws Throwable
{
ESBase call = hasProperty(key);
if (call != null) {
eval.callee = call;
return call.call(eval, length);
}
if (prototype != null && prototype != this)
return prototype.call(eval, length, key);
else
throw new ESUndefinedException("undefined call `" + key + "'");
}
public ESBase construct(Call eval, int length) throws Throwable
{
throw new ESNullException(toStr() + " is not a constructor");
}
public Iterator keys() throws Throwable
{
return toObject().keys();
}
// useful junk
String getClassName()
{
return className;
}
public ESBase hasProperty(ESString key) throws Throwable
{
ESBase value = getProperty(key);
return value == esEmpty ? null : value;
}
ESBase hasProperty(int i) throws Throwable
{
return hasProperty(ESString.create(i));
}
/**
* Returns the text object for the lexeme.
*/
public ESBase getProperty(String key) throws Throwable
{
return getProperty(ESString.create(key));
}
/**
* Returns the text object for the lexeme.
*/
ESBase getProperty(int i) throws Throwable
{
return getProperty(ESString.create(i));
}
public void setProperty(String key, ESBase value) throws Throwable
{
setProperty(ESString.create(key), value);
}
/**
* Sets the named property
*/
public void setProperty(int i, ESBase value) throws Throwable
{
setProperty(ESString.create(i), value);
}
ESBase delete(String key) throws Throwable
{
return delete(ESString.create(key));
}
ESBase delete(int i) throws Throwable
{
return delete(ESString.create(i));
}
public ESBase plus(ESBase b) throws Throwable
{
ESBase primA = toPrimitive(NONE);
ESBase primB = b.toPrimitive(NONE);
if (primA instanceof ESString || primB instanceof ESString) {
return ESString.create(primA.toStr().toString() +
primB.toStr().toString());
}
else {
return ESNumber.create(primA.toNum() + primB.toNum());
}
}
public boolean lessThan(ESBase ob, boolean neg) throws Throwable
{
ESBase a = toPrimitive(NONE);
ESBase b = ob.toPrimitive(NONE);
if (a instanceof ESString && b instanceof ESString) {
return ((((ESString) a).compareTo((ESString) b) < 0) != neg);
} else {
double da = a.toNum();
double db = b.toNum();
if (Double.isNaN(da) || Double.isNaN(db))
return false;
else
return (da < db) != neg;
}
}
public boolean greaterThan(ESBase ob, boolean neg) throws Throwable
{
return ob.lessThan(this, neg);
}
public int toInt32() throws Throwable
{
double value = toNum();
if (Double.isInfinite(value))
return 0;
else
return (int) ((long) value & 0xffffffffL);
}
public String toString()
{
try {
return toStr().toString();
} catch (Throwable e) {
System.out.println("Exception: " + e);
e.printStackTrace();
return "";
}
}
public String toJavaString() throws Throwable
{
return toStr().toString();
}
public boolean ecmaEquals(ESBase b) throws Throwable
{
return this == b;
}
}