package org.dynjs.runtime;
import org.dynjs.exception.ThrowException;
public abstract class AbstractFunction extends DynObject implements JSFunction {
private String[] formalParameters;
private LexicalEnvironment scope;
private boolean strict;
protected String debugContext;
protected SourceProvider source;
public AbstractFunction(final GlobalContext globalContext, final LexicalEnvironment scope, final boolean strict, final String... formalParameters) {
super(globalContext);
this.formalParameters = formalParameters;
this.scope = scope;
this.strict = strict;
setClassName("Function");
// http://es5.github.com/#x15.3.3.2
defineOwnProperty(null, "length",
PropertyDescriptor.newDataPropertyDescriptor((long) formalParameters.length, false, false, false), false);
if (strict) {
final Object thrower = globalContext.getThrowTypeError();
if (thrower != null) {
defineOwnProperty(null, "caller",
PropertyDescriptor.newAccessorPropertyDescriptor(thrower, thrower), false);
defineOwnProperty(null, "arguments",
PropertyDescriptor.newAccessorPropertyDescriptor(thrower, thrower), true);
}
}
setPrototype(globalContext.getPrototypeFor("Function"));
}
public LexicalEnvironment getScope() {
return this.scope;
}
public void setScope(LexicalEnvironment scope) {
this.scope = scope;
}
public boolean isStrict() {
return this.strict;
}
public boolean isConstructor() {
return true;
}
@Override
public String[] getFormalParameters() {
return this.formalParameters;
}
protected void setFormalParamters(String[] formalParameters) {
this.formalParameters = formalParameters;
}
// ------------------------------------------------------------------------
// ------------------------------------------------------------------------
@Override
public Object get(ExecutionContext context, String name) {
// 15.3.5.4
if (name.equals("caller") && this.strict) {
throw new ThrowException(context, context.createTypeError("may not reference 'caller'"));
}
return super.get(context, name);
}
@Override
public boolean hasInstance(ExecutionContext context, Object v) {
if (!(v instanceof JSObject)) {
return false;
}
Object o = get(null, "prototype");
if (!(o instanceof JSObject)) {
throw new ThrowException(context, context.createTypeError("prototype must be an object"));
}
JSObject proto = (JSObject) o;
if (proto == null || v == Types.UNDEFINED) {
return false;
}
while (true) {
v = ((JSObject) v).getPrototype();
if (v == null || v == Types.UNDEFINED) {
return false;
}
if (v == proto) {
return true;
}
}
}
@Override
public JSObject createNewObject(ExecutionContext context) {
return new DynObject(context.getGlobalContext());
}
public void setDebugContext(String debugContext) {
this.debugContext = debugContext;
}
public String getDebugContext() {
return this.debugContext;
}
public void setSource(SourceProvider source) {
this.source = source;
}
public SourceProvider getSource() {
return this.source;
}
}