using Jint.Native.Object;
using Jint.Runtime;
using Jint.Runtime.Environments;
namespace Jint.Native.Function
{
public abstract class FunctionInstance : ObjectInstance, ICallable
{
private readonly Engine _engine;
protected FunctionInstance(Engine engine, string[] parameters, LexicalEnvironment scope, bool strict) : base(engine)
{
_engine = engine;
FormalParameters = parameters;
Scope = scope;
Strict = strict;
}
///
/// Executed when a function object is used as a function
///
///
///
///
public abstract JsValue Call(JsValue thisObject, JsValue[] arguments);
public LexicalEnvironment Scope { get; private set; }
public string[] FormalParameters { get; private set; }
public bool Strict { get; private set; }
public virtual bool HasInstance(JsValue v)
{
var vObj = v.TryCast();
if (vObj == null)
{
return false;
}
var po = Get("prototype");
if (!po.IsObject())
{
throw new JavaScriptException(_engine.TypeError, string.Format("Function has non-object prototype '{0}' in instanceof check", TypeConverter.ToString(po)));
}
var o = po.AsObject();
if (o == null)
{
throw new JavaScriptException(_engine.TypeError);
}
while (true)
{
vObj = vObj.Prototype;
if (vObj == null)
{
return false;
}
if (vObj == o)
{
return true;
}
}
}
public override string Class
{
get
{
return "Function";
}
}
///
/// http://www.ecma-international.org/ecma-262/5.1/#sec-15.3.5.4
///
///
///
public override JsValue Get(string propertyName)
{
var v = base.Get(propertyName);
var f = v.As();
if (propertyName == "caller" && f != null && f.Strict)
{
throw new JavaScriptException(_engine.TypeError);
}
return v;
}
}
}