// Copyright 2010 NexJ Systems Inc. This software is licensed under the terms of the Eclipse Public License 1.0
package nexj.core.scripting.object;
import nexj.core.meta.Primitive;
import nexj.core.scripting.Function;
import nexj.core.scripting.Machine;
import nexj.core.scripting.Symbol;
import nexj.core.util.ObjUtil;
/**
* The generic object implementation.
*/
public abstract class GenericObject implements ObjectOriented
{
// constants
/**
* Symbol "initialize".
*/
public final static Symbol INITIALIZE_SYMBOL = Symbol.define("initialize");
// associations
/**
* The class object.
*/
protected ClassObject m_class;
// constructors
/**
* Constructs the instance.
* @param classObject The class object.
*/
protected GenericObject(ClassObject classObject)
{
m_class = classObject;
}
// operations
/**
* @see ObjectOriented#getClassObject()
*/
public ClassObject getClassObject()
{
return m_class;
}
/**
* @see nexj.core.scripting.object.ObjectOriented#initialize(Machine)
*/
public void initialize(Machine machine)
{
for (int i = 0, n = m_class.getInitializerCount(); i < n; ++i)
{
int nOffset = m_class.getInitializerOffset(i);
if (getValue(nOffset, machine) == null)
{
AttributeObject attribute = m_class.resolveAttribute(nOffset);
Object value = machine.invoke(attribute.getInitializerFunction(), this, (Object[])null);
Function setter = attribute.getSetterFunction();
if (setter != null)
{
value = machine.invoke(setter, this, value, null);
}
setValue(nOffset, value, machine);
}
}
}
/**
* Invokes an instance method dispatching on the first argument,
* which must be a symbol, and the total argument count.
* @see nexj.core.scripting.Function#invoke(int, nexj.core.scripting.Machine)
*/
public boolean invoke(int nArgCount, Machine machine)
{
if (nArgCount == 0)
{
throw new InvocationException("err.scripting.minArgCount",
new Object[]{m_class.getName(),
Primitive.ONE_INTEGER,
Primitive.createInteger(nArgCount)});
}
Object selector = machine.getArg(0, nArgCount);
if (selector instanceof Symbol)
{
machine.setArg(0, nArgCount, this);
Function fun = machine.getGlobalEnvironment().findFunction(m_class, (Symbol)selector, nArgCount - 1);
if (fun != null)
{
return fun.invoke(nArgCount, machine);
}
fun = m_class.resolveFunction((Symbol)selector, nArgCount - 1);
if (fun != null)
{
return fun.invoke(nArgCount, machine);
}
throw new InvocationException("err.scripting.methodLookup",
new Object[]{selector.toString(), Primitive.createInteger(nArgCount - 1), m_class.getName()});
}
if (selector instanceof ClassObject && nArgCount >= 1)
{
ClassObject classObject = (ClassObject)selector;
selector = machine.getArg(1, nArgCount);
if (selector instanceof Symbol)
{
machine.shiftArgs(1, nArgCount--);
machine.setArg(0, nArgCount, this);
Function fun = machine.getGlobalEnvironment().findFunction(classObject, (Symbol)selector, -nArgCount);
if (fun != null)
{
return fun.invoke(nArgCount, machine);
}
fun = classObject.resolveBaseFunction((Symbol)selector, nArgCount - 1);
if (fun != null)
{
return fun.invoke(nArgCount, machine);
}
throw new InvocationException("err.scripting.baseMethodLookup",
new Object[]{selector.toString(), Primitive.createInteger(nArgCount - 1), classObject.getName()});
}
}
throw new InvocationException("err.scripting.funCall");
}
/**
* @see ObjectOriented#setValue(int, Object, Machine)
*/
public void setValue(int nOffset, Object value, Machine machine)
{
throw new UnsupportedOperationException();
}
/**
* @see ObjectOriented#getValue(int, Machine)
*/
public Object getValue(int nOffset, Machine machine)
{
throw new UnsupportedOperationException();
}
/**
* @see java.lang.Object#toString()
*/
public String toString()
{
String sName = m_class.getName();
return ObjUtil.getShortClassName(this) + ':' +
((sName == null) ? "" : sName) + '@' + System.identityHashCode(this);
}
/**
* Exposes members from ObjectOriented on a class object.
* @param classObject The destination class object.
*/
public static void addMembers(ClassObject classObject)
{
classObject.addMethod(":class", 0, false, new Function()
{
public boolean invoke(int nArgCount, Machine machine)
{
machine.returnValue(((ObjectOriented)machine.getArg(0, nArgCount)).getClassObject(), nArgCount);
return false;
}
});
classObject.addMethod(":understands?", 2, false, new Function()
{
public boolean invoke(int nArgCount, Machine machine)
{
int nMemberArgCount = ((Number)machine.getArg(2, nArgCount)).intValue();
machine.returnValue(Boolean.valueOf(nMemberArgCount >= 0 &&
((ObjectOriented)machine.getArg(0, nArgCount)).getClassObject()
.resolveFunction((Symbol)machine.getArg(1, nArgCount), nMemberArgCount) != null),
nArgCount);
return false;
}
});
classObject.addMethod("initialize", 0, false, new Function()
{
public boolean invoke(int nArgCount, Machine machine)
{
((ObjectOriented)machine.getArg(0, nArgCount)).initialize(machine);
machine.returnValue(null, nArgCount);
return false;
}
});
}
}