diff dmdscript_tango/program.d @ 0:55c2951c07be

initial, files origin, premoved tree
author saaadel
date Sun, 24 Jan 2010 12:34:47 +0200
parents
children 8363a4bf6a8f
line wrap: on
line diff
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/dmdscript_tango/program.d	Sun Jan 24 12:34:47 2010 +0200
@@ -0,0 +1,276 @@
+
+/* 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.program;
+
+import std.stdio;
+import std.c.stdlib;
+
+import dmdscript.script;
+import dmdscript.dobject;
+import dmdscript.dglobal;
+import dmdscript.functiondefinition;
+import dmdscript.statement;
+import dmdscript.threadcontext;
+import dmdscript.value;
+import dmdscript.opcodes;
+import dmdscript.darray;
+import dmdscript.parse;
+import dmdscript.scopex;
+import dmdscript.text;
+import dmdscript.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;
+    }
+
+}