view dmdscript_tango/dfunction.d @ 4:6d905019f7bf

some changes
author saaadel
date Thu, 28 Jan 2010 21:23:27 +0200
parents 8363a4bf6a8f
children
line wrap: on
line source


/* Digital Mars DMDScript source code.
 * Copyright (c) 2000-2002 by Chromium Communications
 * D version Copyright (c) 2004-2005 by Digital Mars
 * All Rights Reserved
 * written by Walter Bright
 * www.digitalmars.com
 * Use at your own risk. There is no warranty, express or implied.
 * License for redistribution is by the GNU General Public License in gpl.txt.
 *
 * A binary, non-exclusive license for commercial use can be
 * purchased from www.digitalmars.com/dscript/buy.html.
 *
 * DMDScript is implemented in the D Programming Language,
 * www.digitalmars.com/d/
 *
 * For a C++ implementation of DMDScript, including COM support,
 * see www.digitalmars.com/dscript/cppscript.html.
 */


module dmdscript_tango.dfunction;

//import std.string;
//import std.c.stdlib;
import tango.stdc.stdlib;
import tango.text.convert.Format;

import dmdscript_tango.script;
import dmdscript_tango.dobject;
import dmdscript_tango.value;
import dmdscript_tango.protoerror;
import dmdscript_tango.threadcontext;
import dmdscript_tango.text;
import dmdscript_tango.textgen.errmsgs;
import dmdscript_tango.property;
import dmdscript_tango.scopex;
import dmdscript_tango.dnative;
import dmdscript_tango.functiondefinition;
import dmdscript_tango.parse;
import dmdscript_tango.ddeclaredfunction;

/* ===================== Dfunction_constructor ==================== */

class Dfunction_constructor : Dfunction
{
    this(ThreadContext *tc)
    {
	super(1, tc.Dfunction_prototype);

	// Actually put in later by Dfunction::init()
	//unsigned attributes = DontEnum | DontDelete | ReadOnly;
	//Put(TEXT_prototype, Dfunction::getPrototype(), attributes);
    }

    void *Construct(CallContext *cc, Value *ret, Value[] arglist)
    {
	// ECMA 15.3.2.1
	d_string bdy;
	d_string P;
	FunctionDefinition fd;
	ErrInfo errinfo;

	//writef("Dfunction_constructor::Construct()\n");

	// Get parameter list (P) and body from arglist[]
	if (arglist.length)
	{
	    bdy = arglist[arglist.length - 1].toString();
	    if (arglist.length >= 2)
	    {
		for (uint a = 0; a < arglist.length - 1; a++)
		{
		    if (a)
			P ~= ',';
		    P ~= arglist[a].toString();
		}
	    }
	}

	if (Parser.parseFunctionDefinition(fd, P, bdy, errinfo))
	    goto Lsyntaxerror;

	if (fd)
	{
	    Scope sc;

	    sc.ctor(fd);
	    fd.semantic(&sc);
	    errinfo = sc.errinfo;
	    if (errinfo.message)
		goto Lsyntaxerror;
	    fd.toIR(null);
	    Dfunction fobj = new DdeclaredFunction(fd);
	    ret.putVobject(fobj);
	}
	else
	    ret.putVundefined();

	return null;

    Lsyntaxerror:
	Dobject o;

	ret.putVundefined();
	o = new syntaxerror.D0(&errinfo);
	Value* v = new Value;
	v.putVobject(o);
	return v;
    }

    void *Call(CallContext *cc, Dobject othis, Value* ret, Value[] arglist)
    {
	// ECMA 15.3.1
	return Construct(cc, ret, arglist);
    }
}


/* ===================== Dfunction_prototype_toString =============== */

void* Dfunction_prototype_toString(Dobject pthis, CallContext *cc, Dobject othis, Value *ret, Value[] arglist)
{
    d_string s;
    Dfunction f;

    //writef("function.prototype.toString()\n");
    // othis must be a Function
    if (!othis.isClass(TEXT_Function))
    {	ErrInfo errinfo;
	ret.putVundefined();
	return Dobject.RuntimeError(&errinfo, ERR_TS_NOT_TRANSFERRABLE);
    }
    else
    {
	// Generate string that looks like a FunctionDeclaration
	// FunctionDeclaration:
	//	function Identifier (Identifier, ...) Block

	// If anonymous function, the name should be "anonymous"
	// per ECMA 15.3.2.1.19

	f = cast(Dfunction)othis;
	s = f.toString();
	ret.putVstring(s);
    }
    return null;
}

/* ===================== Dfunction_prototype_apply =============== */

void* Dfunction_prototype_apply(Dobject pthis, CallContext *cc, Dobject othis, Value *ret, Value[] arglist)
{
    // ECMA v3 15.3.4.3

    Value* thisArg;
    Value* argArray;
    Dobject o;
    void* v;

    thisArg = &vundefined;
    argArray = &vundefined;
    switch (arglist.length)
    {
	case 0:
	    break;
	default:
	    argArray = &arglist[1];
	case 1:
	    thisArg = &arglist[0];
	    break;
    }

    if (thisArg.isUndefinedOrNull())
	o = cc.global;
    else
	o = thisArg.toObject();

    if (argArray.isUndefinedOrNull())
    {
	v = othis.Call(cc, o, ret, null);
    }
    else
    {
	if (argArray.isPrimitive())
	{
	  Ltypeerror:
	    ret.putVundefined();
	    ErrInfo errinfo;
	    return Dobject.RuntimeError(&errinfo, ERR_ARRAY_ARGS);
	}
	Dobject a;

	a = argArray.toObject();

	// Must be array or arguments object
	if (!a.isDarray() && !a.isDarguments())
	    goto Ltypeerror;

	uint len;
	uint i;
	Value[] alist;
	Value* x;

	x = a.Get(TEXT_length);
	len = x ? x.toUint32() : 0;

	Value[] p1;
	Value* v1;
	if (len < 128)
	    v1 = cast(Value*)alloca(len * Value.sizeof);
	if (v1)
	    alist = v1[0 .. len];
	else
	{   p1 = new Value[len];
	    alist = p1;
	}

	for (i = 0; i < len; i++)
	{
	    x = a.Get(i);
	    Value.copy(&alist[i], x);
	}

	v = othis.Call(cc, o, ret, alist);

	delete p1;
    }
    return v;
}

/* ===================== Dfunction_prototype_call =============== */

void* Dfunction_prototype_call(Dobject pthis, CallContext *cc, Dobject othis, Value *ret, Value[] arglist)
{
    // ECMA v3 15.3.4.4
    Value* thisArg;
    Dobject o;
    void* v;

    if (arglist.length == 0)
    {
	o = cc.global;
	v = othis.Call(cc, o, ret, arglist);
    }
    else
    {
	thisArg = &arglist[0];
	if (thisArg.isUndefinedOrNull())
	    o = cc.global;
	else
	    o = thisArg.toObject();
	v = othis.Call(cc, o, ret, arglist[1 .. length]);
    }
    return v;
}

/* ===================== Dfunction_prototype ==================== */

class Dfunction_prototype : Dfunction
{
    this(ThreadContext *tc)
    {
	super(0, tc.Dobject_prototype);

	uint attributes = DontEnum;

	classname = TEXT_Function;
	name = "prototype";
	Put(TEXT_constructor, tc.Dfunction_constructor, attributes);

	static NativeFunctionData nfd[] =
	[
	    {	&TEXT_toString, &Dfunction_prototype_toString, 0 },
	    {	&TEXT_apply, &Dfunction_prototype_apply, 2 },
	    {	&TEXT_call, &Dfunction_prototype_call, 1 },
	];

	DnativeFunction.init(this, nfd, attributes);
    }

    void *Call(CallContext *cc, Dobject othis, Value* ret, Value[] arglist)
    {
	// ECMA v3 15.3.4
	// Accept any arguments and return "undefined"
	ret.putVundefined();
	return null;
    }
}


/* ===================== Dfunction ==================== */

class Dfunction : Dobject
{   tchar[] name;
    Dobject[] scopex;	// Function object's scope chain per 13.2 step 7

    this(d_uint32 length)
    {
	this(length, Dfunction.getPrototype());
    }

    this(d_uint32 length, Dobject prototype)
    {
	super(prototype);
	classname = TEXT_Function;
	name = TEXT_Function;
	Put(TEXT_length, length, DontDelete | DontEnum | ReadOnly);
	Put(TEXT_arity, length, DontDelete | DontEnum | ReadOnly);
    }

    d_string getTypeof()
    {   // ECMA 11.4.3
	return TEXT_function;
    }

    d_string toString()
    {
	// Native overrides of this function replace Identifier with the actual name.
	// Don't need to do parameter list, though.
	d_string s;

	s = Format("function {}() {{ [native code] }", name);
	//s = std.string.format("function %s() { [native code] }", name);
	return s;
    }

    void *HasInstance(Value* ret, Value* v)
    {
	// ECMA v3 15.3.5.3
	Dobject V;
	Value* w;
	Dobject o;

	if (v.isPrimitive())
	    goto Lfalse;
	V = v.toObject();
	w = Get(TEXT_prototype);
	if (w.isPrimitive())
	{   ErrInfo errinfo;
	    return RuntimeError(&errinfo, errmsgtbl[ERR_MUST_BE_OBJECT], w.getType());
	}
	o = w.toObject();
	for (;;)
	{
	    V = V.internal_prototype;
	    if (!V)
		goto Lfalse;
	    if (o == V)
		goto Ltrue;
	}

    Ltrue:
	ret.putVboolean(true);
	return null;

    Lfalse:
	ret.putVboolean(false);
	return null;
    }

    static Dfunction isFunction(Value* v)
    {
	Dfunction r;
	Dobject o;

	r = null;
	if (!v.isPrimitive())
	{
	    o = v.toObject();
	    if (o.isClass(TEXT_Function))
		r = cast(Dfunction)o;
	}
	return r;
    }


    static Dfunction getConstructor()
    {
	ThreadContext *tc = ThreadContext.getThreadContext();
	assert(tc);
	return tc.Dfunction_constructor;
    }

    static Dobject getPrototype()
    {
	ThreadContext *tc = ThreadContext.getThreadContext();
	assert(tc);
	return tc.Dfunction_prototype;
    }

    static void init(ThreadContext *tc)
    {
	tc.Dfunction_constructor = new Dfunction_constructor(tc);
	tc.Dfunction_prototype = new Dfunction_prototype(tc);

	tc.Dfunction_constructor.Put(TEXT_prototype, tc.Dfunction_prototype, DontEnum | DontDelete | ReadOnly);

	tc.Dfunction_constructor.internal_prototype = tc.Dfunction_prototype;
	tc.Dfunction_constructor.proptable.previous = tc.Dfunction_prototype.proptable;
    }
}