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

//import std.stdio;
//import std.c.stdlib;
import tango.stdc.stdlib;

import dmdscript_tango.script;
import dmdscript_tango.dobject;
import dmdscript_tango.dglobal;
import dmdscript_tango.functiondefinition;
import dmdscript_tango.statement;
import dmdscript_tango.threadcontext;
import dmdscript_tango.value;
import dmdscript_tango.opcodes;
import dmdscript_tango.darray;
import dmdscript_tango.parse;
import dmdscript_tango.scopex;
import dmdscript_tango.text;
import dmdscript_tango.property;

class Program
{
    uint errors;	// if any errors in file
    CallContext *callcontext;
    FunctionDefinition globalfunction;

    // Locale info
    uint lcid;		// current locale
    tchar[] slist;	// list separator

    this()
    {
	initContext();
    }

    void initContext()
    {
	//writefln("Program.initContext()");
	if (callcontext)		// if already done
	    return;

	callcontext = new CallContext();

	CallContext *cc = callcontext;

	// Do object inits
	ThreadContext *tc = ThreadContext.getThreadContext();
	assert(tc);

	dobject_init(tc);

	cc.prog = this;

	// Create global object
	cc.global = new Dglobal(null);

	Dobject[] scopex;
	scopex ~= cc.global;

	cc.variable = cc.global;
	cc.scopex = scopex;
	cc.scoperoot++;
	cc.globalroot++;

	assert(tc.Ddate_prototype.proptable.table.length != 0);
    }

    /**************************************************
     * Two ways of calling this:
     * 1. with text representing group of topstatements (pfd == null)
     * 2. with text representing a function name & body (pfd != null)
     */

    void compile(char[] progIdentifier, tchar[] srctext, FunctionDefinition *pfd)
    {
	TopStatement[] topstatements;
	tchar[] msg;

	//writef("parse_common()\n");
	Parser p = new Parser(progIdentifier, srctext, 1);

	ErrInfo errinfo;
	if (p.parseProgram(topstatements, &errinfo))
	{
	    topstatements[] = null;
	    throw new ScriptException(&errinfo);
	}

	if (pfd)
	{   // If we are expecting a function, we should have parsed one
	    assert(p.lastnamedfunc);
	    *pfd = p.lastnamedfunc;
	}

	// Build empty function definition array
	// Make globalfunction an anonymous one (by passing in null for name) so
	// it won't get instantiated as a property
	globalfunction = new FunctionDefinition(0, 1, null, null, null);

	// Any functions parsed in topstatements wind up in the global
	// object (cc.global), where they are found by normal property lookups.
	// Any global new top statements only get executed once, and so although
	// the previous group of topstatements gets lost, it does not matter.

	// In essence, globalfunction encapsulates the *last* group of topstatements
	// passed to script, and any previous version of globalfunction, along with
	// previous topstatements, gets discarded.

	globalfunction.topstatements = topstatements;

	// If pfd, it is not really necessary to create a global function just
	// so we can do the semantic analysis, we could use p.lastnamedfunc
	// instead if we're careful to insure that p.lastnamedfunc winds up
	// as a property of the global object.

	Scope sc;
	sc.ctor(this, globalfunction);	// create global scope
	sc.src = srctext;
	globalfunction.semantic(&sc);

	msg = sc.errinfo.message;
	if (msg)			// if semantic() failed
	{
	    globalfunction.topstatements[] = null;
	    globalfunction.topstatements = null;
	    globalfunction = null;
	    throw new ScriptException(&sc.errinfo);
	}

	if (pfd)
	    // If expecting a function, that is the only topstatement we should
	    // have had
	    (*pfd).toIR(null);
	else
	{
	    globalfunction.toIR(null);
	}

	// Don't need parse trees anymore, so null'ing the pointer allows
	// the garbage collector to find & free them.
	globalfunction.topstatements[] = null;
	globalfunction.topstatements = null;
    }

    /*******************************
     * Execute program.
     * Throw ScriptException on error.
     */

    void execute(char[][] args)
    {
	// ECMA 10.2.1
	//writef("Program.execute(argc = %d, argv = %p)\n", argc, argv);
	//writef("Program.execute()\n");

	initContext();

	Value[] locals;
	Value ret;
	Value* result;
	CallContext *cc = callcontext;
	Darray arguments;
	Dobject dglobal = cc.global;
	Program program_save;

	// Set argv and argc for execute    
	arguments = new Darray();
	dglobal.Put(TEXT_arguments, arguments, DontDelete | DontEnum);
	arguments.length.putVnumber(args.length);
	for (int i = 0; i < args.length; i++)
	{
	    arguments.Put(i, args[i], DontEnum);
	}

	Value[] p1;
	Value* v;
	version (Win32)		// eh and alloca() not working under linux
	{
	    if (globalfunction.nlocals < 128)
		v = cast(Value*)alloca(globalfunction.nlocals * Value.sizeof);
	}
	if (v)
	    locals = v[0 .. globalfunction.nlocals];
	else
	{
	    p1 = new Value[globalfunction.nlocals];
	    locals = p1;
	}

	// Instantiate global variables as properties of global
	// object with 0 attributes
	globalfunction.instantiate(cc.scopex, cc.variable, 0);

//	cc.scopex.reserve(globalfunction.withdepth + 1);

	// The 'this' value is the global object
	//printf("cc.scopex.ptr = %x, cc.scopex.length = %d\n", cc.scopex.ptr, cc.scopex.length);
	program_save = getProgram();
	try
	{
	    setProgram(this);
	    ret.putVundefined();
	    result = cast(Value*)IR.call(cc, cc.global, globalfunction.code, &ret, locals.ptr);
	}
	finally
	{
	    setProgram(program_save);
	}
	//writef("-Program.execute()\n");
	if (result)
	{
	    ErrInfo errinfo;

	    result.getErrInfo(&errinfo, cc.linnum);
	    cc.linnum = 0;
	    delete p1;
	    throw new ScriptException(&errinfo);
	}

	delete p1;
    }

    void toBuffer(inout tchar[] buf)
    {
	if (globalfunction)
	    globalfunction.toBuffer(buf);
    }

    /***********************************************
     * Get/Set Program associated with this thread.
     * This enables multiple scripts (Programs) running simultaneously
     * in different threads.
     * It is needed because which Program is being run is essentially
     * global data - and this makes it thread local data.
     */

    static Program getProgram()
    {
	ThreadContext *tc;

	tc = ThreadContext.getThreadContext();
	assert(tc != null);
	return tc.program;
    }

    static void setProgram(Program p)
    {
	ThreadContext *tc;

	tc = ThreadContext.getThreadContext();

	assert(tc != null);
	tc.program = p;
    }

}