view dmdscript_tango/functiondefinition.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-2007 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.functiondefinition;

//import std.stdio;

import dmdscript_tango.script;
import dmdscript_tango.identifier;
import dmdscript_tango.statement;
import dmdscript_tango.dfunction;
import dmdscript_tango.scopex;
import dmdscript_tango.irstate;
import dmdscript_tango.opcodes;
import dmdscript_tango.ddeclaredfunction;
import dmdscript_tango.symbol;
import dmdscript_tango.dobject;
import dmdscript_tango.ir;
import dmdscript_tango.textgen.errmsgs;
import dmdscript_tango.value;
import dmdscript_tango.property;

/* ========================== FunctionDefinition ================== */

class FunctionDefinition : TopStatement
{
    // Maybe the following two should be done with derived classes instead
    int isglobal;		// !=0 if the global anonymous function
    int isanonymous;		// !=0 if anonymous function
    int iseval;			// !=0 if eval function

    Identifier* name;			// null for anonymous function
    Identifier*[] parameters;		// array of Identifier's
    TopStatement[] topstatements;	// array of TopStatement's

    Identifier*[] varnames;	// array of Identifier's
    FunctionDefinition[] functiondefinitions;
    FunctionDefinition enclosingFunction;
    int nestDepth;
    int withdepth;		// max nesting of ScopeStatement's

    SymbolTable *labtab;	// symbol table for LabelSymbol's

    IR *code;
    uint nlocals;


    this(TopStatement[] topstatements)
    {
	super(0);
	st = FUNCTIONDEFINITION;
	this.isglobal = 1;
	this.topstatements = topstatements;
    }

    this(Loc loc, int isglobal,
	    Identifier *name, Identifier*[] parameters,
	    TopStatement[] topstatements)
    {
	super(loc);

	//writef("FunctionDefinition('%ls')\n", name ? name.string : L"");
	st = FUNCTIONDEFINITION;
	this.isglobal = isglobal;
	this.name = name;
	this.parameters = parameters;
	this.topstatements = topstatements;
    }

    Statement semantic(Scope *sc)
    {
	uint i;
	TopStatement ts;
	FunctionDefinition fd;

	//writef("FunctionDefinition::semantic(%s)\n", this);

	// Log all the FunctionDefinition's so we can rapidly
	// instantiate them at runtime
	fd = enclosingFunction = sc.funcdef;

	// But only push it if it is not already in the array
	for (i = 0; ; i++)
	{
	    if (i == fd.functiondefinitions.length)	// not in the array
	    {   fd.functiondefinitions ~= this;
		break;
	    }
	    if (fd.functiondefinitions[i] is this)	// already in the array
		break;
	}

	//writef("isglobal = %d, isanonymous = %d\n", isglobal, isanonymous);
	if (!isglobal && !isanonymous)
	{   sc = sc.push(this);
	    sc.nestDepth++;
	}
	nestDepth = sc.nestDepth;
	//writefln("nestDepth = %d", nestDepth);

	if (topstatements.length)
	{
	    for (i = 0; i < topstatements.length; i++)
	    {
		ts = topstatements[i];
		//writefln("calling semantic routine %d which is %x\n",i, cast(uint)cast(void*)ts);
		if (!ts.done)
		{   ts = ts.semantic(sc);
		    if (sc.errinfo.message)
			break;

		    if (iseval)
		    {
			// There's an implied "return" on the last statement
			if ((i + 1) == topstatements.length)
			{
			    ts = ts.ImpliedReturn();
			}
		    }
		    topstatements[i] = ts;
		    ts.done = 1;
		}
	    }

	    // Make sure all the LabelSymbol's are defined
	    if (labtab)
	    {
		foreach (Symbol s; labtab.members)
		{   LabelSymbol ls = cast(LabelSymbol) s;
		    if (!ls.statement)
			error(sc, errmsgtbl[ERR_UNDEFINED_LABEL],
			    ls.toString(), toString());
		}
	    }
	}

	if (!isglobal && !isanonymous)
	    sc.pop();

	FunctionDefinition fdx = this;
	return cast(Statement)cast(void*)fdx;
    }

    void toBuffer(inout tchar[] buf)
    {   uint i;

	//writef("FunctionDefinition::toBuffer()\n");
	if (!isglobal)
	{
	    buf ~= "function ";
	    if (isanonymous)
		buf ~= "anonymous";
	    else if (name)
		buf ~= name.toString();
	    buf ~= '(';
	    for (i = 0; i < parameters.length; i++)
	    {
		if (i)
		    buf ~= ',';
		buf ~= parameters[i].toString();
	    }
	    buf ~= ")\n{ \n";
	}
	if (topstatements)
	{
	    for (i = 0; i < topstatements.length; i++)
	    {
		topstatements[i].toBuffer(buf);
	    }
	}
	if (!isglobal)
	{
	    buf ~= "}\n";
	}
    }

    void toIR(IRstate *ignore)
    {
	IRstate irs;
	uint i;

	//writefln("FunctionDefinition.toIR() done = %d", done);
	irs.ctor();
	if (topstatements.length)
	{
	    for (i = 0; i < topstatements.length; i++)
	    {   TopStatement ts;
		FunctionDefinition fd;

		ts = topstatements[i];
		if (ts.st == FUNCTIONDEFINITION)
		{
		    fd = cast(FunctionDefinition)ts;
		    if (fd.code)
			continue;
		}
		ts.toIR(&irs);
	    }

	    // Don't need parse trees anymore, release to garbage collector
	    topstatements[] = null;
	    topstatements = null;
	    labtab = null;			// maybe delete it?
	}
	irs.gen0(0, IRret);
	irs.gen0(0, IRend);

	//irs.validate();

	irs.doFixups();
	irs.optimize();

	code = cast(IR *) irs.codebuf.data;
	irs.codebuf.data = null;
	nlocals = irs.nlocals;
    }

    void instantiate(Dobject[] scopex, Dobject actobj, uint attributes)
    {
	//writefln("FunctionDefinition.instantiate() %s nestDepth = %d", name ? name.toString() : "", nestDepth);

	// Instantiate all the Var's per 10.1.3
	foreach (Identifier* name; varnames)
	{
	    // If name is already declared, don't override it
	    //writefln("\tVar Put(%s)", name.toString());
	    actobj.Put(name.toString(), &vundefined, Instantiate | DontOverride | attributes);
	}

	// Instantiate the Function's per 10.1.3
	foreach (FunctionDefinition fd; functiondefinitions)
	{
	    // Set [[Scope]] property per 13.2 step 7
	    Dfunction fobject = new DdeclaredFunction(fd);
	    fobject.scopex = scopex;

	    if (fd.name)       // skip anonymous functions
	    {
		//writefln("\tFunction Put(%s)", fd.name.toString());
		actobj.Put(fd.name.toString(), fobject, Instantiate | attributes);
	    }
	}
	//writefln("-FunctionDefinition.instantiate()");
    }
}