changeset 0:55c2951c07be

initial, files origin, premoved tree
author saaadel
date Sun, 24 Jan 2010 12:34:47 +0200
parents
children 987135a700f2
files .classpath .project dmdscript_tango/darguments.d dmdscript_tango/darray.d dmdscript_tango/dboolean.d dmdscript_tango/ddate.d dmdscript_tango/ddeclaredfunction.d dmdscript_tango/derror.d dmdscript_tango/dfunction.d dmdscript_tango/dglobal.d dmdscript_tango/dmath.d dmdscript_tango/dnative.d dmdscript_tango/dnumber.d dmdscript_tango/dobject.d dmdscript_tango/dregexp.d dmdscript_tango/dstring.d dmdscript_tango/expression.d dmdscript_tango/functiondefinition.d dmdscript_tango/identifier.d dmdscript_tango/ir.d dmdscript_tango/irstate.d dmdscript_tango/iterator.d dmdscript_tango/lexer.d dmdscript_tango/license/gpl.txt dmdscript_tango/license/saaadel.readme.txt dmdscript_tango/opcodes.d dmdscript_tango/parse.d dmdscript_tango/program.d dmdscript_tango/property.d dmdscript_tango/protoerror.d dmdscript_tango/scopex.d dmdscript_tango/script.d dmdscript_tango/statement.d dmdscript_tango/symbol.d dmdscript_tango/test/testscript.d dmdscript_tango/text.d dmdscript_tango/textgen/textgen.d dmdscript_tango/threadcontext.d dmdscript_tango/value.d
diffstat 39 files changed, 22565 insertions(+), 0 deletions(-) [+]
line wrap: on
line diff
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/.classpath	Sun Jan 24 12:34:47 2010 +0200
@@ -0,0 +1,6 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<classpath>
+	<classpathentry kind="src" path=""/>
+	<classpathentry kind="con" path="descent.USER_LIBRARY/tango-lib-headers"/>
+	<classpathentry kind="output" path=""/>
+</classpath>
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/.project	Sun Jan 24 12:34:47 2010 +0200
@@ -0,0 +1,17 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<projectDescription>
+	<name>DMDScript-tango</name>
+	<comment></comment>
+	<projects>
+	</projects>
+	<buildSpec>
+		<buildCommand>
+			<name>descent.core.dbuilder</name>
+			<arguments>
+			</arguments>
+		</buildCommand>
+	</buildSpec>
+	<natures>
+		<nature>descent.core.dnature</nature>
+	</natures>
+</projectDescription>
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/dmdscript_tango/darguments.d	Sun Jan 24 12:34:47 2010 +0200
@@ -0,0 +1,173 @@
+
+/* 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.darguments;
+
+import dmdscript.script;
+import dmdscript.dobject;
+import dmdscript.identifier;
+import dmdscript.value;
+import dmdscript.text;
+import dmdscript.property;
+
+// The purpose of Darguments is to implement "value sharing"
+// per ECMA 10.1.8 between the activation object and the
+// arguments object.
+// We implement it by forwarding the property calls from the
+// arguments object to the activation object.
+
+class Darguments : Dobject
+{
+    Dobject actobj;		// activation object
+    Identifier*[] parameters;
+
+    int isDarguments() { return true; }
+
+    this(Dobject caller, Dobject callee, Dobject actobj,
+	    Identifier*[] parameters, Value[] arglist)
+
+    {
+	super(Dobject.getPrototype());
+
+	this.actobj = actobj;
+	this.parameters = parameters;
+
+	if (caller)
+	    Put(TEXT_caller, caller, DontEnum);
+	else
+	    Put(TEXT_caller, &vnull, DontEnum);
+
+	Put(TEXT_callee, callee, DontEnum);
+	Put(TEXT_length, arglist.length, DontEnum);
+
+	for (uint a = 0; a < arglist.length; a++)
+	{
+	    Put(a, &arglist[a], DontEnum);
+	}
+    }
+
+    Value* Get(d_string PropertyName)
+    {
+	d_uint32 index;
+
+	return (StringToIndex(PropertyName, index) && index < parameters.length)
+	    ? actobj.Get(index)
+	    : Dobject.Get(PropertyName);
+    }
+
+    Value* Get(d_uint32 index)
+    {
+	return (index < parameters.length)
+	    ? actobj.Get(index)
+	    : Dobject.Get(index);
+    }
+
+    Value* Get(d_uint32 index, Value* vindex)
+    {
+	return (index < parameters.length)
+	    ? actobj.Get(index, vindex)
+	    : Dobject.Get(index, vindex);
+    }
+
+    Value* Put(d_string PropertyName, Value* value, uint attributes)
+    {
+	d_uint32 index;
+
+	if (StringToIndex(PropertyName, index) && index < parameters.length)
+	    return actobj.Put(PropertyName, value, attributes);
+	else
+	    return Dobject.Put(PropertyName, value, attributes);
+    }
+
+    Value* Put(Identifier* key, Value* value, uint attributes)
+    {
+	d_uint32 index;
+
+	if (StringToIndex(key.value.string, index) && index < parameters.length)
+	    return actobj.Put(key, value, attributes);
+	else
+	    return Dobject.Put(key, value, attributes);
+    }
+
+    Value* Put(d_string PropertyName, Dobject o, uint attributes)
+    {
+	d_uint32 index;
+
+	if (StringToIndex(PropertyName, index) && index < parameters.length)
+	    return actobj.Put(PropertyName, o, attributes);
+	else
+	    return Dobject.Put(PropertyName, o, attributes);
+    }
+
+    Value* Put(d_string PropertyName, d_number n, uint attributes)
+    {
+	d_uint32 index;
+
+	if (StringToIndex(PropertyName, index) && index < parameters.length)
+	    return actobj.Put(PropertyName, n, attributes);
+	else
+	    return Dobject.Put(PropertyName, n, attributes);
+    }
+
+    Value* Put(d_uint32 index, Value* vindex, Value* value, uint attributes)
+    {
+	if (index < parameters.length)
+	    return actobj.Put(index, vindex, value, attributes);
+	else
+	    return Dobject.Put(index, vindex, value, attributes);
+    }
+
+    Value* Put(d_uint32 index, Value* value, uint attributes)
+    {
+	if (index < parameters.length)
+	    return actobj.Put(index, value, attributes);
+	else
+	    return Dobject.Put(index, value, attributes);
+    }
+
+    int CanPut(d_string PropertyName)
+    {
+	d_uint32 index;
+
+	return (StringToIndex(PropertyName, index) && index < parameters.length)
+	    ? actobj.CanPut(PropertyName)
+	    : Dobject.CanPut(PropertyName);
+    }
+
+    int HasProperty(d_string PropertyName)
+    {
+	d_uint32 index;
+
+	return (StringToIndex(PropertyName, index) && index < parameters.length)
+	    ? actobj.HasProperty(PropertyName)
+	    : Dobject.HasProperty(PropertyName);
+    }
+
+    int Delete(d_string PropertyName)
+    {
+	d_uint32 index;
+
+	return (StringToIndex(PropertyName, index) && index < parameters.length)
+	    ? actobj.Delete(PropertyName)
+	    : Dobject.Delete(PropertyName);
+    }
+}
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/dmdscript_tango/darray.d	Sun Jan 24 12:34:47 2010 +0200
@@ -0,0 +1,1100 @@
+
+/* 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.darray;
+
+import std.string;
+import std.c.stdlib;
+
+import dmdscript.script;
+import dmdscript.value;
+import dmdscript.dobject;
+import dmdscript.threadcontext;
+import dmdscript.identifier;
+import dmdscript.dfunction;
+import dmdscript.text;
+import dmdscript.property;
+import dmdscript.errmsgs;
+import dmdscript.dnative;
+import dmdscript.program;
+
+/* ===================== Darray_constructor ==================== */
+
+class Darray_constructor : Dfunction
+{
+    this(ThreadContext *tc)
+    {
+	super(1, tc.Dfunction_prototype);
+	name = "Array";
+    }
+
+    void* Construct(CallContext *cc, Value *ret, Value[] arglist)
+    {
+	// ECMA 15.4.2
+	Darray a;
+
+	a = new Darray();
+	if (arglist.length == 0)
+	{
+	    a.ulength = 0;
+	    a.length.number = 0;
+	}
+	else if (arglist.length == 1)
+	{
+	    Value* v = &arglist[0];
+
+	    if (v.isNumber())
+	    {
+		d_uint32 len;
+
+		len = v.toUint32();
+		if (cast(double) len != v.number)
+		{   ErrInfo errinfo;
+
+		    ret.putVundefined();
+		    return RangeError(&errinfo, ERR_ARRAY_LEN_OUT_OF_BOUNDS, v.number);
+		}
+		else
+		{   a.ulength = len;
+		    a.length.number = len;
+		    /+
+		    if (len > 16)
+		    {
+			//writef("setting %p dimension to %d\n", &a.proptable, len);
+			if (len > 10000)
+			    len = 10000;		// cap so we don't run out of memory
+			a.proptable.roots.setDim(len);
+			a.proptable.roots.zero();
+		    }
+		    +/
+		}
+	    }
+	    else
+	    {
+		a.ulength = 1;
+		a.length.number = 1;
+		a.Put(cast(d_uint32) 0, v, 0);
+	    }
+	}
+	else
+	{
+	    //if (arglist.length > 10) writef("Array constructor: arglist.length = %d\n", arglist.length);
+	    /+
+	    if (arglist.length > 16)
+	    {
+		a.proptable.roots.setDim(arglist.length);
+		a.proptable.roots.zero();
+	    }
+	    +/
+	    a.ulength = arglist.length;
+	    a.length.number = arglist.length;
+	    for (uint k = 0; k < arglist.length; k++)
+	    {
+		a.Put(k, &arglist[k], 0);
+	    }
+	}
+	Value.copy(ret, &a.value);
+	//writef("Darray_constructor.Construct(): length = %g\n", a.length.number);
+	return null;
+    }
+
+    void* Call(CallContext *cc, Dobject othis, Value* ret, Value[] arglist)
+    {
+	// ECMA 15.4.1
+	return Construct(cc, ret, arglist);
+    }
+}
+
+
+/* ===================== Darray_prototype_toString ================= */
+
+void *Darray_prototype_toString(Dobject pthis, CallContext *cc, Dobject othis, Value *ret, Value[] arglist)
+{
+    //writef("Darray_prototype_toString()\n");
+    array_join(othis, ret, null);
+    return null;
+}
+
+/* ===================== Darray_prototype_toLocaleString ================= */
+
+void *Darray_prototype_toLocaleString(Dobject pthis, CallContext *cc, Dobject othis, Value *ret, Value[] arglist)
+{
+    // ECMA v3 15.4.4.3
+    tchar[] separator;
+    d_string r;
+    d_uint32 len;
+    d_uint32 k;
+    Value* v;
+
+    //writef("array_join(othis = %p)\n", othis);
+
+    if (!othis.isClass(TEXT_Array))
+    {
+	ret.putVundefined();
+	ErrInfo errinfo;
+	return Dobject.RuntimeError(&errinfo, ERR_TLS_NOT_TRANSFERRABLE);
+    }
+
+    v = othis.Get(TEXT_length);
+    len = v ? v.toUint32() : 0;
+
+    Program prog = cc.prog;
+    if (!prog.slist)
+    {
+	// Determine what list separator is only once per thread
+	//prog.slist = list_separator(prog.lcid);
+	prog.slist = ",";
+    }
+    separator = prog.slist;
+
+    for (k = 0; k != len; k++)
+    {
+	if (k)
+	    r ~= separator;
+	v = othis.Get(k);
+	if (v && !v.isUndefinedOrNull())
+	{   Dobject ot;
+
+	    ot = v.toObject();
+	    v = ot.Get(TEXT_toLocaleString);
+	    if (v && !v.isPrimitive())	// if it's an Object
+	    {   void* a;
+		Dobject o;
+		Value rt;
+
+		o = v.object;
+		rt.putVundefined();
+		a = o.Call(cc, ot, &rt, null);
+		if (a)			// if exception was thrown
+		    return a;
+		r ~= rt.toString();
+	    }
+	}
+    }
+
+    ret.putVstring(r);
+    return null;
+}
+
+/* ===================== Darray_prototype_concat ================= */
+
+void *Darray_prototype_concat(Dobject pthis, CallContext *cc, Dobject othis, Value *ret, Value[] arglist)
+{
+    // ECMA v3 15.4.4.4
+    Darray A;
+    Darray E;
+    Value* v;
+    d_uint32 k;
+    d_uint32 n;
+    d_uint32 a;
+
+    A = new Darray();
+    n = 0;
+    v = &othis.value;
+    for (a = 0; ; a++)
+    {
+	if (!v.isPrimitive() && v.object.isDarray())
+	{   d_uint32 len;
+
+	    E = cast(Darray)v.object;
+	    len = E.ulength;
+	    for (k = 0; k != len; k++)
+	    {
+		v = E.Get(k);
+		if (v)
+		    A.Put(n, v, 0);
+		n++;
+	    }
+	}
+	else
+	{
+	    A.Put(n, v, 0);
+	    n++;
+	}
+	if (a == arglist.length)
+	    break;
+	v = &arglist[a];
+    }
+
+    A.Put(TEXT_length, n, DontDelete | DontEnum);
+    Value.copy(ret, &A.value);
+    return null;
+}
+
+/* ===================== Darray_prototype_join ================= */
+
+void *Darray_prototype_join(Dobject pthis, CallContext *cc, Dobject othis, Value *ret, Value[] arglist)
+{
+    array_join(othis, ret, arglist);
+    return null;
+}
+
+void array_join(Dobject othis, Value* ret, Value[] arglist)
+{
+    // ECMA 15.4.4.3
+    d_string separator;
+    d_string r;
+    d_uint32 len;
+    d_uint32 k;
+    Value* v;
+
+    //writef("array_join(othis = %p)\n", othis);
+    v = othis.Get(TEXT_length);
+    len = v ? v.toUint32() : 0;
+    if (arglist.length == 0)
+	separator = TEXT_comma;
+    else
+	separator = arglist[0].toString();
+
+    for (k = 0; k != len; k++)
+    {
+	if (k)
+	    r ~= separator;
+	v = othis.Get(k);
+	if (v && !v.isUndefinedOrNull())
+	    r ~= v.toString();
+    }
+
+    ret.putVstring(r);
+}
+
+/* ===================== Darray_prototype_toSource ================= */
+
+void *Darray_prototype_toSource(Dobject pthis, CallContext *cc, Dobject othis, Value *ret, Value[] arglist)
+{
+    tchar[] separator;
+    d_string r;
+    d_uint32 len;
+    d_uint32 k;
+    Value* v;
+
+    v = othis.Get(TEXT_length);
+    len = v ? v.toUint32() : 0;
+    separator = ",";
+
+    r = "[";
+    for (k = 0; k != len; k++)
+    {
+	if (k)
+	    r ~= separator;
+	v = othis.Get(k);
+	if (v && !v.isUndefinedOrNull())
+	    r ~= v.toSource();
+    }
+    r ~= "]";
+
+    ret.putVstring(r);
+    return null;
+}
+
+
+/* ===================== Darray_prototype_pop ================= */
+
+void *Darray_prototype_pop(Dobject pthis, CallContext *cc, Dobject othis, Value *ret, Value[] arglist)
+{
+    // ECMA v3 15.4.4.6
+    Value* v;
+    d_uint32 u;
+
+    // If othis is a Darray, then we can optimize this significantly
+    v = othis.Get(TEXT_length);
+    if (!v)
+	v = &vundefined;
+    u = v.toUint32();
+    if (u == 0)
+    {
+	othis.Put(TEXT_length, 0.0, DontDelete | DontEnum);
+	ret.putVundefined();
+    }
+    else
+    {
+	v = othis.Get(u - 1);
+	if (!v)
+	    v = &vundefined;
+	Value.copy(ret, v);
+	othis.Delete(u - 1);
+	othis.Put(TEXT_length, u - 1, DontDelete | DontEnum);
+    }
+    return null;
+}
+
+/* ===================== Darray_prototype_push ================= */
+
+void *Darray_prototype_push(Dobject pthis, CallContext *cc, Dobject othis, Value *ret, Value[] arglist)
+{
+    // ECMA v3 15.4.4.7
+    Value* v;
+    d_uint32 u;
+    d_uint32 a;
+
+    // If othis is a Darray, then we can optimize this significantly
+    v = othis.Get(TEXT_length);
+    if (!v)
+	v = &vundefined;
+    u = v.toUint32();
+    for (a = 0; a < arglist.length; a++)
+    {
+	othis.Put(u + a, &arglist[a], 0);
+    }
+    othis.Put(TEXT_length, u + a, DontDelete | DontEnum);
+    ret.putVnumber(u + a);
+    return null;
+}
+
+/* ===================== Darray_prototype_reverse ================= */
+
+void *Darray_prototype_reverse(Dobject pthis, CallContext *cc, Dobject othis, Value *ret, Value[] arglist)
+{
+    // ECMA 15.4.4.4
+    d_uint32 a;
+    d_uint32 b;
+    Value* va;
+    Value* vb;
+    Value* v;
+    d_uint32 pivot;
+    d_uint32 len;
+    Value tmp;
+
+    v = othis.Get(TEXT_length);
+    len = v ? v.toUint32() : 0;
+    pivot = len / 2;
+    for (a = 0; a != pivot; a++)
+    {
+	b = len - a - 1;
+	//writef("a = %d, b = %d\n", a, b);
+	va = othis.Get(a);
+	if (va)
+	    Value.copy(&tmp, va);
+	vb = othis.Get(b);
+	if (vb)
+	    othis.Put(a, vb, 0);
+	else
+	    othis.Delete(a);
+
+	if (va)
+	    othis.Put(b, &tmp, 0);
+	else
+	    othis.Delete(b);
+    }
+    Value.copy(ret, &othis.value);
+    return null;
+}
+
+/* ===================== Darray_prototype_shift ================= */
+
+void *Darray_prototype_shift(Dobject pthis, CallContext *cc, Dobject othis, Value *ret, Value[] arglist)
+{
+    // ECMA v3 15.4.4.9
+    Value* v;
+    Value* result;
+    d_uint32 len;
+    d_uint32 k;
+
+    // If othis is a Darray, then we can optimize this significantly
+    //writef("shift(othis = %p)\n", othis);
+    v = othis.Get(TEXT_length);
+    if (!v)
+	v = &vundefined;
+    len = v.toUint32();
+    if (len)
+    {
+	result = othis.Get(0u);
+	Value.copy(ret, result);
+	for (k = 1; k != len; k++)
+	{
+	    v = othis.Get(k);
+	    if (v)
+	    {
+		othis.Put(k - 1, v, 0);
+	    }
+	    else
+	    {
+		othis.Delete(k - 1);
+	    }
+	}
+	othis.Delete(len - 1);
+	len--;
+    }
+    else
+	Value.copy(ret, &vundefined);
+
+    othis.Put(TEXT_length, len, DontDelete | DontEnum);
+    return null;
+}
+
+/* ===================== Darray_prototype_slice ================= */
+
+void *Darray_prototype_slice(Dobject pthis, CallContext *cc, Dobject othis, Value *ret, Value[] arglist)
+{
+    // ECMA v3 15.4.4.10
+    d_uint32 len;
+    d_uint32 n;
+    d_uint32 k;
+    d_uint32 r8;
+    d_number start;
+    d_number end;
+    Value* v;
+    Darray A;
+
+    v = othis.Get(TEXT_length);
+    if (!v)
+	v = &vundefined;
+    len = v.toUint32();
+
+    switch (arglist.length)
+    {
+	case 0:
+	    start = vundefined.toUint32();
+	    end = start;
+	    break;
+
+	case 1:
+	    start = arglist[0].toInteger();
+	    end = len;
+	    break;
+
+	default:
+	    start = arglist[0].toInteger();
+	    end   = arglist[1].toInteger();
+	    break;
+    }
+
+    if (start < 0)
+    {
+	k = len + cast(d_uint32) start;
+	if (cast(d_int32)k < 0)
+	    k = 0;
+    }
+    else
+    {
+	k = cast(d_uint32) start;
+	if (len < k)
+	    k = len;
+    }
+
+    if (end < 0)
+    {
+	r8 = len + cast(d_uint32) end;
+	if (cast(d_int32)r8 < 0)
+	    r8 = 0;
+    }
+    else
+    {
+	r8 = cast(d_uint32) end;
+	if (len < cast(d_uint32) end)
+	    r8 = len;
+    }
+
+    A = new Darray();
+    for (n = 0; k < r8; k++)
+    {
+	v = othis.Get(k);
+	if (v)
+	{
+	    A.Put(n, v, 0);
+	}
+	n++;
+    }
+
+    A.Put(TEXT_length, n, DontDelete | DontEnum);
+    Value.copy(ret, &A.value);
+    return null;
+}
+
+/* ===================== Darray_prototype_sort ================= */
+
+static Dobject comparefn;
+static CallContext *comparecc;
+
+extern (C) int compare_value(void* x, void* y)
+{
+    Value* vx = cast(Value*)x;
+    Value* vy = cast(Value*)y;
+    d_string sx;
+    d_string sy;
+    int cmp;
+
+    //writef("compare_value()\n");
+    if (vx.isUndefined())
+    {
+	cmp = (vy.isUndefined()) ? 0 : 1;
+    }
+    else if (vy.isUndefined())
+	cmp = -1;
+    else
+    {
+	if (comparefn)
+	{   Value arglist[2];
+	    Value ret;
+	    Value* v;
+	    d_number n;
+
+	    Value.copy(&arglist[0], vx);
+	    Value.copy(&arglist[1], vy);
+	    ret.putVundefined();
+	    comparefn.Call(comparecc, comparefn, &ret, arglist);
+	    n = ret.toNumber();
+	    if (n < 0)
+		cmp = -1;
+	    else if (n > 0)
+		cmp = 1;
+	    else
+		cmp = 0;
+	}
+	else
+	{
+	    sx = vx.toString();
+	    sy = vy.toString();
+	    cmp = std.string.cmp(sx, sy);
+	    if (cmp < 0)
+		cmp = -1;
+	    else if (cmp > 0)
+		cmp = 1;
+	}
+    }
+    return cmp;
+}
+
+void *Darray_prototype_sort(Dobject pthis, CallContext *cc, Dobject othis, Value *ret, Value[] arglist)
+{
+    // ECMA v3 15.4.4.11
+    Value* v;
+    d_uint32 len;
+    uint u;
+
+    //writef("Array.prototype.sort()\n");
+    v = othis.Get(TEXT_length);
+    len = v ? v.toUint32() : 0;
+
+    // This is not optimal, as isArrayIndex is done at least twice
+    // for every array member. Additionally, the qsort() by index
+    // can be avoided if we can deduce it is not a sparse array.
+
+    Property *p;
+    Value[] pvalues;
+    d_uint32[] pindices;
+    d_uint32 parraydim;
+    d_uint32 nprops;
+
+    // First, size & alloc our temp array
+    if (len < 100)
+    {	// Probably not too sparse an array
+	parraydim = len;
+    }
+    else
+    {
+	parraydim = 0;
+	foreach (inout Property p; *othis.proptable)
+	{   if (p.attributes == 0)	// don't count special properties
+		parraydim++;
+	}
+	if (parraydim > len)		// could theoretically happen
+	    parraydim = len;
+    }
+
+    Value[] p1 = null;
+    Value* v1;
+    version (Win32)	// eh and alloca() not working under linux
+    {
+	if (parraydim < 128)
+	    v1 = cast(Value*)alloca(parraydim * Value.sizeof);
+    }
+    if (v1)
+	pvalues = v1[0 .. parraydim];
+    else
+    {
+	p1 = new Value[parraydim];
+	pvalues = p1;
+    }
+
+    d_uint32[] p2 = null;
+    d_uint32* p3;
+    version (Win32)
+    {
+	if (parraydim < 128)
+	    p3 = cast(d_uint32*)alloca(parraydim * d_uint32.sizeof);
+    }
+    if (p3)
+	pindices = p3[0 .. parraydim];
+    else
+    {
+	p2 = new d_uint32[parraydim];
+	pindices = p2;
+    }
+
+    // Now fill it with all the Property's that are array indices
+    nprops = 0;
+    foreach (Value key, inout Property p; *othis.proptable)
+    {	d_uint32 index;
+
+	if (p.attributes == 0 && key.isArrayIndex(index))
+	{
+	    pindices[nprops] = index;
+	    Value.copy(&pvalues[nprops], &p.value);
+	    nprops++;
+	}
+    }
+
+    synchronized
+    {
+	comparefn = null;
+	comparecc = cc;
+	if (arglist.length)
+	{
+	    if (!arglist[0].isPrimitive())
+		comparefn = arglist[0].object;
+	}
+
+	// Sort pvalues[]
+	std.c.stdlib.qsort(pvalues.ptr, nprops, Value.sizeof, &compare_value);
+
+	comparefn = null;
+	comparecc = null;
+    }
+
+    // Stuff the sorted value's back into the array
+    for (u = 0; u < nprops; u++)
+    {	d_uint32 index;
+
+	othis.Put(u, &pvalues[u], 0);
+	index = pindices[u];
+	if (index >= nprops)
+	{
+	    othis.Delete(index);
+	}
+    }
+
+    delete p1;
+    delete p2;
+
+    ret.putVobject(othis);
+    return null;
+}
+
+/* ===================== Darray_prototype_splice ================= */
+
+void *Darray_prototype_splice(Dobject pthis, CallContext *cc, Dobject othis, Value *ret, Value[] arglist)
+{
+    // ECMA v3 15.4.4.12
+    d_uint32 len;
+    d_uint32 k;
+    d_number start;
+    d_number deleteCount;
+    Value* v;
+    Darray A;
+    d_uint32 a;
+    d_uint32 delcnt;
+    d_uint32 inscnt;
+    d_uint32 startidx;
+
+    v = othis.Get(TEXT_length);
+    if (!v)
+	v = &vundefined;
+    len = v.toUint32();
+
+    switch (arglist.length)
+    {
+	case 0:
+	    start = vundefined.toUint32();
+	    deleteCount = start;
+	    break;
+
+	case 1:
+	    start = arglist[0].toInteger();
+	    deleteCount = vundefined.toUint32();
+	    break;
+
+	default:
+	    start = arglist[0].toInteger();
+	    deleteCount = arglist[1].toInteger();
+	    break;
+    }
+
+    if (start < 0)
+    {
+	startidx = len + cast(d_uint32) start;
+	if (cast(d_int32)startidx < 0)
+	    startidx = 0;
+    }
+    else
+    {
+	startidx = cast(d_uint32) start;
+	if (len < startidx)
+	    startidx = len;
+    }
+
+    A = new Darray();
+
+    delcnt = (deleteCount > 0) ? cast(d_uint32) deleteCount : 0;
+    if (delcnt > len - startidx)
+	delcnt = len - startidx;
+
+    // If deleteCount is not specified, ECMA implies it should
+    // be 0, while "JavaScript The Definitive Guide" says it should
+    // be delete to end of array. Jscript doesn't implement splice().
+    // We'll do it the Guide way.
+    if (arglist.length < 2)
+	delcnt = len - startidx;
+
+    //writef("Darray.splice(startidx = %d, delcnt = %d)\n", startidx, delcnt);
+    for (k = 0; k != delcnt; k++)
+    {
+	v = othis.Get(startidx + k);
+	if (v)
+	    A.Put(k, v, 0);
+    }
+
+    A.Put(TEXT_length, delcnt, DontDelete | DontEnum);
+    inscnt = (arglist.length > 2) ? arglist.length - 2 : 0;
+    if (inscnt != delcnt)
+    {
+	if (inscnt <= delcnt)
+	{
+	    for (k = startidx; k != (len - delcnt); k++)
+	    {
+		v = othis.Get(k + delcnt);
+		if (v)
+		    othis.Put(k + inscnt, v, 0);
+		else
+		    othis.Delete(k + inscnt);
+	    }
+
+	    for (k = len; k != (len - delcnt + inscnt); k--)
+		othis.Delete(k - 1);
+	}
+	else
+	{
+	    for (k = len - delcnt; k != startidx; k--)
+	    {
+		v = othis.Get(k + delcnt - 1);
+		if (v)
+		    othis.Put(k + inscnt - 1, v, 0);
+		else
+		    othis.Delete(k + inscnt - 1);
+	    }
+	}
+    }
+    k = startidx;
+    for (a = 2; a < arglist.length; a++)
+    {
+	v = &arglist[a];
+	othis.Put(k, v, 0);
+	k++;
+    }
+
+    othis.Put(TEXT_length, len - delcnt + inscnt, DontDelete | DontEnum);
+    Value.copy(ret, &A.value);
+    return null;
+}
+
+/* ===================== Darray_prototype_unshift ================= */
+
+void *Darray_prototype_unshift(Dobject pthis, CallContext *cc, Dobject othis, Value *ret, Value[] arglist)
+{
+    // ECMA v3 15.4.4.13
+    Value* v;
+    d_uint32 len;
+    d_uint32 k;
+
+    v = othis.Get(TEXT_length);
+    if (!v)
+	v = &vundefined;
+    len = v.toUint32();
+
+    for (k = len; k; k--)
+    {
+	v = othis.Get(k - 1);
+	if (v)
+	    othis.Put(k + arglist.length - 1, v, 0);
+	else
+	    othis.Delete(k + arglist.length - 1);
+    }
+
+    for (k = 0; k < arglist.length; k++)
+    {
+	othis.Put(k, &arglist[k], 0);
+    }
+    othis.Put(TEXT_length, len + arglist.length, DontDelete | DontEnum);
+    ret.putVnumber(len + arglist.length);
+    return null;
+}
+
+/* =========================== Darray_prototype =================== */
+
+class Darray_prototype : Darray
+{
+    this(ThreadContext *tc)
+    {
+	super(tc.Dobject_prototype);
+	Dobject f = tc.Dfunction_prototype;
+
+	Put(TEXT_constructor, tc.Darray_constructor, DontEnum);
+
+	static NativeFunctionData nfd[] =
+	[
+	    {   &TEXT_toString, &Darray_prototype_toString, 0 },
+	    {   &TEXT_toLocaleString, &Darray_prototype_toLocaleString, 0 },
+	    {   &TEXT_toSource, &Darray_prototype_toSource, 0 },
+	    {   &TEXT_concat, &Darray_prototype_concat, 1 },
+	    {   &TEXT_join, &Darray_prototype_join, 1 },
+	    {   &TEXT_pop, &Darray_prototype_pop, 0 },
+	    {   &TEXT_push, &Darray_prototype_push, 1 },
+	    {   &TEXT_reverse, &Darray_prototype_reverse, 0 },
+	    {   &TEXT_shift, &Darray_prototype_shift, 0, },
+	    {   &TEXT_slice, &Darray_prototype_slice, 2 },
+	    {   &TEXT_sort, &Darray_prototype_sort, 1 },
+	    {   &TEXT_splice, &Darray_prototype_splice, 2 },
+	    {   &TEXT_unshift, &Darray_prototype_unshift, 1 },
+	];
+
+	DnativeFunction.init(this, nfd, DontEnum);
+    }
+}
+
+
+/* =========================== Darray =================== */
+
+class Darray : Dobject
+{
+    Value length;		// length property
+    d_uint32 ulength;
+
+    this()
+    {
+	this(getPrototype());
+    }
+
+    this(Dobject prototype)
+    {
+	super(prototype);
+	length.putVnumber(0);
+	ulength = 0;
+	classname = TEXT_Array;
+    }
+
+    Value* Put(Identifier* key, Value* value, uint attributes)
+    {
+	Value* result = proptable.put(&key.value, key.value.hash, value, attributes);
+	if (!result)
+	    Put(key.value.string, value, attributes);
+	return null;
+    }
+
+    Value* Put(d_string name, Value* v, uint attributes)
+    {
+	d_uint32 i;
+	uint c;
+	Value* result;
+
+	// ECMA 15.4.5.1
+	result = proptable.put(name, v, attributes);
+	if (!result)
+	{
+	    if (name == TEXT_length)
+	    {
+		i = v.toUint32();
+		if (i != v.toInteger())
+		{   ErrInfo errinfo;
+
+		    return Dobject.RuntimeError(&errinfo, ERR_LENGTH_INT);
+		}
+		if (i < ulength)
+		{
+		    // delete all properties with keys >= i
+		    d_uint32[] todelete;
+
+		    foreach (Value key, inout Property p; *proptable)
+		    {	d_uint32 j;
+
+			j = key.toUint32();
+			if (j >= i)
+			    todelete ~= j;
+		    }
+		    foreach (d_uint32 j; todelete)
+		    {
+			proptable.del(j);
+		    }
+		}
+		ulength = i;
+		length.number = i;
+		proptable.put(name, v, attributes | DontDelete | DontEnum);
+	    }
+
+	    // if (name is an array index i)
+
+	    i = 0;
+	    for (size_t j = 0; j < name.length; j++)
+	    {   ulong k;
+
+		c = name[j];
+		if (c == '0' && i == 0 && name.length > 1)
+		    goto Lret;
+		if (c >= '0' && c <= '9')
+		{   k = i * cast(ulong)10 + c - '0';
+		    i = cast(d_uint32)k;
+		    if (i != k)
+			goto Lret;		// overflow
+		}
+		else
+		    goto Lret;
+	    }
+	    if (i >= ulength)
+	    {
+		if (i == 0xFFFFFFFF)
+		    goto Lret;
+		ulength = i + 1;
+		length.number = ulength;
+	    }
+	}
+      Lret:
+	return null;
+    }
+
+    Value* Put(d_string name, Dobject o, uint attributes)
+    {
+	return Put(name, &o.value, attributes);
+    }
+
+    Value* Put(d_string PropertyName, d_number n, uint attributes)
+    {
+	Value v;
+
+	v.putVnumber(n);
+	return Put(PropertyName, &v, attributes);
+    }
+
+    Value* Put(d_string PropertyName, d_string string, uint attributes)
+    {
+	Value v;
+
+	v.putVstring(string);
+	return Put(PropertyName, &v, attributes);
+    }
+
+    Value* Put(d_uint32 index, Value* vindex, Value* value, uint attributes)
+    {
+	if (index >= ulength)
+	    ulength = index + 1;
+
+	proptable.put(vindex, index ^ 0x55555555 /*Value.calcHash(index)*/, value, attributes);
+	return null;
+    }
+
+    Value* Put(d_uint32 index, Value* value, uint attributes)
+    {
+	if (index >= ulength)
+	{   ulength = index + 1;
+	    length.number = ulength;
+	}
+
+	proptable.put(index, value, attributes);
+	return null;
+    }
+
+    Value* Put(d_uint32 index, d_string string, uint attributes)
+    {
+	if (index >= ulength)
+	{   ulength = index + 1;
+	    length.number = ulength;
+	}
+
+	proptable.put(index, string, attributes);
+	return null;
+    }
+
+    Value* Get(Identifier* id)
+    {
+	//writef("Darray.Get(%p, '%s')\n", &proptable, PropertyName);
+	if (id.value.string == TEXT_length)
+	{   length.number = ulength;
+	    return &length;
+	}
+	else
+	    return Dobject.Get(id);
+    }
+
+    Value* Get(d_string PropertyName, uint hash)
+    {
+	//writef("Darray.Get(%p, '%s')\n", &proptable, PropertyName);
+	if (PropertyName == TEXT_length)
+	{   length.number = ulength;
+	    return &length;
+	}
+	else
+	    return Dobject.Get(PropertyName, hash);
+    }
+
+    Value* Get(d_uint32 index)
+    {   Value* v;
+
+	//writef("Darray.Get(%p, %d)\n", &proptable, index);
+	v = proptable.get(index);
+	return v;
+    }
+
+    Value* Get(d_uint32 index, Value* vindex)
+    {   Value* v;
+
+	//writef("Darray.Get(%p, %d)\n", &proptable, index);
+	v = proptable.get(vindex, index ^ 0x55555555 /*Value.calcHash(index)*/);
+	return v;
+    }
+
+    int Delete(d_string PropertyName)
+    {
+	// ECMA 8.6.2.5
+	//writef("Darray.Delete('%ls')\n", d_string_ptr(PropertyName));
+	if (PropertyName == TEXT_length)
+	    return 0;		// can't delete 'length' property
+	else
+	    return proptable.del(PropertyName);
+    }
+
+    int Delete(d_uint32 index)
+    {
+	// ECMA 8.6.2.5
+	return proptable.del(index);
+    }
+
+
+    static Dfunction getConstructor()
+    {
+	ThreadContext *tc = ThreadContext.getThreadContext();
+	assert(tc);
+	return tc.Darray_constructor;
+    }
+
+    static Dobject getPrototype()
+    {
+	ThreadContext *tc = ThreadContext.getThreadContext();
+	assert(tc);
+	return tc.Darray_prototype;
+    }
+
+    static void init(ThreadContext *tc)
+    {
+	tc.Darray_constructor = new Darray_constructor(tc);
+	tc.Darray_prototype = new Darray_prototype(tc);
+
+	tc.Darray_constructor.Put(TEXT_prototype, tc.Darray_prototype, DontEnum | DontDelete | ReadOnly);
+    }
+}
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/dmdscript_tango/dboolean.d	Sun Jan 24 12:34:47 2010 +0200
@@ -0,0 +1,178 @@
+
+/* 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.dboolean;
+
+import dmdscript.script;
+import dmdscript.dobject;
+import dmdscript.value;
+import dmdscript.threadcontext;
+import dmdscript.dfunction;
+import dmdscript.text;
+import dmdscript.property;
+import dmdscript.errmsgs;
+import dmdscript.dnative;
+
+/* ===================== Dboolean_constructor ==================== */
+
+class Dboolean_constructor : Dfunction
+{
+    this(ThreadContext *tc)
+    {
+	super(1, tc.Dfunction_prototype);
+	name = "Boolean";
+    }
+
+    void *Construct(CallContext *cc, Value *ret, Value[] arglist)
+    {
+	// ECMA 15.6.2
+	d_boolean b;
+	Dobject o;
+
+	b = (arglist.length) ? arglist[0].toBoolean() : false;
+	o = new Dboolean(b);
+	ret.putVobject(o);
+	return null;
+    }
+
+    void *Call(CallContext *cc, Dobject othis, Value* ret, Value[] arglist)
+    {
+	// ECMA 15.6.1
+	d_boolean b;
+
+	b = (arglist.length) ? arglist[0].toBoolean() : false;
+	ret.putVboolean(b);
+	return null;
+    }
+}
+
+
+/* ===================== Dboolean_prototype_toString =============== */
+
+void* Dboolean_prototype_toString(Dobject pthis, CallContext *cc, Dobject othis, Value *ret, Value[] arglist)
+{
+    // othis must be a Boolean
+    if (!othis.isClass(TEXT_Boolean))
+    {
+	ErrInfo errinfo;
+
+	ret.putVundefined();
+	return Dobject.RuntimeError(&errinfo, errmsgtbl[ERR_FUNCTION_WANTS_BOOL],
+		TEXT_toString,
+		othis.classname);
+    }
+    else
+    {	Value *v;
+
+	v = &(cast(Dboolean)othis).value;
+	ret.putVstring(v.toString());
+    }
+    return null;
+}
+
+/* ===================== Dboolean_prototype_valueOf =============== */
+
+void* Dboolean_prototype_valueOf(Dobject pthis, CallContext *cc, Dobject othis, Value *ret, Value[] arglist)
+{
+    //FuncLog f("Boolean.prototype.valueOf()");
+    //logflag = 1;
+
+    // othis must be a Boolean
+    if (!othis.isClass(TEXT_Boolean))
+    {
+	ErrInfo errinfo;
+
+	ret.putVundefined();
+	return Dobject.RuntimeError(&errinfo, errmsgtbl[ERR_FUNCTION_WANTS_BOOL],
+		TEXT_valueOf,
+		othis.classname);
+    }
+    else
+    {	Value *v;
+
+	v = &(cast(Dboolean)othis).value;
+	Value.copy(ret, v);
+    }
+    return null;
+}
+
+/* ===================== Dboolean_prototype ==================== */
+
+class Dboolean_prototype : Dboolean
+{
+    this(ThreadContext *tc)
+    {
+	super(tc.Dobject_prototype);
+	Dobject f = tc.Dfunction_prototype;
+
+	Put(TEXT_constructor, tc.Dboolean_constructor, DontEnum);
+
+	static NativeFunctionData nfd[] =
+	[
+	    {	&TEXT_toString, &Dboolean_prototype_toString, 0 },
+	    {   &TEXT_valueOf,  &Dboolean_prototype_valueOf,  0 },
+	];
+
+	DnativeFunction.init(this, nfd, DontEnum);
+    }
+}
+
+
+/* ===================== Dboolean ==================== */
+
+class Dboolean : Dobject
+{
+    this(d_boolean b)
+    {
+	super(Dboolean.getPrototype());
+	value.putVboolean(b);
+	classname = TEXT_Boolean;
+    }
+
+    this(Dobject prototype)
+    {
+	super(prototype);
+	value.putVboolean(false);
+	classname = TEXT_Boolean;
+    }
+
+    static Dfunction getConstructor()
+    {
+	ThreadContext *tc = ThreadContext.getThreadContext();
+	assert(tc);
+	return tc.Dboolean_constructor;
+    }
+
+    static Dobject getPrototype()
+    {
+	ThreadContext *tc = ThreadContext.getThreadContext();
+	assert(tc);
+	return tc.Dboolean_prototype;
+    }
+
+    static void init(ThreadContext *tc)
+    {
+	tc.Dboolean_constructor = new Dboolean_constructor(tc);
+	tc.Dboolean_prototype = new Dboolean_prototype(tc);
+
+	tc.Dboolean_constructor.Put(TEXT_prototype, tc.Dboolean_prototype, DontEnum | DontDelete | ReadOnly);
+    }
+}
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/dmdscript_tango/ddate.d	Sun Jan 24 12:34:47 2010 +0200
@@ -0,0 +1,1527 @@
+
+/* 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.ddate;
+
+import std.math;
+import std.date;
+
+import dmdscript.script;
+import dmdscript.dobject;
+import dmdscript.value;
+import dmdscript.threadcontext;
+import dmdscript.dfunction;
+import dmdscript.dnative;
+import dmdscript.property;
+import dmdscript.text;
+import dmdscript.errmsgs;
+
+version = DATETOSTRING;			// use DateToString
+
+enum TIMEFORMAT
+{
+	String,
+	DateString,
+	TimeString,
+	LocaleString,
+	LocaleDateString,
+	LocaleTimeString,
+	UTCString,
+}
+
+d_time parseDateString(CallContext *cc, d_string s)
+{
+    return std.date.parse(s);
+}
+
+d_string dateToString(CallContext *cc, d_time t, TIMEFORMAT tf)
+{   tchar[] p;
+
+    if (t == d_time_nan)
+	p = "Invalid Date";
+    else
+    {
+	switch (tf)
+	{
+	    case TIMEFORMAT.String:
+		t = std.date.LocalTimetoUTC(t);
+		p = std.date.toString(t);
+		break;
+
+	    case TIMEFORMAT.DateString:
+		t = std.date.LocalTimetoUTC(t);
+		p = std.date.toDateString(t);
+		break;
+
+	    case TIMEFORMAT.TimeString:
+		t = std.date.LocalTimetoUTC(t);
+		p = std.date.toTimeString(t);
+		break;
+
+	    case TIMEFORMAT.LocaleString:
+		//p = std.date.toLocaleString(t);
+		p = std.date.toString(t);
+		break;
+
+	    case TIMEFORMAT.LocaleDateString:
+		//p = std.date.toLocaleDateString(t);
+		p = std.date.toDateString(t);
+		break;
+
+	    case TIMEFORMAT.LocaleTimeString:
+		//p = std.date.toLocaleTimeString(t);
+		p = std.date.toTimeString(t);
+		break;
+
+	    case TIMEFORMAT.UTCString:
+		p = std.date.toUTCString(t);
+		//p = std.date.toString(t);
+		break;
+
+	    default:
+		assert(0);
+	}
+    }
+    return p;
+}
+
+
+/* ===================== Ddate.constructor functions ==================== */
+
+void* Ddate_parse(Dobject pthis, CallContext *cc, Dobject othis, Value* ret, Value[] arglist)
+{
+
+    // ECMA 15.9.4.2
+    d_string s;
+    d_time n;
+
+    if (arglist.length == 0)
+	n = d_time_nan;
+    else
+    {
+	s = arglist[0].toString();
+	n = parseDateString(cc, s);
+    }
+
+    ret.putVtime(n);
+    return null;
+}
+
+void* Ddate_UTC(Dobject pthis, CallContext *cc, Dobject othis, Value* ret, Value[] arglist)
+{
+    // ECMA 15.9.4.3 - 15.9.4.10
+
+    d_time n;
+
+    d_time year;
+    d_time month = 0;
+    d_time date = 0;
+    d_time hours = 0;
+    d_time minutes = 0;
+    d_time seconds = 0;
+    d_time ms = 0;
+
+    d_time day;
+    d_time time = 0;
+
+    switch (arglist.length)
+    {
+	default:
+	case 7:
+	    ms = arglist[6].toDtime();
+	case 6:
+	    seconds = arglist[5].toDtime();
+	case 5:
+	    minutes = arglist[4].toDtime();
+	case 4:
+	    hours = arglist[3].toDtime();
+	    time = std.date.MakeTime(hours, minutes, seconds, ms);
+	case 3:
+	    date = arglist[2].toDtime();
+	case 2:
+	    month = arglist[1].toDtime();
+	case 1:
+	    year = arglist[0].toDtime();
+
+	    if (year != d_time_nan && year >= 0 && year <= 99)
+		year += 1900;
+	    day = std.date.MakeDay(year, month, date);
+	    n = std.date.TimeClip(std.date.MakeDate(day,time));
+	    break;
+
+	case 0:
+	    n = std.date.getUTCtime();
+	    break;
+    }
+    ret.putVtime(n);
+    return null;
+}
+
+/* ===================== Ddate_constructor ==================== */
+
+class Ddate_constructor : Dfunction
+{
+    this(ThreadContext *tc)
+    {
+	super(7, tc.Dfunction_prototype);
+	name = "Date";
+
+	static NativeFunctionData nfd[] =
+	[
+	    { &TEXT_parse, &Ddate_parse, 1 },
+	    { &TEXT_UTC, &Ddate_UTC, 7 },
+	];
+
+	DnativeFunction.init(this, nfd, 0);
+    }
+
+    void *Construct(CallContext *cc, Value *ret, Value[] arglist)
+    {
+	// ECMA 15.9.3
+	Dobject o;
+	d_time n;
+
+	d_time year;
+	d_time month;
+	d_time date = 0;
+	d_time hours = 0;
+	d_time minutes = 0;
+	d_time seconds = 0;
+	d_time ms = 0;
+
+	d_time day;
+	d_time time = 0;
+
+	//writefln("Ddate_constructor.Construct()");
+	switch (arglist.length)
+	{
+	    default:
+	    case 7:
+		ms = arglist[6].toDtime();
+	    case 6:
+		seconds = arglist[5].toDtime();
+	    case 5:
+		minutes = arglist[4].toDtime();
+	    case 4:
+		hours = arglist[3].toDtime();
+		time = std.date.MakeTime(hours, minutes, seconds, ms);
+	    case 3:
+		date = arglist[2].toDtime();
+	    case 2:
+		month = arglist[1].toDtime();
+		year = arglist[0].toDtime();
+
+		if (year != d_time_nan && year >= 0 && year <= 99)
+		    year += 1900;
+		day = std.date.MakeDay(year, month, date);
+		n = std.date.TimeClip(std.date.LocalTimetoUTC(std.date.MakeDate(day, time)));
+		break;
+
+	    case 1:
+		arglist[0].toPrimitive(ret, null);
+		if (ret.getType() == TypeString)
+		{
+		    n = parseDateString(cc, ret.string);
+		}
+		else
+		{
+		    n = ret.toDtime();
+		    n = std.date.TimeClip(n);
+		}
+		break;
+
+	    case 0:
+		n = std.date.getUTCtime();
+		break;
+	}
+	//writefln("\tn = %s", n);
+	o = new Ddate(n);
+	ret.putVobject(o);
+	return null;
+    }
+
+    void *Call(CallContext *cc, Dobject othis, Value* ret, Value[] arglist)
+    {
+	// ECMA 15.9.2
+	// return string as if (new Date()).toString()
+	d_string s;
+	d_time t;
+
+	version (DATETOSTRING)
+	{
+	    t = std.date.getUTCtime();
+	    t = std.date.UTCtoLocalTime(t);
+	    s = dateToString(cc, t, TIMEFORMAT.String);
+	}
+	else
+	{
+	    t = std.date.time();
+	    s = std.date.toString(t);
+	}
+	ret.putVstring(s);
+	return null;
+    }
+}
+
+
+/* ===================== Ddate.prototype functions =============== */
+
+void *checkdate(Value* ret, tchar[] name, Dobject othis)
+{
+    ret.putVundefined();
+    ErrInfo errinfo;
+    return Dobject.RuntimeError(&errinfo, errmsgtbl[ERR_FUNCTION_WANTS_DATE],
+	    name, othis.classname);
+}
+
+int getThisTime(Value* ret, Dobject othis, out d_time n)
+{   d_number x;
+
+    n = cast(d_time)othis.value.number;
+    ret.putVtime(n);
+    return (n == d_time_nan) ? 1 : 0;
+}
+
+int getThisLocalTime(Value* ret, Dobject othis, out d_time n)
+{   int isn = 1;
+
+    n = cast(d_time)othis.value.number;
+    if (n != d_time_nan)
+    {	isn = 0;
+	n = std.date.UTCtoLocalTime(n);
+    }
+    ret.putVtime(n);
+    return isn;
+}
+
+void* Ddate_prototype_toString(Dobject pthis, CallContext *cc, Dobject othis, Value* ret, Value[] arglist)
+{
+    // ECMA 15.9.5.2
+    d_time n;
+    d_string s;
+
+    //writefln("Ddate_prototype_toString()");
+    if (!othis.isDdate())
+	return checkdate(ret, TEXT_toString, othis);
+
+  version (DATETOSTRING)
+  {
+    getThisLocalTime(ret, othis, n);
+    s = dateToString(cc, n, TIMEFORMAT.String);
+  }
+  else
+  {
+    getThisTime(ret, othis, n);
+    s = std.date.ToString(n);
+  }
+    ret.putVstring(s);
+    return null;
+}
+
+void* Ddate_prototype_toDateString(Dobject pthis, CallContext *cc, Dobject othis, Value* ret, Value[] arglist)
+{
+    // ECMA 15.9.5.3
+    d_time n;
+    d_string s;
+
+    if (!othis.isDdate())
+	return checkdate(ret, TEXT_toDateString, othis);
+
+    version (DATETOSTRING)
+    {
+	getThisLocalTime(ret, othis, n);
+	s = dateToString(cc, n, TIMEFORMAT.DateString);
+    }
+    else
+    {
+	getThisTime(ret, othis, n);
+	s = std.date.ToDateString(n);
+    }
+    ret.putVstring(s);
+    return null;
+}
+
+void* Ddate_prototype_toTimeString(Dobject pthis, CallContext *cc, Dobject othis, Value* ret, Value[] arglist)
+{
+    // ECMA 15.9.5.4
+    d_time n;
+    d_string s;
+
+    if (!othis.isDdate())
+	return checkdate(ret, TEXT_toTimeString, othis);
+
+    version (DATETOSTRING)
+    {
+	getThisLocalTime(ret, othis, n);
+	s = dateToString(cc, n, TIMEFORMAT.TimeString);
+    }
+    else
+    {
+	getThisTime(ret, othis, n);
+	s = std.date.ToTimeString(n);
+    }
+    //s = std.date.ToTimeString(n);
+    ret.putVstring(s);
+    return null;
+}
+
+void* Ddate_prototype_valueOf(Dobject pthis, CallContext *cc, Dobject othis, Value* ret, Value[] arglist)
+{
+    // ECMA 15.9.5.3
+    d_time n;
+
+    if (!othis.isDdate())
+	return checkdate(ret, TEXT_valueOf, othis);
+    getThisTime(ret, othis, n);
+    return null;
+}
+
+void* Ddate_prototype_getTime(Dobject pthis, CallContext *cc, Dobject othis, Value* ret, Value[] arglist)
+{
+    // ECMA 15.9.5.4
+    d_time n;
+
+    if (!othis.isDdate())
+	return checkdate(ret, TEXT_getTime, othis);
+    getThisTime(ret, othis, n);
+    return null;
+}
+
+void* Ddate_prototype_getYear(Dobject pthis, CallContext *cc, Dobject othis, Value* ret, Value[] arglist)
+{
+    // ECMA 15.9.5.5
+    d_time n;
+
+    if (!othis.isDdate())
+	return checkdate(ret, TEXT_getYear, othis);
+
+    if (getThisLocalTime(ret, othis, n) == 0)
+    {
+	n = std.date.YearFromTime(n);
+	if (n != d_time_nan)
+	{
+	    n -= 1900;
+	    version (all) // emulate jscript bug
+	    {
+		if (n < 0 || n >= 100)
+		    n += 1900;
+	    }
+	}
+	ret.putVtime(n);
+    }
+    return null;
+}
+
+void* Ddate_prototype_getFullYear(Dobject pthis, CallContext *cc, Dobject othis, Value* ret, Value[] arglist)
+{
+    // ECMA 15.9.5.6
+    d_time n;
+
+    if (!othis.isDdate())
+	return checkdate(ret, TEXT_getFullYear, othis);
+
+    if (getThisLocalTime(ret, othis, n) == 0)
+    {
+	n = std.date.YearFromTime(n);
+	ret.putVtime(n);
+    }
+    return null;
+}
+
+void* Ddate_prototype_getUTCFullYear(Dobject pthis, CallContext *cc, Dobject othis, Value* ret, Value[] arglist)
+{
+    // ECMA 15.9.5.7
+    d_time n;
+
+    if (!othis.isDdate())
+	return checkdate(ret, TEXT_getUTCFullYear, othis);
+    if (getThisTime(ret, othis, n) == 0)
+    {
+	n = std.date.YearFromTime(n);
+	ret.putVtime(n);
+    }
+    return null;
+}
+
+void* Ddate_prototype_getMonth(Dobject pthis, CallContext *cc, Dobject othis, Value* ret, Value[] arglist)
+{
+    // ECMA 15.9.5.8
+    d_time n;
+
+    if (!othis.isDdate())
+	return checkdate(ret, TEXT_getMonth, othis);
+
+    if (getThisLocalTime(ret, othis, n) == 0)
+    {
+	n = std.date.MonthFromTime(n);
+	ret.putVtime(n);
+    }
+    return null;
+}
+
+void* Ddate_prototype_getUTCMonth(Dobject pthis, CallContext *cc, Dobject othis, Value* ret, Value[] arglist)
+{
+    // ECMA 15.9.5.9
+    d_time n;
+
+    if (!othis.isDdate())
+	return checkdate(ret, TEXT_getUTCMonth, othis);
+
+    if (getThisTime(ret, othis, n) == 0)
+    {
+	n = std.date.MonthFromTime(n);
+	ret.putVtime(n);
+    }
+    return null;
+}
+
+void* Ddate_prototype_getDate(Dobject pthis, CallContext *cc, Dobject othis, Value* ret, Value[] arglist)
+{
+    // ECMA 15.9.5.10
+    d_time n;
+
+    if (!othis.isDdate())
+	return checkdate(ret, TEXT_getDate, othis);
+
+    if (getThisLocalTime(ret, othis, n) == 0)
+    {
+	//printf("LocalTime = %.16g\n", n);
+	//printf("DaylightSavingTA(n) = %d\n", std.date.DaylightSavingTA(n));
+	n = std.date.DateFromTime(n);
+	ret.putVtime(n);
+    }
+    return null;
+}
+
+void* Ddate_prototype_getUTCDate(Dobject pthis, CallContext *cc, Dobject othis, Value* ret, Value[] arglist)
+{
+    // ECMA 15.9.5.11
+    d_time n;
+
+    if (!othis.isDdate())
+	return checkdate(ret, TEXT_getUTCDate, othis);
+
+    if (getThisTime(ret, othis, n) == 0)
+    {
+	n = std.date.DateFromTime(n);
+	ret.putVtime(n);
+    }
+    return null;
+}
+
+void* Ddate_prototype_getDay(Dobject pthis, CallContext *cc, Dobject othis, Value* ret, Value[] arglist)
+{
+    // ECMA 15.9.5.12
+    d_time n;
+
+    if (!othis.isDdate())
+	return checkdate(ret, TEXT_getDay, othis);
+
+    if (getThisLocalTime(ret, othis, n) == 0)
+    {
+	n = std.date.WeekDay(n);
+	ret.putVtime(n);
+    }
+    return null;
+}
+
+void* Ddate_prototype_getUTCDay(Dobject pthis, CallContext *cc, Dobject othis, Value* ret, Value[] arglist)
+{
+    // ECMA 15.9.5.13
+    d_time n;
+
+    if (!othis.isDdate())
+	return checkdate(ret, TEXT_getUTCDay, othis);
+
+    if (getThisTime(ret, othis, n) == 0)
+    {
+	n = std.date.WeekDay(n);
+	ret.putVtime(n);
+    }
+    return null;
+}
+
+void* Ddate_prototype_getHours(Dobject pthis, CallContext *cc, Dobject othis, Value* ret, Value[] arglist)
+{
+    // ECMA 15.9.5.14
+    d_time n;
+
+    if (!othis.isDdate())
+	return checkdate(ret, TEXT_getHours, othis);
+
+    if (getThisLocalTime(ret, othis, n) == 0)
+    {
+	n = std.date.HourFromTime(n);
+	ret.putVtime(n);
+    }
+    return null;
+}
+
+void* Ddate_prototype_getUTCHours(Dobject pthis, CallContext *cc, Dobject othis, Value* ret, Value[] arglist)
+{
+    // ECMA 15.9.5.15
+    d_time n;
+
+    if (!othis.isDdate())
+	return checkdate(ret, TEXT_getUTCHours, othis);
+
+    if (getThisTime(ret, othis, n) == 0)
+    {
+	n = std.date.HourFromTime(n);
+	ret.putVtime(n);
+    }
+    return null;
+}
+
+void* Ddate_prototype_getMinutes(Dobject pthis, CallContext *cc, Dobject othis, Value* ret, Value[] arglist)
+{
+    // ECMA 15.9.5.16
+    d_time n;
+
+    if (!othis.isDdate())
+	return checkdate(ret, TEXT_getMinutes, othis);
+
+    if (getThisLocalTime(ret, othis, n) == 0)
+    {
+	n = std.date.MinFromTime(n);
+	ret.putVtime(n);
+    }
+    return null;
+}
+
+void* Ddate_prototype_getUTCMinutes(Dobject pthis, CallContext *cc, Dobject othis, Value* ret, Value[] arglist)
+{
+    // ECMA 15.9.5.17
+    d_time n;
+
+    if (!othis.isDdate())
+	return checkdate(ret, TEXT_getUTCMinutes, othis);
+
+    if (getThisTime(ret, othis, n) == 0)
+    {
+	n = std.date.MinFromTime(n);
+	ret.putVtime(n);
+    }
+    return null;
+}
+
+void* Ddate_prototype_getSeconds(Dobject pthis, CallContext *cc, Dobject othis, Value* ret, Value[] arglist)
+{
+    // ECMA 15.9.5.18
+    d_time n;
+
+    if (!othis.isDdate())
+	return checkdate(ret, TEXT_getSeconds, othis);
+
+    if (getThisLocalTime(ret, othis, n) == 0)
+    {
+	n = std.date.SecFromTime(n);
+	ret.putVtime(n);
+    }
+    return null;
+}
+
+void* Ddate_prototype_getUTCSeconds(Dobject pthis, CallContext *cc, Dobject othis, Value* ret, Value[] arglist)
+{
+    // ECMA 15.9.5.19
+    d_time n;
+
+    if (!othis.isDdate())
+	return checkdate(ret, TEXT_getUTCSeconds, othis);
+
+    if (getThisTime(ret, othis, n) == 0)
+    {
+	n = std.date.SecFromTime(n);
+	ret.putVtime(n);
+    }
+    return null;
+}
+
+void* Ddate_prototype_getMilliseconds(Dobject pthis, CallContext *cc, Dobject othis, Value* ret, Value[] arglist)
+{
+    // ECMA 15.9.5.20
+    d_time n;
+
+    if (!othis.isDdate())
+	return checkdate(ret, TEXT_getMilliseconds, othis);
+
+    if (getThisLocalTime(ret, othis, n) == 0)
+    {
+	n = std.date.msFromTime(n);
+	ret.putVtime(n);
+    }
+    return null;
+}
+
+void* Ddate_prototype_getUTCMilliseconds(Dobject pthis, CallContext *cc, Dobject othis, Value* ret, Value[] arglist)
+{
+    // ECMA 15.9.5.21
+    d_time n;
+
+    if (!othis.isDdate())
+	return checkdate(ret, TEXT_getUTCMilliseconds, othis);
+
+    if (getThisTime(ret, othis, n) == 0)
+    {
+	n = std.date.msFromTime(n);
+	ret.putVtime(n);
+    }
+    return null;
+}
+
+void* Ddate_prototype_getTimezoneOffset(Dobject pthis, CallContext *cc, Dobject othis, Value* ret, Value[] arglist)
+{
+    // ECMA 15.9.5.22
+    d_time n;
+
+    if (!othis.isDdate())
+	return checkdate(ret, TEXT_getTimezoneOffset, othis);
+
+    if (getThisTime(ret, othis, n) == 0)
+    {
+	n = (n - std.date.UTCtoLocalTime(n)) / (60 * 1000);
+	ret.putVtime(n);
+    }
+    return null;
+}
+
+void* Ddate_prototype_setTime(Dobject pthis, CallContext *cc, Dobject othis, Value* ret, Value[] arglist)
+{
+    // ECMA 15.9.5.23
+    d_time n;
+
+    if (!othis.isDdate())
+	return checkdate(ret, TEXT_setTime, othis);
+
+    if (!arglist.length)
+	n = d_time_nan;
+    else
+	n = arglist[0].toDtime();
+    n = std.date.TimeClip(n);
+    othis.value.putVtime(n);
+    ret.putVtime(n);
+    return null;
+}
+
+void* Ddate_prototype_setMilliseconds(Dobject pthis, CallContext *cc, Dobject othis, Value* ret, Value[] arglist)
+{
+    // ECMA 15.9.5.24
+
+    d_time ms;
+    d_time t;
+    d_time time;
+    d_time n;
+
+    if (!othis.isDdate())
+	return checkdate(ret, TEXT_setMilliseconds, othis);
+
+    if (getThisLocalTime(ret, othis, t) == 0)
+    {
+	if (!arglist.length)
+	    ms = d_time_nan;
+	else
+	    ms = arglist[0].toDtime();
+	time = std.date.MakeTime(std.date.HourFromTime(t), std.date.MinFromTime(t), std.date.SecFromTime(t), ms);
+	n = std.date.TimeClip(std.date.LocalTimetoUTC(std.date.MakeDate(std.date.Day(t),time)));
+	othis.value.putVtime(n);
+	ret.putVtime(n);
+    }
+    return null;
+}
+
+void* Ddate_prototype_setUTCMilliseconds(Dobject pthis, CallContext *cc, Dobject othis, Value* ret, Value[] arglist)
+{
+    // ECMA 15.9.5.25
+    d_time ms;
+    d_time t;
+    d_time time;
+    d_time n;
+
+    if (!othis.isDdate())
+	return checkdate(ret, TEXT_setUTCMilliseconds, othis);
+
+    if (getThisTime(ret, othis, t) == 0)
+    {
+	if (!arglist.length)
+	    ms = d_time_nan;
+	else
+	    ms = arglist[0].toDtime();
+	time = std.date.MakeTime(std.date.HourFromTime(t), std.date.MinFromTime(t), std.date.SecFromTime(t), ms);
+	n = std.date.TimeClip(std.date.MakeDate(std.date.Day(t),time));
+	othis.value.putVtime(n);
+	ret.putVtime(n);
+    }
+    return null;
+}
+
+void* Ddate_prototype_setSeconds(Dobject pthis, CallContext *cc, Dobject othis, Value* ret, Value[] arglist)
+{
+    // ECMA 15.9.5.26
+    d_time ms;
+    d_time seconds;
+    d_time t;
+    d_time time;
+    d_time n;
+
+    if (!othis.isDdate())
+	return checkdate(ret, TEXT_setSeconds, othis);
+
+    if (getThisLocalTime(ret, othis, t) == 0)
+    {
+	switch (arglist.length)
+	{
+	    default:
+	    case 2:
+		ms = arglist[1].toDtime();
+		seconds = arglist[0].toDtime();
+		break;
+
+	    case 1:
+		ms = std.date.msFromTime(t);
+		seconds = arglist[0].toDtime();
+		break;
+
+	    case 0:
+		ms = std.date.msFromTime(t);
+		seconds = d_time_nan;
+		break;
+	}
+	time = std.date.MakeTime(std.date.HourFromTime(t), std.date.MinFromTime(t), seconds, ms);
+	n = std.date.TimeClip(std.date.LocalTimetoUTC(std.date.MakeDate(std.date.Day(t),time)));
+	othis.value.putVtime(n);
+	ret.putVtime(n);
+    }
+    return null;
+}
+
+void* Ddate_prototype_setUTCSeconds(Dobject pthis, CallContext *cc, Dobject othis, Value* ret, Value[] arglist)
+{
+    // ECMA 15.9.5.27
+    d_time ms;
+    d_time seconds;
+    d_time t;
+    d_time time;
+    d_time n;
+
+    if (!othis.isDdate())
+	return checkdate(ret, TEXT_setUTCSeconds, othis);
+
+    if (getThisTime(ret, othis, t) == 0)
+    {
+	switch (arglist.length)
+	{
+	    default:
+	    case 2:
+		ms = arglist[1].toDtime();
+		seconds = arglist[0].toDtime();
+		break;
+
+	    case 1:
+		ms = std.date.msFromTime(t);
+		seconds = arglist[0].toDtime();
+		break;
+
+	    case 0:
+		ms = std.date.msFromTime(t);
+		seconds = d_time_nan;
+		break;
+	}
+	time = std.date.MakeTime(std.date.HourFromTime(t), std.date.MinFromTime(t), seconds, ms);
+	n = std.date.TimeClip(std.date.MakeDate(std.date.Day(t),time));
+	othis.value.putVtime(n);
+	ret.putVtime(n);
+    }
+    return null;
+}
+
+void* Ddate_prototype_setMinutes(Dobject pthis, CallContext *cc, Dobject othis, Value* ret, Value[] arglist)
+{
+    // ECMA 15.9.5.28
+    d_time ms;
+    d_time seconds;
+    d_time minutes;
+    d_time t;
+    d_time time;
+    d_time n;
+
+    if (!othis.isDdate())
+	return checkdate(ret, TEXT_setMinutes, othis);
+
+    if (getThisLocalTime(ret, othis, t) == 0)
+    {
+	switch (arglist.length)
+	{
+	    default:
+	    case 3:
+		ms      = arglist[2].toDtime();
+		seconds = arglist[1].toDtime();
+		minutes = arglist[0].toDtime();
+		break;
+
+	    case 2:
+		ms      = std.date.msFromTime(t);
+		seconds = arglist[1].toDtime();
+		minutes = arglist[0].toDtime();
+		break;
+
+	    case 1:
+		ms      = std.date.msFromTime(t);
+		seconds = std.date.SecFromTime(t);
+		minutes = arglist[0].toDtime();
+		break;
+
+	    case 0:
+		ms      = std.date.msFromTime(t);
+		seconds = std.date.SecFromTime(t);
+		minutes = d_time_nan;
+		break;
+	}
+	time = std.date.MakeTime(std.date.HourFromTime(t), minutes, seconds, ms);
+	n = std.date.TimeClip(std.date.LocalTimetoUTC(std.date.MakeDate(std.date.Day(t),time)));
+	othis.value.putVtime(n);
+	ret.putVtime(n);
+    }
+    return null;
+}
+
+void* Ddate_prototype_setUTCMinutes(Dobject pthis, CallContext *cc, Dobject othis, Value* ret, Value[] arglist)
+{
+    // ECMA 15.9.5.29
+    d_time ms;
+    d_time seconds;
+    d_time minutes;
+    d_time t;
+    d_time time;
+    d_time n;
+
+    if (!othis.isDdate())
+	return checkdate(ret, TEXT_setUTCMinutes, othis);
+
+    if (getThisTime(ret, othis, t) == 0)
+    {
+	switch (arglist.length)
+	{
+	    default:
+	    case 3:
+		ms      = arglist[2].toDtime();
+		seconds = arglist[1].toDtime();
+		minutes = arglist[0].toDtime();
+		break;
+
+	    case 2:
+		ms      = std.date.msFromTime(t);
+		seconds = arglist[1].toDtime();
+		minutes = arglist[0].toDtime();
+		break;
+
+	    case 1:
+		ms      = std.date.msFromTime(t);
+		seconds = std.date.SecFromTime(t);
+		minutes = arglist[0].toDtime();
+		break;
+
+	    case 0:
+		ms      = std.date.msFromTime(t);
+		seconds = std.date.SecFromTime(t);
+		minutes = d_time_nan;
+		break;
+	}
+	time = std.date.MakeTime(std.date.HourFromTime(t), minutes, seconds, ms);
+	n = std.date.TimeClip(std.date.MakeDate(std.date.Day(t),time));
+	othis.value.putVtime(n);
+	ret.putVtime(n);
+    }
+    return null;
+}
+
+void* Ddate_prototype_setHours(Dobject pthis, CallContext *cc, Dobject othis, Value* ret, Value[] arglist)
+{
+    // ECMA 15.9.5.30
+    d_time ms;
+    d_time seconds;
+    d_time minutes;
+    d_time hours;
+    d_time t;
+    d_time time;
+    d_time n;
+
+    if (!othis.isDdate())
+	return checkdate(ret, TEXT_setHours, othis);
+
+    if (getThisLocalTime(ret, othis, t) == 0)
+    {
+	switch (arglist.length)
+	{
+	    default:
+	    case 4:
+		ms      = arglist[3].toDtime();
+		seconds = arglist[2].toDtime();
+		minutes = arglist[1].toDtime();
+		hours   = arglist[0].toDtime();
+		break;
+
+	    case 3:
+		ms      = std.date.msFromTime(t);
+		seconds = arglist[2].toDtime();
+		minutes = arglist[1].toDtime();
+		hours   = arglist[0].toDtime();
+		break;
+
+	    case 2:
+		ms      = std.date.msFromTime(t);
+		seconds = std.date.SecFromTime(t);
+		minutes = arglist[1].toDtime();
+		hours   = arglist[0].toDtime();
+		break;
+
+	    case 1:
+		ms      = std.date.msFromTime(t);
+		seconds = std.date.SecFromTime(t);
+		minutes = std.date.MinFromTime(t);
+		hours   = arglist[0].toDtime();
+		break;
+
+	    case 0:
+		ms      = std.date.msFromTime(t);
+		seconds = std.date.SecFromTime(t);
+		minutes = std.date.MinFromTime(t);
+		hours   = d_time_nan;
+		break;
+	}
+	time = std.date.MakeTime(hours, minutes, seconds, ms);
+	n = std.date.TimeClip(std.date.LocalTimetoUTC(std.date.MakeDate(std.date.Day(t),time)));
+	othis.value.putVtime(n);
+	ret.putVtime(n);
+    }
+    return null;
+}
+
+void* Ddate_prototype_setUTCHours(Dobject pthis, CallContext *cc, Dobject othis, Value* ret, Value[] arglist)
+{
+    // ECMA 15.9.5.31
+    d_time ms;
+    d_time seconds;
+    d_time minutes;
+    d_time hours;
+    d_time t;
+    d_time time;
+    d_time n;
+
+    if (!othis.isDdate())
+	return checkdate(ret, TEXT_setUTCHours, othis);
+
+    if (getThisTime(ret, othis, t) == 0)
+    {
+	switch (arglist.length)
+	{
+	    default:
+	    case 4:
+		ms      = arglist[3].toDtime();
+		seconds = arglist[2].toDtime();
+		minutes = arglist[1].toDtime();
+		hours   = arglist[0].toDtime();
+		break;
+
+	    case 3:
+		ms      = std.date.msFromTime(t);
+		seconds = arglist[2].toDtime();
+		minutes = arglist[1].toDtime();
+		hours   = arglist[0].toDtime();
+		break;
+
+	    case 2:
+		ms      = std.date.msFromTime(t);
+		seconds = std.date.SecFromTime(t);
+		minutes = arglist[1].toDtime();
+		hours   = arglist[0].toDtime();
+		break;
+
+	    case 1:
+		ms      = std.date.msFromTime(t);
+		seconds = std.date.SecFromTime(t);
+		minutes = std.date.MinFromTime(t);
+		hours   = arglist[0].toDtime();
+		break;
+
+	    case 0:
+		ms      = std.date.msFromTime(t);
+		seconds = std.date.SecFromTime(t);
+		minutes = std.date.MinFromTime(t);
+		hours   = d_time_nan;
+		break;
+	}
+	time = std.date.MakeTime(hours, minutes, seconds, ms);
+	n = std.date.TimeClip(std.date.MakeDate(std.date.Day(t),time));
+	othis.value.putVtime(n);
+	ret.putVtime(n);
+    }
+    return null;
+}
+
+void* Ddate_prototype_setDate(Dobject pthis, CallContext *cc, Dobject othis, Value* ret, Value[] arglist)
+{
+    // ECMA 15.9.5.32
+    d_time date;
+    d_time t;
+    d_time day;
+    d_time n;
+
+    if (!othis.isDdate())
+	return checkdate(ret, TEXT_setDate, othis);
+
+    if (getThisLocalTime(ret, othis, t) == 0)
+    {
+	if (!arglist.length)
+	    date = d_time_nan;
+	else
+	    date = arglist[0].toDtime();
+	day = std.date.MakeDay(std.date.YearFromTime(t), std.date.MonthFromTime(t), date);
+	n = std.date.TimeClip(std.date.LocalTimetoUTC(std.date.MakeDate(day, std.date.TimeWithinDay(t))));
+	othis.value.putVtime(n);
+	ret.putVtime(n);
+    }
+    return null;
+}
+
+void* Ddate_prototype_setUTCDate(Dobject pthis, CallContext *cc, Dobject othis, Value* ret, Value[] arglist)
+{
+    // ECMA 15.9.5.33
+    d_time date;
+    d_time t;
+    d_time day;
+    d_time n;
+
+    if (!othis.isDdate())
+	return checkdate(ret, TEXT_setUTCDate, othis);
+
+    if (getThisTime(ret, othis, t) == 0)
+    {
+	if (!arglist.length)
+	    date = d_time_nan;
+	else
+	    date = arglist[0].toDtime();
+	day = std.date.MakeDay(std.date.YearFromTime(t), std.date.MonthFromTime(t), date);
+	n = std.date.TimeClip(std.date.MakeDate(day, std.date.TimeWithinDay(t)));
+	othis.value.putVtime(n);
+	ret.putVtime(n);
+    }
+    return null;
+}
+
+void* Ddate_prototype_setMonth(Dobject pthis, CallContext *cc, Dobject othis, Value* ret, Value[] arglist)
+{
+    // ECMA 15.9.5.34
+    d_time date;
+    d_time month;
+    d_time t;
+    d_time day;
+    d_time n;
+
+    if (!othis.isDdate())
+	return checkdate(ret, TEXT_setMonth, othis);
+
+    if (getThisLocalTime(ret, othis, t) == 0)
+    {
+	switch (arglist.length)
+	{   default:
+	    case 2:
+		month = arglist[0].toDtime();
+		date  = arglist[1].toDtime();
+		break;
+
+	    case 1:
+		month = arglist[0].toDtime();
+		date  = std.date.DateFromTime(t);
+		break;
+
+	    case 0:
+		month = d_time_nan;
+		date  = std.date.DateFromTime(t);
+		break;
+	}
+	day = std.date.MakeDay(std.date.YearFromTime(t), month, date);
+	n = std.date.TimeClip(std.date.LocalTimetoUTC(std.date.MakeDate(day, std.date.TimeWithinDay(t))));
+	othis.value.putVtime(n);
+	ret.putVtime(n);
+    }
+    return null;
+}
+
+void* Ddate_prototype_setUTCMonth(Dobject pthis, CallContext *cc, Dobject othis, Value* ret, Value[] arglist)
+{
+    // ECMA 15.9.5.35
+    d_time date;
+    d_time month;
+    d_time t;
+    d_time day;
+    d_time n;
+
+    if (!othis.isDdate())
+	return checkdate(ret, TEXT_setUTCMonth, othis);
+
+    if (getThisTime(ret, othis, t) == 0)
+    {
+	switch (arglist.length)
+	{   default:
+	    case 2:
+		month = arglist[0].toDtime();
+		date  = arglist[1].toDtime();
+		break;
+
+	    case 1:
+		month = arglist[0].toDtime();
+		date  = std.date.DateFromTime(t);
+		break;
+
+	    case 0:
+		month = d_time_nan;
+		date  = std.date.DateFromTime(t);
+		break;
+	}
+	day = std.date.MakeDay(std.date.YearFromTime(t), month, date);
+	n = std.date.TimeClip(std.date.MakeDate(day, std.date.TimeWithinDay(t)));
+	othis.value.putVtime(n);
+	ret.putVtime(n);
+    }
+    return null;
+}
+
+void* Ddate_prototype_setFullYear(Dobject pthis, CallContext *cc, Dobject othis, Value* ret, Value[] arglist)
+{
+    // ECMA 15.9.5.36
+    d_time date;
+    d_time month;
+    d_time year;
+    d_time t;
+    d_time day;
+    d_time n;
+
+    if (!othis.isDdate())
+	return checkdate(ret, TEXT_setFullYear, othis);
+
+    if (getThisLocalTime(ret, othis, t))
+	t = 0;
+
+    switch (arglist.length)
+    {   default:
+	case 3:
+	    date  = arglist[2].toDtime();
+	    month = arglist[1].toDtime();
+	    year  = arglist[0].toDtime();
+	    break;
+
+	case 2:
+	    date  = std.date.DateFromTime(t);
+	    month = arglist[1].toDtime();
+	    year  = arglist[0].toDtime();
+	    break;
+
+	case 1:
+	    date  = std.date.DateFromTime(t);
+	    month = std.date.MonthFromTime(t);
+	    year  = arglist[0].toDtime();
+	    break;
+
+	case 0:
+	    date  = std.date.DateFromTime(t);
+	    month = std.date.MonthFromTime(t);
+	    year  = d_time_nan;
+	    break;
+    }
+    day = std.date.MakeDay(year, month, date);
+    n = std.date.TimeClip(std.date.LocalTimetoUTC(std.date.MakeDate(day, std.date.TimeWithinDay(t))));
+    othis.value.putVtime(n);
+    ret.putVtime(n);
+    return null;
+}
+
+void* Ddate_prototype_setUTCFullYear(Dobject pthis, CallContext *cc, Dobject othis, Value* ret, Value[] arglist)
+{
+    // ECMA 15.9.5.37
+    d_time date;
+    d_time month;
+    d_time year;
+    d_time t;
+    d_time day;
+    d_time n;
+
+    if (!othis.isDdate())
+	return checkdate(ret, TEXT_setUTCFullYear, othis);
+
+    getThisTime(ret, othis, t);
+    if (t == d_time_nan)
+	t = 0;
+    switch (arglist.length)
+    {   default:
+	case 3:
+	    month = arglist[2].toDtime();
+	    date  = arglist[1].toDtime();
+	    year  = arglist[0].toDtime();
+	    break;
+
+	case 2:
+	    month = std.date.MonthFromTime(t);
+	    date  = arglist[1].toDtime();
+	    year  = arglist[0].toDtime();
+	    break;
+
+	case 1:
+	    month = std.date.MonthFromTime(t);
+	    date  = std.date.DateFromTime(t);
+	    year  = arglist[0].toDtime();
+	    break;
+
+	case 0:
+	    month = std.date.MonthFromTime(t);
+	    date  = std.date.DateFromTime(t);
+	    year  = d_time_nan;
+	    break;
+    }
+    day = std.date.MakeDay(year, month, date);
+    n = std.date.TimeClip(std.date.MakeDate(day, std.date.TimeWithinDay(t)));
+    othis.value.putVtime(n);
+    ret.putVtime(n);
+    return null;
+}
+
+void* Ddate_prototype_setYear(Dobject pthis, CallContext *cc, Dobject othis, Value* ret, Value[] arglist)
+{
+    // ECMA 15.9.5.38
+    d_time date;
+    d_time month;
+    d_time year;
+    d_time t;
+    d_time day;
+    d_time n;
+
+    if (!othis.isDdate())
+	return checkdate(ret, TEXT_setYear, othis);
+
+    if (getThisLocalTime(ret, othis, t))
+	t = 0;
+    switch (arglist.length)
+    {   default:
+	case 1:
+	    month = std.date.MonthFromTime(t);
+	    date  = std.date.DateFromTime(t);
+	    year  = arglist[0].toDtime();
+	    if (0 <= year && year <= 99)
+		year += 1900;
+	    day = std.date.MakeDay(year, month, date);
+	    n = std.date.TimeClip(std.date.LocalTimetoUTC(std.date.MakeDate(day, std.date.TimeWithinDay(t))));
+	    break;
+
+	case 0:
+	    n = d_time_nan;
+	    break;
+    }
+    othis.value.putVtime(n);
+    ret.putVtime(n);
+    return null;
+}
+
+void* Ddate_prototype_toLocaleString(Dobject pthis, CallContext *cc, Dobject othis, Value* ret, Value[] arglist)
+{
+    // ECMA 15.9.5.39
+    d_string s;
+    d_time t;
+
+    if (!othis.isDdate())
+	return checkdate(ret, TEXT_toLocaleString, othis);
+
+    if (getThisLocalTime(ret, othis, t))
+	t = 0;
+
+    s = dateToString(cc, t, TIMEFORMAT.LocaleString);
+    ret.putVstring(s);
+    return null;
+}
+
+void* Ddate_prototype_toLocaleDateString(Dobject pthis, CallContext *cc, Dobject othis, Value* ret, Value[] arglist)
+{
+    // ECMA 15.9.5.6
+    d_string s;
+    d_time t;
+
+    if (!othis.isDdate())
+	return checkdate(ret, TEXT_toLocaleDateString, othis);
+
+    if (getThisLocalTime(ret, othis, t))
+	t = 0;
+
+    s = dateToString(cc, t, TIMEFORMAT.LocaleDateString);
+    ret.putVstring(s);
+    return null;
+}
+
+void* Ddate_prototype_toLocaleTimeString(Dobject pthis, CallContext *cc, Dobject othis, Value* ret, Value[] arglist)
+{
+    // ECMA 15.9.5.7
+    d_string s;
+    d_time t;
+
+    if (!othis.isDdate())
+	return checkdate(ret, TEXT_toLocaleTimeString, othis);
+
+    if (getThisLocalTime(ret, othis, t))
+	t = 0;
+    s = dateToString(cc, t, TIMEFORMAT.LocaleTimeString);
+    ret.putVstring(s);
+    return null;
+}
+
+void* Ddate_prototype_toUTCString(Dobject pthis, CallContext *cc, Dobject othis, Value* ret, Value[] arglist)
+{
+    // ECMA 15.9.5.40
+    d_string s;
+    d_time t;
+
+    if (!othis.isDdate())
+	return checkdate(ret, TEXT_toUTCString, othis);
+
+    if (getThisTime(ret, othis, t))
+	t = 0;
+    s = dateToString(cc, t, TIMEFORMAT.UTCString);
+    ret.putVstring(s);
+    return null;
+}
+
+/* ===================== Ddate_prototype ==================== */
+
+class Ddate_prototype : Ddate
+{
+    this(ThreadContext *tc)
+    {
+	super(tc.Dobject_prototype);
+
+	Dobject f = tc.Dfunction_prototype;
+
+	Put(TEXT_constructor, tc.Ddate_constructor, DontEnum);
+
+	static NativeFunctionData nfd[] =
+	[
+	    {	&TEXT_toString, &Ddate_prototype_toString, 0 },
+	    {	&TEXT_toDateString, &Ddate_prototype_toDateString, 0 },
+	    {	&TEXT_toTimeString, &Ddate_prototype_toTimeString, 0 },
+	    {	&TEXT_valueOf, &Ddate_prototype_valueOf, 0 },
+	    {	&TEXT_getTime, &Ddate_prototype_getTime, 0 },
+	    //{	&TEXT_getVarDate, &Ddate_prototype_getVarDate, 0 },
+	    {	&TEXT_getYear, &Ddate_prototype_getYear, 0 },
+	    {	&TEXT_getFullYear, &Ddate_prototype_getFullYear, 0 },
+	    {	&TEXT_getUTCFullYear, &Ddate_prototype_getUTCFullYear, 0 },
+	    {	&TEXT_getMonth, &Ddate_prototype_getMonth, 0 },
+	    {	&TEXT_getUTCMonth, &Ddate_prototype_getUTCMonth, 0 },
+	    {	&TEXT_getDate, &Ddate_prototype_getDate, 0 },
+	    {	&TEXT_getUTCDate, &Ddate_prototype_getUTCDate, 0 },
+	    {	&TEXT_getDay, &Ddate_prototype_getDay, 0 },
+	    {	&TEXT_getUTCDay, &Ddate_prototype_getUTCDay, 0 },
+	    {	&TEXT_getHours, &Ddate_prototype_getHours, 0 },
+	    {	&TEXT_getUTCHours, &Ddate_prototype_getUTCHours, 0 },
+	    {	&TEXT_getMinutes, &Ddate_prototype_getMinutes, 0 },
+	    {	&TEXT_getUTCMinutes, &Ddate_prototype_getUTCMinutes, 0 },
+	    {	&TEXT_getSeconds, &Ddate_prototype_getSeconds, 0 },
+	    {	&TEXT_getUTCSeconds, &Ddate_prototype_getUTCSeconds, 0 },
+	    {	&TEXT_getMilliseconds, &Ddate_prototype_getMilliseconds, 0 },
+	    {	&TEXT_getUTCMilliseconds, &Ddate_prototype_getUTCMilliseconds, 0 },
+	    {	&TEXT_getTimezoneOffset, &Ddate_prototype_getTimezoneOffset, 0 },
+	    {	&TEXT_setTime, &Ddate_prototype_setTime, 1 },
+	    {	&TEXT_setMilliseconds, &Ddate_prototype_setMilliseconds, 1 },
+	    {	&TEXT_setUTCMilliseconds, &Ddate_prototype_setUTCMilliseconds, 1 },
+	    {	&TEXT_setSeconds, &Ddate_prototype_setSeconds, 2 },
+	    {	&TEXT_setUTCSeconds, &Ddate_prototype_setUTCSeconds, 2 },
+	    {	&TEXT_setMinutes, &Ddate_prototype_setMinutes, 3 },
+	    {	&TEXT_setUTCMinutes, &Ddate_prototype_setUTCMinutes, 3 },
+	    {	&TEXT_setHours, &Ddate_prototype_setHours, 4 },
+	    {	&TEXT_setUTCHours, &Ddate_prototype_setUTCHours, 4 },
+	    {	&TEXT_setDate, &Ddate_prototype_setDate, 1 },
+	    {	&TEXT_setUTCDate, &Ddate_prototype_setUTCDate, 1 },
+	    {	&TEXT_setMonth, &Ddate_prototype_setMonth, 2 },
+	    {	&TEXT_setUTCMonth, &Ddate_prototype_setUTCMonth, 2 },
+	    {	&TEXT_setFullYear, &Ddate_prototype_setFullYear, 3 },
+	    {	&TEXT_setUTCFullYear, &Ddate_prototype_setUTCFullYear, 3 },
+	    {	&TEXT_setYear, &Ddate_prototype_setYear, 1 },
+	    {	&TEXT_toLocaleString, &Ddate_prototype_toLocaleString, 0 },
+	    {	&TEXT_toLocaleDateString, &Ddate_prototype_toLocaleDateString, 0 },
+	    {	&TEXT_toLocaleTimeString, &Ddate_prototype_toLocaleTimeString, 0 },
+	    {	&TEXT_toUTCString, &Ddate_prototype_toUTCString, 0 },
+
+	    // Map toGMTString() onto toUTCString(), per ECMA 15.9.5.41
+	    {   &TEXT_toGMTString, &Ddate_prototype_toUTCString, 0 },
+	];
+
+	DnativeFunction.init(this, nfd, 0);
+	assert(proptable.get("toString", Value.calcHash("toString")));
+    }
+}
+
+
+/* ===================== Ddate ==================== */
+
+class Ddate : Dobject
+{
+    this(d_number n)
+    {
+	super(Ddate.getPrototype());
+	classname = TEXT_Date;
+	value.putVnumber(n);
+    }
+
+    this(d_time n)
+    {
+	super(Ddate.getPrototype());
+	classname = TEXT_Date;
+	value.putVtime(n);
+    }
+
+    this(Dobject prototype)
+    {
+	super(prototype);
+	classname = TEXT_Date;
+	value.putVnumber(d_number.nan);
+    }
+
+    static void init(ThreadContext *tc)
+    {
+	tc.Ddate_constructor = new Ddate_constructor(tc);
+	tc.Ddate_prototype = new Ddate_prototype(tc);
+
+	tc.Ddate_constructor.Put(TEXT_prototype, tc.Ddate_prototype,
+		DontEnum | DontDelete | ReadOnly);
+
+	assert(tc.Ddate_prototype.proptable.table.length != 0);
+    }
+
+    static Dfunction getConstructor()
+    {
+	ThreadContext *tc = ThreadContext.getThreadContext();
+	assert(tc);
+	return tc.Ddate_constructor;
+    }
+
+    static Dobject getPrototype()
+    {
+	ThreadContext *tc = ThreadContext.getThreadContext();
+	assert(tc);
+	return tc.Ddate_prototype;
+    }
+}
+
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/dmdscript_tango/ddeclaredfunction.d	Sun Jan 24 12:34:47 2010 +0200
@@ -0,0 +1,249 @@
+
+/* Digital Mars DMDScript source code.
+ * Copyright (c) 2000-2002 by Chromium Communications
+ * D version Copyright (c) 2004-2006 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.ddeclaredfunction;
+
+import std.stdio;
+import std.c.stdlib;
+
+import dmdscript.script;
+import dmdscript.dobject;
+import dmdscript.dfunction;
+import dmdscript.darguments;
+import dmdscript.opcodes;
+import dmdscript.ir;
+import dmdscript.identifier;
+import dmdscript.value;
+import dmdscript.functiondefinition;
+import dmdscript.text;
+import dmdscript.property;
+
+/* ========================== DdeclaredFunction ================== */
+
+class DdeclaredFunction : Dfunction
+{
+    FunctionDefinition fd;
+
+    this(FunctionDefinition fd)
+    {
+	super(fd.parameters.length, Dfunction.getPrototype());
+	assert(Dfunction.getPrototype());
+	assert(internal_prototype);
+	this.fd = fd;
+
+	Dobject o;
+
+	// ECMA 3 13.2
+	o = new Dobject(Dobject.getPrototype());	// step 9
+	Put(TEXT_prototype, o, DontEnum);		// step 11
+	o.Put(TEXT_constructor, this, DontEnum);	// step 10
+    }
+
+    void *Call(CallContext *cc, Dobject othis, Value* ret, Value[] arglist)
+    {
+	// 1. Create activation object per ECMA 10.1.6
+	// 2. Instantiate function variables as properties of
+	//    activation object
+	// 3. The 'this' value is the activation object
+
+	Dobject actobj;		// activation object
+	Darguments args;
+	Value[] locals;
+	uint i;
+	void *result;
+
+	//writefln("DdeclaredFunction.Call() '%s'", toString());
+	//writefln("this.scopex.length = %d", this.scopex.length);
+	//writefln("\tinstantiate(this = %x, fd = %x)", cast(uint)cast(void*)this, cast(uint)cast(void*)fd);
+
+	// if it's an empty function, just return
+	if (fd.code[0].opcode == IRret)
+	{
+	    return null;
+	}
+
+	// Generate the activation object
+	// ECMA v3 10.1.6
+	actobj = new Dobject(null);
+
+	// Instantiate the parameters
+	{
+	    uint a = 0;
+	    foreach (Identifier* p; fd.parameters)
+	    {
+		Value* v = (a < arglist.length) ? &arglist[a++] : &vundefined;
+		actobj.Put(p.toString(), v, DontDelete);
+	    }
+	}
+
+	// Generate the Arguments Object
+	// ECMA v3 10.1.8
+	args = new Darguments(cc.caller, this, actobj, fd.parameters, arglist);
+
+	actobj.Put(TEXT_arguments, args, DontDelete);
+
+	// The following is not specified by ECMA, but seems to be supported
+	// by jscript. The url www.grannymail.com has the following code
+	// which looks broken to me but works in jscript:
+	//
+	//	    function MakeArray() {
+	//	      this.length = MakeArray.arguments.length
+	//	      for (var i = 0; i < this.length; i++)
+	//		  this[i+1] = arguments[i]
+	//	    }
+	//	    var cardpic = new MakeArray("LL","AP","BA","MB","FH","AW","CW","CV","DZ");
+	Put(TEXT_arguments, args, DontDelete);		// make grannymail bug work
+
+	auto scoperootsave = cc.scoperoot;
+
+	/* If calling a nested function, need to increase scoperoot
+	 */
+	if (fd.enclosingFunction == cc.callerf)
+	{   assert(cc.scoperoot < cc.scopex.length);
+	    cc.scoperoot++;
+	}
+	else
+	{
+	    auto df = cast(DdeclaredFunction)cc.caller;
+	    if (df && !fd.isanonymous)
+	    {
+		version (none)
+		{
+		    writefln("current nestDepth = %d, calling %d, cc.scopex.length = %d",
+			    df.fd.nestDepth,
+			    fd.nestDepth,
+			    cc.scopex.length);
+		}
+		int diff = df.fd.nestDepth - fd.nestDepth;
+		if (diff > 0)
+		{   if (diff >= cc.scoperoot)
+			writefln("diff %s cc.scoperoot %s", diff, cc.scoperoot);
+		    else
+			cc.scoperoot -= diff;
+		    assert(cc.scoperoot >= 1);
+		}
+	    }
+	}
+
+	Dobject[] scopesave = cc.scopex;
+
+	Dobject[] scopex;
+	//scopex = cc.scopex[0 .. cc.scoperoot].dup;
+	scopex = this.scopex.dup;
+	if (scopex.length == 0)
+	{   this.scopex = cc.scopex[0 .. cc.scoperoot];
+	    scopex = this.scopex.dup;
+	}
+	scopex ~= actobj;
+
+	fd.instantiate(scopex, actobj, DontDelete);
+
+	cc.scopex = scopex;
+	Dobject variablesave = cc.variable;
+	cc.variable = actobj;
+	auto callersave = cc.caller;
+	cc.caller = this;
+	auto callerfsave = cc.callerf;
+	cc.callerf = fd;
+
+	Value[] p1;
+	Value* v;
+	if (fd.nlocals < 128)
+	    v = cast(Value*) alloca(fd.nlocals * Value.sizeof);
+	if (v)
+	    locals = v[0 .. fd.nlocals];
+	else
+	{
+	    p1 = new Value[fd.nlocals];
+	    locals = p1;
+	}
+
+	result = IR.call(cc, othis, fd.code, ret, locals.ptr);
+
+	delete p1;
+
+	cc.callerf = callerfsave;
+	cc.caller = callersave;
+	cc.variable = variablesave;
+	cc.scopex = scopesave;
+	cc.scoperoot = scoperootsave;
+
+	// Remove the arguments object
+	//Value* v;
+	//v=Get(TEXT_arguments);
+	//writef("1v = %x, %s, v.object = %x\n", v, v.getType(), v.object);
+	Put(TEXT_arguments, &vundefined, 0);
+	//actobj.Put(TEXT_arguments, &vundefined, 0);
+
+    version (none)
+    {
+	writef("args = %x, actobj = %x\n", args, actobj);
+	v=Get(TEXT_arguments);
+	writef("2v = %x, %s, v.object = %x\n", v, v.getType(), v.object);
+	v.object = null;
+
+	{
+	    uint *p = cast(uint *)0x40a49a80;
+	    uint i;
+	    for (i = 0; i < 16; i++)
+	    {
+		writef("p[%x] = %x\n", &p[i], p[i]);
+	    }
+	}
+    }
+
+	return result;
+    }
+
+    void *Construct(CallContext *cc, Value *ret, Value[] arglist)
+    {
+	// ECMA 3 13.2.2
+	Dobject othis;
+	Dobject proto;
+	Value* v;
+	void *result;
+
+	v = Get(TEXT_prototype);
+	if (v.isPrimitive())
+	    proto = Dobject.getPrototype();
+	else
+	    proto = v.toObject();
+	othis = new Dobject(proto);
+	result = Call(cc, othis, ret, arglist);
+	if (!result)
+	{
+	    if (ret.isPrimitive())
+		ret.putVobject(othis);
+	}
+	return result;
+    }
+
+    d_string toString()
+    {
+	d_string s;
+
+	//writef("DdeclaredFunction.toString()\n");
+	fd.toBuffer(s);
+	return s;
+    }
+}
+
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/dmdscript_tango/derror.d	Sun Jan 24 12:34:47 2010 +0200
@@ -0,0 +1,193 @@
+
+/* Digital Mars DMDScript source code.
+ * Copyright (c) 2000-2002 by Chromium Communications
+ * D version Copyright (c) 2004-2006 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.derror;
+
+import dmdscript.script;
+import dmdscript.dobject;
+import dmdscript.dfunction;
+import dmdscript.value;
+import dmdscript.threadcontext;
+import dmdscript.dnative;
+import dmdscript.text;
+import dmdscript.property;
+
+
+// Comes from MAKE_HRESULT(SEVERITY_ERROR, FACILITY_CONTROL, 0)
+const uint FACILITY = 0x800A0000;
+
+/* ===================== Derror_constructor ==================== */
+
+class Derror_constructor : Dfunction
+{
+    this(ThreadContext *tc)
+    {
+	super(1, tc.Dfunction_prototype);
+    }
+
+    void* Construct(CallContext *cc, Value *ret, Value[] arglist)
+    {
+	// ECMA 15.7.2
+	Dobject o;
+	Value* m;
+	Value* n;
+	Value vemptystring;
+
+	vemptystring.putVstring(null);
+	switch (arglist.length)
+	{
+	    case 0:	// ECMA doesn't say what we do if m is undefined
+		    m = &vemptystring;
+		    n = &vundefined;
+		    break;
+	    case 1:
+		    m = &arglist[0];
+		    if (m.isNumber())
+		    {
+			n = m;
+			m = &vemptystring;
+		    }
+		    else
+			n = &vundefined;
+		    break;
+	    default:
+		    m = &arglist[0];
+		    n = &arglist[1];
+		    break;
+	}
+	o = new Derror(m, n);
+	ret.putVobject(o);
+	return null;
+    }
+
+    void* Call(CallContext *cc, Dobject othis, Value* ret, Value[] arglist)
+    {
+	// ECMA v3 15.11.1
+	return Construct(cc, ret, arglist);
+    }
+}
+
+
+/* ===================== Derror_prototype_toString =============== */
+
+void* Derror_prototype_toString(Dobject pthis, CallContext *cc, Dobject othis, Value *ret, Value[] arglist)
+{
+    // ECMA v3 15.11.4.3
+    // Return implementation defined string
+    Value* v;
+
+    //writef("Error.prototype.toString()\n");
+    v = othis.Get(TEXT_message);
+    if (!v)
+	v = &vundefined;
+    ret.putVstring(v.toString());
+    return null;
+}
+
+/* ===================== Derror_prototype ==================== */
+
+class Derror_prototype : Derror
+{
+    this(ThreadContext *tc)
+    {
+	super(tc.Dobject_prototype);
+	Dobject f = tc.Dfunction_prototype;
+	//d_string m = d_string_ctor(DTEXT("Error.prototype.message"));
+
+	Put(TEXT_constructor, tc.Derror_constructor, DontEnum);
+
+	static NativeFunctionData nfd[] =
+	[
+	    {	&TEXT_toString, &Derror_prototype_toString, 0 },
+	];
+
+	DnativeFunction.init(this, nfd, 0);
+
+	Put(TEXT_name, TEXT_Error, 0);
+	Put(TEXT_message, TEXT_, 0);
+	Put(TEXT_description, TEXT_, 0);
+	Put(TEXT_number, cast(d_number)(/*FACILITY |*/ 0), 0);
+    }
+}
+
+
+/* ===================== Derror ==================== */
+
+class Derror : Dobject
+{
+    this(Value* m, Value* v2)
+    {
+	super(getPrototype());
+	classname = TEXT_Error;
+
+	d_string msg;
+	msg = m.toString();
+	Put(TEXT_message, msg, 0);
+	Put(TEXT_description, msg, 0);
+	if (m.isString())
+	{
+	}
+	else if (m.isNumber())
+	{   d_number n = m.toNumber();
+	    n = cast(d_number)(/*FACILITY |*/ cast(int)n);
+	    Put(TEXT_number, n, 0);
+	}
+	if (v2.isString())
+	{
+	    Put(TEXT_description, v2.toString(), 0);
+	    Put(TEXT_message, v2.toString(), 0);
+	}
+	else if (v2.isNumber())
+	{   d_number n = v2.toNumber();
+	    n = cast(d_number)(/*FACILITY |*/ cast(int)n);
+	    Put(TEXT_number, n, 0);
+	}
+    }
+
+    this(Dobject prototype)
+    {
+	super(prototype);
+	classname = TEXT_Error;
+    }
+
+    static Dfunction getConstructor()
+    {
+	ThreadContext *tc = ThreadContext.getThreadContext();
+	assert(tc);
+	return tc.Derror_constructor;
+    }
+
+    static Dobject getPrototype()
+    {
+	ThreadContext *tc = ThreadContext.getThreadContext();
+	assert(tc);
+	return tc.Derror_prototype;
+    }
+
+    static void init(ThreadContext *tc)
+    {
+	tc.Derror_constructor = new Derror_constructor(tc);
+	tc.Derror_prototype = new Derror_prototype(tc);
+
+	tc.Derror_constructor.Put(TEXT_prototype, tc.Derror_prototype, DontEnum | DontDelete | ReadOnly);
+    }
+}
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/dmdscript_tango/dfunction.d	Sun Jan 24 12:34:47 2010 +0200
@@ -0,0 +1,399 @@
+
+/* 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.dfunction;
+
+import std.string;
+import std.c.stdlib;
+
+import dmdscript.script;
+import dmdscript.dobject;
+import dmdscript.value;
+import dmdscript.protoerror;
+import dmdscript.threadcontext;
+import dmdscript.text;
+import dmdscript.errmsgs;
+import dmdscript.property;
+import dmdscript.scopex;
+import dmdscript.dnative;
+import dmdscript.functiondefinition;
+import dmdscript.parse;
+import dmdscript.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 = 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;
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/dmdscript_tango/dglobal.d	Sun Jan 24 12:34:47 2010 +0200
@@ -0,0 +1,799 @@
+
+/* Digital Mars DMDScript source code.
+ * Copyright (c) 2000-2002 by Chromium Communications
+ * D version Copyright (c) 2004-2006 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.dglobal;
+
+import std.uri;
+import std.c.stdlib;
+import std.c.string;
+import std.stdio;
+import std.math;
+
+import dmdscript.script;
+import dmdscript.protoerror;
+import dmdscript.parse;
+import dmdscript.text;
+import dmdscript.dobject;
+import dmdscript.value;
+import dmdscript.statement;
+import dmdscript.threadcontext;
+import dmdscript.functiondefinition;
+import dmdscript.scopex;
+import dmdscript.opcodes;
+import dmdscript.property;
+
+import dmdscript.dstring;
+import dmdscript.darray;
+import dmdscript.dregexp;
+import dmdscript.dnumber;
+import dmdscript.dboolean;
+import dmdscript.dfunction;
+import dmdscript.dnative;
+
+d_string arg0string(Value[] arglist)
+{
+    Value* v = arglist.length ? &arglist[0] : &vundefined;
+    return v.toString();
+}
+
+/* ====================== Dglobal_eval ================ */
+
+void* Dglobal_eval(Dobject pthis, CallContext *cc, Dobject othis, Value* ret, Value[] arglist)
+{
+    // ECMA 15.1.2.1
+    Value* v;
+    d_string s;
+    FunctionDefinition fd;
+    ErrInfo errinfo;
+
+    //FuncLog funclog(L"Global.eval()");
+
+    v = arglist.length ? &arglist[0] : &vundefined;
+    if (v.getType() != TypeString)
+    {
+	Value.copy(ret, v);
+	return null;
+    }
+    s = v.toString();
+    //writef("eval('%ls')\n", s);
+
+    // Parse program
+    TopStatement[] topstatements;
+    Parser p = new Parser("eval", s, 0);
+    if (p.parseProgram(topstatements, &errinfo))
+	goto Lsyntaxerror;
+
+    // Analyze, generate code
+    fd = new FunctionDefinition(topstatements);
+    fd.iseval = 1;
+    {
+	Scope sc;
+	sc.ctor(fd);
+	sc.src = s;
+	fd.semantic(&sc);
+	errinfo = sc.errinfo;
+	sc.dtor();
+    }
+    if (errinfo.message)
+	goto Lsyntaxerror;
+    fd.toIR(null);
+
+    // Execute code
+    Value[] locals;
+    Value[] p1 = null;
+
+    Value* v1 = null;
+    if (fd.nlocals < 128)
+	v1 = cast(Value*) alloca(fd.nlocals * Value.sizeof);
+    if (v1)
+	locals = v1[0 .. fd.nlocals];
+    else
+    {
+	p1 = new Value[fd.nlocals];
+	locals = p1;
+    }
+
+    void *result;
+version (none)
+{
+    Array scopex;
+    scopex.reserve(cc.scoperoot + fd.withdepth + 2);
+    for (uint u = 0; u < cc.scoperoot; u++)
+	scopex.push(cc.scopex.data[u]);
+
+    Array *scopesave = cc.scopex;
+    cc.scopex = &scopex;
+    Dobject variablesave = cc.variable;
+    cc.variable = cc.global;
+
+    fd.instantiate(cc.variable, 0);
+
+    // The this value is the same as the this value of the
+    // calling context.
+    result = IR.call(cc, othis, fd.code, ret, locals);
+
+    delete p1;
+    cc.variable = variablesave;
+    cc.scopex = scopesave;
+    return result;
+}
+else
+{
+    // The scope chain is initialized to contain the same objects,
+    // in the same order, as the calling context's scope chain.
+    // This includes objects added to the calling context's
+    // scope chain by WithStatement.
+//    cc.scopex.reserve(fd.withdepth);
+
+    // Variable instantiation is performed using the calling
+    // context's variable object and using empty
+    // property attributes
+    fd.instantiate(cc.scopex, cc.variable, 0);
+
+    // The this value is the same as the this value of the
+    // calling context.
+    assert(cc.callerothis);
+    result = IR.call(cc, cc.callerothis, fd.code, ret, locals.ptr);
+    if (p1)
+	delete p1;
+    fd = null;
+    //if (result) writef("result = '%s'\n", d_string_ptr(((Value* )result).toString()));
+    return result;
+}
+
+Lsyntaxerror:
+    Dobject o;
+
+    // For eval()'s, use location of caller, not the string
+    errinfo.linnum = 0;
+
+    ret.putVundefined();
+    o = new syntaxerror.D0(&errinfo);
+    Value* v2 = new Value;
+    v2.putVobject(o);
+    return v2;
+}
+
+/* ====================== Dglobal_parseInt ================ */
+
+void* Dglobal_parseInt(Dobject pthis, CallContext *cc, Dobject othis, Value* ret, Value[] arglist)
+{
+    // ECMA 15.1.2.2
+    Value* v2;
+    tchar *s;
+    tchar *z;
+    d_int32 radix;
+    int sign = 1;
+    d_number number;
+    uint i;
+    d_string string;
+
+    string = arg0string(arglist);
+
+    //writefln("Dglobal_parseInt('%s')", string);
+
+    while (i < string.length)
+    {	uint idx = i;
+	dchar c = std.utf.decode(string, idx);
+	if (!isStrWhiteSpaceChar(c))
+	    break;
+	i = idx;
+    }
+    s = string.ptr + i;
+    i = string.length - i;
+
+    if (i)
+    {
+	if (*s == '-')
+	{   sign = -1;
+	    s++;
+	    i--;
+	}
+	else if (*s == '+')
+	{   s++;
+	    i--;
+	}
+    }
+
+    radix = 0;
+    if (arglist.length >= 2)
+    {
+	v2 = &arglist[1];
+	radix = v2.toInt32();
+    }
+
+    if (radix)
+    {
+	if (radix < 2 || radix > 36)
+	{
+	    number = d_number.nan;
+	    goto Lret;
+	}
+	if (radix == 16 && i >= 2 && *s == '0' && 
+	    (s[1] == 'x' || s[1] == 'X'))
+	{
+	    s += 2;
+	    i -= 2;
+	}
+    }
+    else if (i >= 1 && *s != '0')
+    {
+	radix = 10;
+    }
+    else if (i >= 2 && (s[1] == 'x' || s[1] == 'X'))
+    {
+	radix = 16;
+	s += 2;
+	i -= 2;
+    }
+    else
+	radix = 8;
+
+    number = 0;
+    for (z = s; i; z++, i--)
+    {   d_int32 n;
+	tchar c;
+
+	c = *z;
+	if ('0' <= c && c <= '9')
+	    n = c - '0';
+	else if ('A' <= c && c <= 'Z')
+	    n = c - 'A' + 10;
+	else if ('a' <= c && c <= 'z')
+	    n = c - 'a' + 10;
+	else
+	    break;
+	if (radix <= n)
+	    break;
+	number = number * radix + n;
+    }
+    if (z == s)
+    {
+	number = d_number.nan;
+	goto Lret;
+    }
+    if (sign < 0)
+	number = -number;
+
+    version (none)    // ECMA says to silently ignore trailing characters
+    {
+	while (z - &string[0] < string.length)
+	{
+	    if (!isStrWhiteSpaceChar(*z))
+	    {
+		number = d_number.nan;
+		goto Lret;
+	    }
+	    z++;
+	}
+    }
+
+Lret:
+    ret.putVnumber(number);
+    return null;
+}
+
+/* ====================== Dglobal_parseFloat ================ */
+
+void* Dglobal_parseFloat(Dobject pthis, CallContext *cc, Dobject othis, Value* ret, Value[] arglist)
+{
+    // ECMA 15.1.2.3
+    d_number n;
+    size_t endidx;
+
+    d_string string = arg0string(arglist);
+    n = StringNumericLiteral(string, endidx, 1);
+
+    ret.putVnumber(n);
+    return null;
+}
+
+/* ====================== Dglobal_escape ================ */
+
+int ISURIALNUM(dchar c)
+{
+    return (c >= 'a' && c <= 'z') ||
+	   (c >= 'A' && c <= 'Z') ||
+	   (c >= '0' && c <= '9');
+}
+
+tchar TOHEX[16+1] = "0123456789ABCDEF";
+
+void* Dglobal_escape(Dobject pthis, CallContext *cc, Dobject othis, Value* ret, Value[] arglist)
+{
+    // ECMA 15.1.2.4
+    d_string s;
+    d_string R;
+    uint escapes;
+    uint unicodes;
+    size_t slen;
+
+    s = arg0string(arglist);
+    escapes = 0;
+    unicodes = 0;
+    foreach (dchar c; s)
+    {
+	slen++;
+	if (c >= 0x100)
+	    unicodes++;
+	else
+	if (c == 0 || c >= 0x80 || (!ISURIALNUM(c) && std.string.find("*@-_+./", c) == -1))
+	    escapes++;
+    }
+    if ((escapes + unicodes) == 0)
+    {
+	R = s;
+    }
+    else
+    {
+	//writefln("s.length = %d, escapes = %d, unicodes = %d", s.length, escapes, unicodes);
+	R = new tchar[slen + escapes * 2 + unicodes * 5];
+	tchar* r = R.ptr;
+	foreach (dchar c; s)
+	{
+	    if (c >= 0x100)
+	    {
+		r[0] = '%';
+		r[1] = 'u';
+		r[2] = TOHEX[(c >> 12) & 15];
+		r[3] = TOHEX[(c >> 8) & 15];
+		r[4] = TOHEX[(c >> 4) & 15];
+		r[5] = TOHEX[c & 15];
+		r += 6;
+	    }
+	    else if (c == 0 || c >= 0x80 || (!ISURIALNUM(c) && std.string.find("*@-_+./", c) == -1))
+	    {
+		r[0] = '%';
+		r[1] = TOHEX[c >> 4];
+		r[2] = TOHEX[c & 15];
+		r += 3;
+	    }
+	    else
+	    {
+		r[0] = cast(tchar)c;
+		r++;
+	    }
+	}
+	assert(r - R.ptr == R.length);
+    }
+    ret.putVstring(R);
+    return null;
+}
+
+/* ====================== Dglobal_unescape ================ */
+
+void* Dglobal_unescape(Dobject pthis, CallContext *cc, Dobject othis, Value* ret, Value[] arglist)
+{
+    // ECMA 15.1.2.5
+    d_string s;
+    d_string R;
+
+    s = arg0string(arglist);
+    //writefln("Dglobal.unescape(s = '%s')", s);
+    for (size_t k = 0; k < s.length; k++)
+    {	tchar c = s[k];
+
+	if (c == '%')
+	{
+	    if (k + 6 <= s.length && s[k + 1] == 'u')
+	    {	uint u;
+
+		u = 0;
+		for (int i = 2; ; i++)
+		{   uint x;
+
+		    if (i == 6)
+		    {
+			std.utf.encode(R, cast(dchar)u);
+			k += 5;
+			goto L1;
+		    }
+		    x = s[k + i];
+		    if ('0' <= x && x <= '9')
+			x = x - '0';
+		    else if ('A' <= x && x <= 'F')
+			x = x - 'A' + 10;
+		    else if ('a' <= x && x <= 'f')
+			x = x - 'a' + 10;
+		    else
+			break;
+		    u = (u << 4) + x;
+		}
+	    }
+	    else if (k + 3 <= s.length)
+	    {	uint u;
+
+		u = 0;
+		for (int i = 1; ; i++)
+		{   uint x;
+
+		    if (i == 3)
+		    {
+			std.utf.encode(R, cast(dchar)u);
+			k += 2;
+			goto L1;
+		    }
+		    x = s[k + i];
+		    if ('0' <= x && x <= '9')
+			x = x - '0';
+		    else if ('A' <= x && x <= 'F')
+			x = x - 'A' + 10;
+		    else if ('a' <= x && x <= 'f')
+			x = x - 'a' + 10;
+		    else
+			break;
+		    u = (u << 4) + x;
+		}
+	    }
+	}
+	R ~= c;
+      L1:
+	;
+    }
+
+    ret.putVstring(R);
+    return null;
+}
+
+/* ====================== Dglobal_isNaN ================ */
+
+void* Dglobal_isNaN(Dobject pthis, CallContext *cc, Dobject othis, Value* ret, Value[] arglist)
+{
+    // ECMA 15.1.2.6
+    Value* v;
+    d_number n;
+    d_boolean b;
+
+    if (arglist.length)
+	v = &arglist[0];
+    else
+	v = &vundefined;
+    n = v.toNumber();
+    b = isnan(n) ? true : false;
+    ret.putVboolean(b);
+    return null;
+}
+
+/* ====================== Dglobal_isFinite ================ */
+
+void* Dglobal_isFinite(Dobject pthis, CallContext *cc, Dobject othis, Value* ret, Value[] arglist)
+{
+    // ECMA 15.1.2.7
+    Value* v;
+    d_number n;
+    d_boolean b;
+
+    if (arglist.length)
+	v = &arglist[0];
+    else
+	v = &vundefined;
+    n = v.toNumber();
+    b = isfinite(n) ? true : false;
+    ret.putVboolean(b);
+    return null;
+}
+
+/* ====================== Dglobal_ URI Functions ================ */
+
+void* URI_error(char[] s)
+{
+    Dobject o = new urierror.D0(s ~ "() failure");
+    Value* v = new Value;
+    v.putVobject(o);
+    return v;
+}
+
+void* Dglobal_decodeURI(Dobject pthis, CallContext *cc, Dobject othis, Value* ret, Value[] arglist)
+{
+    // ECMA v3 15.1.3.1
+    d_string s;
+
+    s = arg0string(arglist);
+    try
+    {
+	s = std.uri.decode(s);
+    }
+    catch (URIerror u)
+    {
+	ret.putVundefined();
+	return URI_error(TEXT_decodeURI);
+    }
+    ret.putVstring(s);
+    return null;
+}
+
+void* Dglobal_decodeURIComponent(Dobject pthis, CallContext *cc, Dobject othis, Value* ret, Value[] arglist)
+{
+    // ECMA v3 15.1.3.2
+    d_string s;
+
+    s = arg0string(arglist);
+    try
+    {
+	s = std.uri.decodeComponent(s);
+    }
+    catch (URIerror u)
+    {
+	ret.putVundefined();
+	return URI_error(TEXT_decodeURIComponent);
+    }
+    ret.putVstring(s);
+    return null;
+}
+
+void* Dglobal_encodeURI(Dobject pthis, CallContext *cc, Dobject othis, Value* ret, Value[] arglist)
+{
+    // ECMA v3 15.1.3.3
+    d_string s;
+
+    s = arg0string(arglist);
+    try
+    {
+	s = std.uri.encode(s);
+    }
+    catch (URIerror u)
+    {
+	ret.putVundefined();
+	return URI_error(TEXT_encodeURI);
+    }
+    ret.putVstring(s);
+    return null;
+}
+
+void* Dglobal_encodeURIComponent(Dobject pthis, CallContext *cc, Dobject othis, Value* ret, Value[] arglist)
+{
+    // ECMA v3 15.1.3.4
+    d_string s;
+
+    s = arg0string(arglist);
+    try
+    {
+	s = std.uri.encodeComponent(s);
+    }
+    catch (URIerror u)
+    {
+	ret.putVundefined();
+	return URI_error(TEXT_encodeURIComponent);
+    }
+    ret.putVstring(s);
+    return null;
+}
+
+/* ====================== Dglobal_print ================ */
+
+static void dglobal_print(CallContext *cc, Dobject othis, Value* ret, Value[] arglist)
+{
+    // Our own extension
+    if (arglist.length)
+    {	uint i;
+
+	for (i = 0; i < arglist.length; i++)
+	{
+	    d_string s = arglist[i].toString();
+
+	    writef("%s", s);
+	}
+    }
+
+    ret.putVundefined();
+}
+
+void* Dglobal_print(Dobject pthis, CallContext *cc, Dobject othis, Value* ret, Value[] arglist)
+{
+    // Our own extension
+    dglobal_print(cc, othis, ret, arglist);
+    return null;
+}
+
+/* ====================== Dglobal_println ================ */
+
+void* Dglobal_println(Dobject pthis, CallContext *cc, Dobject othis, Value* ret, Value[] arglist)
+{
+    // Our own extension
+    dglobal_print(cc, othis, ret, arglist);
+    writef("\n");
+    return null;
+}
+
+/* ====================== Dglobal_readln ================ */
+
+void* Dglobal_readln(Dobject pthis, CallContext *cc, Dobject othis, Value* ret, Value[] arglist)
+{
+    // Our own extension
+    dchar c;
+    tchar[] s;
+
+    for (;;)
+    {
+version (linux)
+{
+	c = std.c.stdio.getchar();
+	if (c == EOF)
+	    break;
+}
+else version (Windows)
+{
+	c = std.c.stdio.getchar();
+	if (c == EOF)
+	    break;
+}
+else version (OSX)
+{
+	c = std.c.stdio.getchar();
+	if (c == EOF)
+	    break;
+}
+else version (FreeBSD)
+{
+	c = std.c.stdio.getchar();
+	if (c == EOF)
+	    break;
+}
+else
+{
+	static assert(0);
+}
+	if (c == '\n')
+	    break;
+	std.utf.encode(s, c);
+    }
+    ret.putVstring(s);
+    return null;
+}
+
+/* ====================== Dglobal_getenv ================ */
+
+void* Dglobal_getenv(Dobject pthis, CallContext *cc, Dobject othis, Value* ret, Value[] arglist)
+{
+    // Our own extension
+    ret.putVundefined();
+    if (arglist.length)
+    {
+	d_string s = arglist[0].toString();
+	tchar* p = getenv(std.string.toStringz(s));
+	if (p)
+	    ret.putVstring(p[0 .. strlen(p)].dup);
+	else
+	    ret.putVnull();
+    }
+    return null;
+}
+
+
+/* ====================== Dglobal_ScriptEngine ================ */
+
+void* Dglobal_ScriptEngine(Dobject pthis, CallContext *cc, Dobject othis, Value* ret, Value[] arglist)
+{
+    ret.putVstring(TEXT_DMDScript);
+    return null;
+}
+
+void* Dglobal_ScriptEngineBuildVersion(Dobject pthis, CallContext *cc, Dobject othis, Value* ret, Value[] arglist)
+{
+    ret.putVnumber(BUILD_VERSION);
+    return null;
+}
+
+void* Dglobal_ScriptEngineMajorVersion(Dobject pthis, CallContext *cc, Dobject othis, Value* ret, Value[] arglist)
+{
+    ret.putVnumber(MAJOR_VERSION);
+    return null;
+}
+
+void* Dglobal_ScriptEngineMinorVersion(Dobject pthis, CallContext *cc, Dobject othis, Value* ret, Value[] arglist)
+{
+    ret.putVnumber(MINOR_VERSION);
+    return null;
+}
+
+/* ====================== Dglobal =========================== */
+
+class Dglobal : Dobject
+{
+    this(tchar[][] argv)
+    {
+	super(Dobject.getPrototype());	// Dglobal.prototype is implementation-dependent
+
+	//writef("Dglobal.Dglobal(%x)\n", this);
+	ThreadContext *tc = ThreadContext.getThreadContext();
+	assert(tc);
+
+	Dobject f = Dfunction.getPrototype();
+
+	classname = TEXT_global;
+
+	// ECMA 15.1
+	// Add in built-in objects which have attribute { DontEnum }
+
+	// Value properties
+
+	Put(TEXT_NaN, d_number.nan, DontEnum);
+	Put(TEXT_Infinity, d_number.infinity, DontEnum);
+
+	static NativeFunctionData nfd[] =
+	[
+	// Function properties
+	    {	&TEXT_eval, &Dglobal_eval, 1 },
+	    {	&TEXT_parseInt, &Dglobal_parseInt, 2 },
+	    {	&TEXT_parseFloat, &Dglobal_parseFloat, 1 },
+	    {	&TEXT_escape, &Dglobal_escape, 1 },
+	    {	&TEXT_unescape, &Dglobal_unescape, 1 },
+	    {	&TEXT_isNaN, &Dglobal_isNaN, 1 },
+	    {	&TEXT_isFinite, &Dglobal_isFinite, 1 },
+	    {	&TEXT_decodeURI, &Dglobal_decodeURI, 1 },
+	    {	&TEXT_decodeURIComponent, &Dglobal_decodeURIComponent, 1 },
+	    {	&TEXT_encodeURI, &Dglobal_encodeURI, 1 },
+	    {	&TEXT_encodeURIComponent, &Dglobal_encodeURIComponent, 1 },
+
+	// Dscript unique function properties
+	    {	&TEXT_print, &Dglobal_print, 1 },
+	    {	&TEXT_println, &Dglobal_println, 1 },
+	    {	&TEXT_readln, &Dglobal_readln, 0 },
+	    {	&TEXT_getenv, &Dglobal_getenv, 1 },
+
+	// Jscript compatible extensions
+	    {	&TEXT_ScriptEngine, &Dglobal_ScriptEngine, 0 },
+	    {	&TEXT_ScriptEngineBuildVersion, &Dglobal_ScriptEngineBuildVersion, 0 },
+	    {	&TEXT_ScriptEngineMajorVersion, &Dglobal_ScriptEngineMajorVersion, 0 },
+	    {	&TEXT_ScriptEngineMinorVersion, &Dglobal_ScriptEngineMinorVersion, 0 },
+	];
+
+	DnativeFunction.init(this, nfd, DontEnum);
+
+	// Now handled by AssertExp()
+	// Put(TEXT_assert, tc.Dglobal_assert(), DontEnum);
+
+	// Constructor properties
+
+	Put(TEXT_Object,         tc.Dobject_constructor, DontEnum);
+	Put(TEXT_Function,       tc.Dfunction_constructor, DontEnum);
+	Put(TEXT_Array,          tc.Darray_constructor, DontEnum);
+	Put(TEXT_String,         tc.Dstring_constructor, DontEnum);
+	Put(TEXT_Boolean,        tc.Dboolean_constructor, DontEnum);
+	Put(TEXT_Number,         tc.Dnumber_constructor, DontEnum);
+	Put(TEXT_Date,           tc.Ddate_constructor, DontEnum);
+	Put(TEXT_RegExp,         tc.Dregexp_constructor, DontEnum);
+	Put(TEXT_Error,          tc.Derror_constructor, DontEnum);
+
+	foreach (d_string key, Dfunction ctor; tc.ctorTable)
+	{
+	    Put(key, ctor, DontEnum);
+	}
+
+	// Other properties
+
+	assert(tc.Dmath_object);
+	Put(TEXT_Math, tc.Dmath_object, DontEnum);
+
+	// Build an "arguments" property out of argv[],
+	// and add it to the global object.
+	Darray arguments;
+
+	arguments = new Darray();
+	Put(TEXT_arguments, arguments, DontDelete);
+	arguments.length.putVnumber(argv.length);
+	for (int i = 0; i < argv.length; i++)
+	{
+	    arguments.Put(i, argv[i].dup, DontEnum);
+	}
+	arguments.Put(TEXT_callee, &vnull, DontEnum);
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/dmdscript_tango/dmath.d	Sun Jan 24 12:34:47 2010 +0200
@@ -0,0 +1,348 @@
+
+/* 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.dmath;
+
+import std.math;
+import std.random;
+
+import dmdscript.script;
+import dmdscript.value;
+import dmdscript.dobject;
+import dmdscript.dnative;
+import dmdscript.threadcontext;
+import dmdscript.text;
+import dmdscript.property;
+
+d_number math_helper(Value[] arglist)
+{
+    Value *v;
+
+    v = arglist.length ? &arglist[0] : &vundefined;
+    return v.toNumber();
+}
+
+void* Dmath_abs(Dobject pthis, CallContext *cc, Dobject othis, Value* ret, Value[] arglist)
+{
+    // ECMA 15.8.2.1
+    d_number result;
+
+    result = fabs(math_helper(arglist));
+    ret.putVnumber(result);
+    return null;
+}
+
+void* Dmath_acos(Dobject pthis, CallContext *cc, Dobject othis, Value* ret, Value[] arglist)
+{
+    // ECMA 15.8.2.2
+    d_number result;
+
+    result = acos(math_helper(arglist));
+    ret.putVnumber(result);
+    return null;
+}
+
+void* Dmath_asin(Dobject pthis, CallContext *cc, Dobject othis, Value* ret, Value[] arglist)
+{
+    // ECMA 15.8.2.3
+    d_number result;
+
+    result = asin(math_helper(arglist));
+    ret.putVnumber(result);
+    return null;
+}
+
+void* Dmath_atan(Dobject pthis, CallContext *cc, Dobject othis, Value* ret, Value[] arglist)
+{
+    // ECMA 15.8.2.4
+    d_number result;
+
+    result = atan(math_helper(arglist));
+    ret.putVnumber(result);
+    return null;
+}
+
+void* Dmath_atan2(Dobject pthis, CallContext *cc, Dobject othis, Value* ret, Value[] arglist)
+{
+    // ECMA 15.8.2.5
+    d_number n1;
+    Value *v2;
+    d_number result;
+
+    n1 = math_helper(arglist);
+    v2 = (arglist.length >= 2) ? &arglist[1] : &vundefined;
+    result = atan2(n1, v2.toNumber());
+    ret.putVnumber(result);
+    return null;
+}
+
+void* Dmath_ceil(Dobject pthis, CallContext *cc, Dobject othis, Value* ret, Value[] arglist)
+{
+    // ECMA 15.8.2.6
+    d_number result;
+
+    result = ceil(math_helper(arglist));
+    ret.putVnumber(result);
+    return null;
+}
+
+void* Dmath_cos(Dobject pthis, CallContext *cc, Dobject othis, Value* ret, Value[] arglist)
+{
+    // ECMA 15.8.2.7
+    d_number result;
+
+    result = cos(math_helper(arglist));
+    ret.putVnumber(result);
+    return null;
+}
+
+void* Dmath_exp(Dobject pthis, CallContext *cc, Dobject othis, Value* ret, Value[] arglist)
+{
+    // ECMA 15.8.2.8
+    d_number result;
+
+    result = std.math.exp(math_helper(arglist));
+    ret.putVnumber(result);
+    return null;
+}
+
+void* Dmath_floor(Dobject pthis, CallContext *cc, Dobject othis, Value* ret, Value[] arglist)
+{
+    // ECMA 15.8.2.9
+    d_number result;
+
+    result = std.math.floor(math_helper(arglist));
+    ret.putVnumber(result);
+    return null;
+}
+
+void* Dmath_log(Dobject pthis, CallContext *cc, Dobject othis, Value* ret, Value[] arglist)
+{
+    // ECMA 15.8.2.10
+    d_number result;
+
+    result = log(math_helper(arglist));
+    ret.putVnumber(result);
+    return null;
+}
+
+void* Dmath_max(Dobject pthis, CallContext *cc, Dobject othis, Value* ret, Value[] arglist)
+{
+    // ECMA v3 15.8.2.11
+    d_number n;
+    d_number result;
+    uint a;
+
+    result = -d_number.infinity;
+    foreach (Value v; arglist)
+    {
+	n = v.toNumber();
+	if (isnan(n))
+	{   result = d_number.nan;
+	    break;
+	}
+	if (result == n)
+	{
+	    // if n is +0 and result is -0, pick n
+	    if (n == 0 && !signbit(n))
+		result = n;
+	}
+	else if (n > result)
+	    result = n;
+    }
+    ret.putVnumber(result);
+    return null;
+}
+
+void* Dmath_min(Dobject pthis, CallContext *cc, Dobject othis, Value* ret, Value[] arglist)
+{
+    // ECMA v3 15.8.2.12
+    d_number n;
+    d_number result;
+    uint a;
+
+    result = d_number.infinity;
+    foreach (Value v; arglist)
+    {
+	n = v.toNumber();
+	if (isnan(n))
+	{   result = d_number.nan;
+	    break;
+	}
+	if (result == n)
+	{
+	    // if n is -0 and result is +0, pick n
+	    if (n == 0 && signbit(n))
+		result = n;
+	}
+	else if (n < result)
+	    result = n;
+    }
+    ret.putVnumber(result);
+    return null;
+}
+
+void* Dmath_pow(Dobject pthis, CallContext *cc, Dobject othis, Value* ret, Value[] arglist)
+{
+    // ECMA 15.8.2.13
+    d_number n1;
+    Value *v2;
+    d_number result;
+
+    n1 = math_helper(arglist);
+    v2 = (arglist.length >= 2) ? &arglist[1] : &vundefined;
+    result = pow(n1, v2.toNumber());
+    ret.putVnumber(result);
+    return null;
+}
+
+void* Dmath_random(Dobject pthis, CallContext *cc, Dobject othis, Value* ret, Value[] arglist)
+{
+    // ECMA 15.8.2.14
+    // 0.0 <= result < 1.0
+    d_number result;
+
+    ulong x;
+
+    // Only want 53 bits of precision
+    x = (cast(ulong)std.random.rand() << 32) + std.random.rand();
+    //PRINTF("x = x%016llx\n",x);
+    x &= 0xFFFFFFFFFFFFF800L;
+    result = x  * (1 / (0x100000000L * cast(double)0x100000000L))
+		+ (1 / (0x200000000L * cast(double)0x100000000L));
+
+    // Experiments on linux show that this will never be exactly
+    // 1.0, so is the assert() worth it?
+    assert(result >= 0 && result < 1.0);
+    ret.putVnumber(result);
+    return null;
+}
+
+void* Dmath_round(Dobject pthis, CallContext *cc, Dobject othis, Value* ret, Value[] arglist)
+{
+    // ECMA 15.8.2.15
+    d_number result;
+
+    result = math_helper(arglist);
+    if (!isnan(result))
+	result = copysign(std.math.floor(result + .5), result);
+    ret.putVnumber(result);
+    return null;
+}
+
+void* Dmath_sin(Dobject pthis, CallContext *cc, Dobject othis, Value* ret, Value[] arglist)
+{
+    // ECMA 15.8.2.16
+    d_number result;
+
+    result = sin(math_helper(arglist));
+    ret.putVnumber(result);
+    return null;
+}
+
+void* Dmath_sqrt(Dobject pthis, CallContext *cc, Dobject othis, Value* ret, Value[] arglist)
+{
+    // ECMA 15.8.2.17
+    d_number result;
+
+    result = sqrt(math_helper(arglist));
+    ret.putVnumber(result);
+    return null;
+}
+
+void* Dmath_tan(Dobject pthis, CallContext *cc, Dobject othis, Value* ret, Value[] arglist)
+{
+    // ECMA 15.8.2.18
+    d_number result;
+
+    result = tan(math_helper(arglist));
+    ret.putVnumber(result);
+    return null;
+}
+
+/* ===================== Dmath ==================== */
+
+class Dmath : Dobject
+{
+    this(ThreadContext *tc)
+    {
+	super(tc.Dobject_prototype);
+
+	//writef("Dmath::Dmath(%x)\n", this);
+	uint attributes = DontEnum | DontDelete | ReadOnly;
+
+	struct MathConst
+	{   d_string *name;
+	    d_number value;
+	}
+
+	static MathConst table[] =
+	[
+	    {   &TEXT_E,       std.math.E       },
+	    {   &TEXT_LN10,    std.math.LN10    },
+	    {   &TEXT_LN2,     std.math.LN2     },
+	    {   &TEXT_LOG2E,   std.math.LOG2E   },
+	    {   &TEXT_LOG10E,  std.math.LOG10E  },
+	    {   &TEXT_PI,      std.math.PI      },
+	    {   &TEXT_SQRT1_2, std.math.SQRT1_2 },
+	    {   &TEXT_SQRT2,   std.math.SQRT2   },
+	];
+
+	for (size_t u = 0; u < table.length; u++)
+	{   Value *v;
+
+	    v = Put(*table[u].name, table[u].value, attributes);
+	    //writef("Put(%s,%.5g) = %x\n", *table[u].name, table[u].value, v);
+	}
+
+	classname = TEXT_Math;
+
+	static NativeFunctionData nfd[] =
+	[
+	    {   &TEXT_abs,    &Dmath_abs,    1 },
+	    {   &TEXT_acos,   &Dmath_acos,   1 },
+	    {   &TEXT_asin,   &Dmath_asin,   1 },
+	    {   &TEXT_atan,   &Dmath_atan,   1 },
+	    {   &TEXT_atan2,  &Dmath_atan2,  2 },
+	    {   &TEXT_ceil,   &Dmath_ceil,   1 },
+	    {   &TEXT_cos,    &Dmath_cos,    1 },
+	    {   &TEXT_exp,    &Dmath_exp,    1 },
+	    {   &TEXT_floor,  &Dmath_floor,  1 },
+	    {   &TEXT_log,    &Dmath_log,    1 },
+	    {   &TEXT_max,    &Dmath_max,    2 },
+	    {   &TEXT_min,    &Dmath_min,    2 },
+	    {   &TEXT_pow,    &Dmath_pow,    2 },
+	    {   &TEXT_random, &Dmath_random, 0 },
+	    {   &TEXT_round,  &Dmath_round,  1 },
+	    {   &TEXT_sin,    &Dmath_sin,    1 },
+	    {   &TEXT_sqrt,   &Dmath_sqrt,   1 },
+	    {   &TEXT_tan,    &Dmath_tan,    1 },
+	];
+
+	DnativeFunction.init(this, nfd, attributes);
+    }
+
+    static void init(ThreadContext *tc)
+    {
+	tc.Dmath_object = new Dmath(tc);
+    }
+}
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/dmdscript_tango/dnative.d	Sun Jan 24 12:34:47 2010 +0200
@@ -0,0 +1,80 @@
+
+/* 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.dnative;
+
+import dmdscript.script;
+import dmdscript.dobject;
+import dmdscript.dfunction;
+import dmdscript.value;
+
+/******************* DnativeFunction ****************************/
+
+alias void *function(Dobject pthis, CallContext *cc, Dobject othis, Value* ret, Value[] arglist) PCall;
+
+struct NativeFunctionData
+{
+    d_string* string;
+    PCall pcall;
+    d_uint32 length;
+}
+
+class DnativeFunction : Dfunction
+{
+    PCall pcall;
+
+    this(PCall func, tchar[] name, d_uint32 length)
+    {
+	super(length);
+	this.name = name;
+	pcall = func;
+    }
+
+    this(PCall func, tchar[] name, d_uint32 length, Dobject o)
+    {
+	super(length, o);
+	this.name = name;
+	pcall = func;
+    }
+
+    void* Call(CallContext *cc, Dobject othis, Value* ret, Value[] arglist)
+    {
+	return (*pcall)(this, cc, othis, ret, arglist);
+    }
+
+    /*********************************
+     * Initalize table of native functions designed
+     * to go in as properties of o.
+     */
+
+    static void init(Dobject o, NativeFunctionData[] nfd, uint attributes)
+    {
+	Dobject f = Dfunction.getPrototype();
+
+	for (size_t i = 0; i < nfd.length; i++)
+	{   NativeFunctionData* n = &nfd[i];
+
+	    o.Put(*n.string,
+		new DnativeFunction(n.pcall, *n.string, n.length, f),
+		attributes);
+	}
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/dmdscript_tango/dnumber.d	Sun Jan 24 12:34:47 2010 +0200
@@ -0,0 +1,666 @@
+
+/* Digital Mars DMDScript source code.
+ * Copyright (c) 2000-2002 by Chromium Communications
+ * D version Copyright (c) 2004-2006 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.dnumber;
+
+import std.math;
+import std.c.stdlib;
+
+import dmdscript.script;
+import dmdscript.dobject;
+import dmdscript.dfunction;
+import dmdscript.value;
+import dmdscript.threadcontext;
+import dmdscript.text;
+import dmdscript.property;
+import dmdscript.errmsgs;
+import dmdscript.dnative;
+
+/* ===================== Dnumber_constructor ==================== */
+
+class Dnumber_constructor : Dfunction
+{
+    this(ThreadContext *tc)
+    {
+	super(1, tc.Dfunction_prototype);
+	uint attributes = DontEnum | DontDelete | ReadOnly;
+
+	name = TEXT_Number;
+	Put(TEXT_MAX_VALUE, d_number.max, attributes);
+	Put(TEXT_MIN_VALUE, d_number.min, attributes);
+	Put(TEXT_NaN, d_number.nan, attributes);
+	Put(TEXT_NEGATIVE_INFINITY, -d_number.infinity, attributes);
+	Put(TEXT_POSITIVE_INFINITY, d_number.infinity, attributes);
+    }
+
+    void* Construct(CallContext *cc, Value *ret, Value[] arglist)
+    {
+	// ECMA 15.7.2
+	d_number n;
+	Dobject o;
+
+	n = (arglist.length) ? arglist[0].toNumber() : 0;
+	o = new Dnumber(n);
+	ret.putVobject(o);
+	return null;
+    }
+
+    void* Call(CallContext *cc, Dobject othis, Value* ret, Value[] arglist)
+    {
+	// ECMA 15.7.1
+	d_number n;
+
+	n = (arglist.length) ? arglist[0].toNumber() : 0;
+	ret.putVnumber(n);
+	return null;
+    }
+}
+
+
+/* ===================== Dnumber_prototype_toString =============== */
+
+void* Dnumber_prototype_toString(Dobject pthis, CallContext *cc, Dobject othis, Value *ret, Value[] arglist)
+{
+    // ECMA v3 15.7.4.2
+    d_string s;
+
+    // othis must be a Number
+    if (!othis.isClass(TEXT_Number))
+    {
+	ret.putVundefined();
+	ErrInfo errinfo;
+	return Dobject.RuntimeError(&errinfo,
+		errmsgtbl[ERR_FUNCTION_WANTS_NUMBER],
+		TEXT_toString,
+		othis.classname);
+    }
+    else
+    {	Value* v;
+
+	v = &(cast(Dnumber)othis).value;
+
+	if (arglist.length)
+	{
+	    d_number radix;
+
+	    radix = arglist[0].toNumber();
+	    if (radix == 10.0 || arglist[0].isUndefined())
+		s = v.toString();
+	    else
+	    {
+		int r;
+
+		r = cast(int) radix;
+		// radix must be an integer 2..36
+		if (r == radix && r >= 2 && r <= 36)
+		    s = v.toString(r);
+		else
+		    s = v.toString();
+	    }
+	}
+	else
+	    s = v.toString();
+	ret.putVstring(s);
+    }
+    return null;
+}
+
+/* ===================== Dnumber_prototype_toLocaleString =============== */
+
+void* Dnumber_prototype_toLocaleString(Dobject pthis, CallContext *cc, Dobject othis, Value *ret, Value[] arglist)
+{
+    // ECMA v3 15.7.4.3
+    d_string s;
+
+    // othis must be a Number
+    if (!othis.isClass(TEXT_Number))
+    {
+	ret.putVundefined();
+	ErrInfo errinfo;
+	return Dobject.RuntimeError(&errinfo,
+		errmsgtbl[ERR_FUNCTION_WANTS_NUMBER],
+		TEXT_toLocaleString,
+		othis.classname);
+    }
+    else
+    {	Value* v;
+
+	v = &(cast(Dnumber)othis).value;
+
+	s = v.toLocaleString();
+	ret.putVstring(s);
+    }
+    return null;
+}
+
+/* ===================== Dnumber_prototype_valueOf =============== */
+
+void* Dnumber_prototype_valueOf(Dobject pthis, CallContext *cc, Dobject othis, Value *ret, Value[] arglist)
+{
+    // othis must be a Number
+    if (!othis.isClass(TEXT_Number))
+    {
+	ret.putVundefined();
+	ErrInfo errinfo;
+	return Dobject.RuntimeError(&errinfo,
+		errmsgtbl[ERR_FUNCTION_WANTS_NUMBER],
+		TEXT_valueOf,
+		othis.classname);
+    }
+    else
+    {
+	Value* v;
+
+	v = &(cast(Dnumber)othis).value;
+	Value.copy(ret, v);
+    }
+    return null;
+}
+
+/* ===================== Formatting Support =============== */
+
+const int FIXED_DIGITS = 20;	// ECMA says >= 20
+
+
+// power of tens array, indexed by power
+
+static d_number tens[FIXED_DIGITS+1] =
+[
+    1,   1e1, 1e2, 1e3, 1e4, 1e5, 1e6, 1e7, 1e8, 1e9,
+    1e10,1e11,1e12,1e13,1e14,1e15,1e16,1e17,1e18,1e19,
+    1e20,
+];
+
+/************************************************
+ * Let e and n be integers such that
+ * 10**f <= n < 10**(f+1) and for which the exact
+ * mathematical value of n * 10**(e-f) - x is as close
+ * to zero as possible. If there are two such sets of
+ * e and n, pick the e and n for which n * 10**(e-f)
+ * is larger.
+ */
+
+number_t deconstruct_real(d_number x, int f, out int pe)
+{
+    number_t n;
+    int e;
+    int i;
+
+    e = cast(int) log10(x);
+    i = e - f;
+    if (i >= 0 && i < tens.length)
+	// table lookup for speed & accuracy
+	n = cast(number_t)(x / tens[i] + 0.5);
+    else
+	n = cast(number_t)(x / std.math.pow(cast(real)10.0, i) + 0.5);
+
+    pe = e;
+    return n;
+}
+
+/* ===================== Dnumber_prototype_toFixed =============== */
+
+void* Dnumber_prototype_toFixed(Dobject pthis, CallContext *cc, Dobject othis, Value *ret, Value[] arglist)
+{
+    // ECMA v3 15.7.4.5
+    Value* v;
+    d_number x;
+    d_number fractionDigits;
+    d_string result;
+    int dup;
+
+    v = &arglist[0];
+    fractionDigits = (arglist.length) ? v.toInteger() : 0;
+    if (fractionDigits < 0 || fractionDigits > FIXED_DIGITS)
+    {
+	ErrInfo errinfo;
+
+	ret.putVundefined();
+	return Dobject.RangeError(&errinfo, ERR_VALUE_OUT_OF_RANGE,
+		TEXT_toFixed, "fractionDigits");
+    }
+    v = &othis.value;
+    x = v.toNumber();
+    if (isnan(x))
+    {
+	result = TEXT_NaN;		// return "NaN"
+    }
+    else
+    {	int sign;
+	tchar[] m;
+
+	sign = 0;
+	if (x < 0)
+	{
+	    sign = 1;
+	    x = -x;
+	}
+	if (x >= 10.0e+21)		// exponent must be FIXED_DIGITS+1
+	{
+	    Value vn;
+	    vn.putVnumber(x);
+	    m = vn.toString();
+	    dup = 0;
+	}
+	else
+	{
+	    number_t n;
+	    tchar buffer[32 + 1];
+	    d_number tenf;
+	    int f;
+
+	    f = cast(int) fractionDigits;
+	    tenf = tens[f];		// tenf = 10**f
+
+	    // Compute n which gives |(n / tenf) - x| is the smallest
+	    // value. If there are two such n's, pick the larger.
+	    n = cast(number_t)(x * tenf + 0.5);		// round up & chop
+
+	    if (n == 0)
+	    {	m = "0";
+		dup = 0;
+	    }
+	    else
+	    {
+		// n still doesn't give 20 digits, only 19
+		m = std.string.sformat(buffer, cast(ulong)n);
+		dup = 1;
+	    }
+	    if (f != 0)
+	    {	int i;
+		int k;
+
+		k = m.length;
+		if (k <= f)
+		{   tchar* s;
+		    int nzeros;
+
+		    s = cast(tchar*)alloca((f + 1) * tchar.sizeof);
+		    assert(s);
+		    nzeros = f + 1 - k;
+		    s[0 .. nzeros] = '0';
+		    s[nzeros .. f + 1] = m[0 .. k];
+
+		    m = s[0 .. f + 1];
+		    k = f + 1;
+		}
+
+		// result = "-" + m[0 .. k-f] + "." + m[k-f .. k];
+		result = new tchar[sign + k + 1];
+		if (sign)
+		    result[0] = '-';
+		i = k - f;
+		result[sign .. sign + i] = m[0 .. i];
+		result[sign + i] = '.';
+		result[sign + i + 1 .. sign + k + 1] = m[i .. k];
+		goto Ldone;
+	    }
+	}
+	if (sign)
+	    result = TEXT_dash ~ m;
+	else if (dup)
+	    result = m.dup;
+	else
+	    result = m;
+    }
+
+Ldone:
+    ret.putVstring(result);
+    return null;
+}
+
+/* ===================== Dnumber_prototype_toExponential =============== */
+
+void* Dnumber_prototype_toExponential(Dobject pthis, CallContext *cc, Dobject othis, Value *ret, Value[] arglist)
+{
+    // ECMA v3 15.7.4.6
+    Value* varg;
+    Value* v;
+    d_number x;
+    d_number fractionDigits;
+    d_string result;
+
+    varg = &arglist[0];
+    fractionDigits = (arglist.length) ? varg.toInteger() : 0;
+
+    v = &othis.value;
+    x = v.toNumber();
+    if (isnan(x))
+    {
+	result = TEXT_NaN;		// return "NaN"
+    }
+    else
+    {	int sign;
+
+	sign = 0;
+	if (x < 0)
+	{
+	    sign = 1;
+	    x = -x;
+	}
+	if (std.math.isinf(x))
+	{
+	    result = sign ? TEXT_negInfinity : TEXT_Infinity;
+	}
+	else
+	{   int f;
+	    number_t n;
+	    int e;
+	    tchar[] m;
+	    int i;
+	    tchar buffer[32 + 1];
+
+	    if (fractionDigits < 0 || fractionDigits > FIXED_DIGITS)
+            {
+		ErrInfo errinfo;
+
+		ret.putVundefined();
+		return Dobject.RangeError(&errinfo,
+			ERR_VALUE_OUT_OF_RANGE,
+			TEXT_toExponential,
+			"fractionDigits");
+            }
+
+	    f = cast(int) fractionDigits;
+	    if (x == 0)
+	    {	tchar* s;
+
+		s = cast(tchar*)alloca((f + 1) * tchar.sizeof);
+		assert(s);
+		m = s[0 .. f + 1];
+		m[0 .. f + 1] = '0';
+		e = 0;
+	    }
+	    else
+	    {
+		if (arglist.length && !varg.isUndefined())
+		{
+		    /* Step 12
+		     * Let e and n be integers such that
+		     * 10**f <= n < 10**(f+1) and for which the exact
+		     * mathematical value of n * 10**(e-f) - x is as close
+		     * to zero as possible. If there are two such sets of
+		     * e and n, pick the e and n for which n * 10**(e-f)
+		     * is larger.
+		     * [Note: this is the same as Step 15 in toPrecision()
+		     *  with f = p - 1]
+		     */
+		    n = deconstruct_real(x, f, e);
+		}
+		else
+		{
+		    /* Step 19
+		     * Let e, n, and f be integers such that f >= 0,
+		     * 10**f <= n < 10**(f+1), the number value for
+		     * n * 10**(e-f) is x, and f is as small as possible.
+		     * Note that the decimal representation of n has f+1
+		     * digits, n is not divisible by 10, and the least
+		     * significant digit of n is not necessarilly uniquely
+		     * determined by these criteria.
+		     */
+		    /* Implement by trying maximum digits, and then
+		     * lopping off trailing 0's.
+		     */
+		    f = 19;		// should use FIXED_DIGITS
+		    n = deconstruct_real(x, f, e);
+
+		    // Lop off trailing 0's
+		    assert(n);
+		    while ((n % 10) == 0)
+		    {
+			n /= 10;
+			f--;
+			assert(f >= 0);
+		    }
+		}
+		// n still doesn't give 20 digits, only 19
+		m = std.string.sformat(buffer, cast(ulong)n);
+	    }
+	    if (f)
+	    {	tchar* s;
+
+		// m = m[0] + "." + m[1 .. f+1];
+		s = cast(tchar*)alloca((f + 2) * tchar.sizeof);
+		assert(s);
+		s[0] = m[0];
+		s[1] = '.';
+		s[2 .. f + 2] = m[1 .. f + 1];
+		m = s[0 .. f + 2];
+	    }
+
+	    // result = sign + m + "e" + c + e;
+	    tchar[] c = (e >= 0) ? "+" : "";
+
+	    result = std.string.format("%s%se%s%d", sign ? "-" : "", m, c, e);
+	}
+    }
+
+    ret.putVstring(result);
+    return null;
+}
+
+/* ===================== Dnumber_prototype_toPrecision =============== */
+
+void* Dnumber_prototype_toPrecision(Dobject pthis, CallContext *cc, Dobject othis, Value *ret, Value[] arglist)
+{
+    // ECMA v3 15.7.4.7
+    Value* varg;
+    Value* v;
+    d_number x;
+    d_number precision;
+    d_string result;
+
+    v = &othis.value;
+    x = v.toNumber();
+
+    varg = (arglist.length == 0) ? &vundefined : &arglist[0];
+
+    if (arglist.length == 0 || varg.isUndefined())
+    {
+	Value vn;
+
+	vn.putVnumber(x);
+	result = vn.toString();
+    }
+    else
+    {
+	if (isnan(x))
+	    result = TEXT_NaN;
+	else
+	{   int sign;
+	    int e;
+	    int p;
+	    int i;
+	    tchar[] m;
+	    number_t n;
+	    tchar buffer[32 + 1];
+
+	    sign = 0;
+	    if (x < 0)
+	    {
+		sign = 1;
+		x = -x;
+	    }
+
+	    if (std.math.isinf(x))
+	    {
+		result = sign ? TEXT_negInfinity : TEXT_Infinity;
+		goto Ldone;
+	    }
+
+	    precision = varg.toInteger();
+	    if (precision < 1 || precision > 21)
+            {
+		ErrInfo errinfo;
+
+		ret.putVundefined();
+		return Dobject.RangeError(&errinfo,
+			ERR_VALUE_OUT_OF_RANGE,
+			TEXT_toPrecision,
+			"precision");
+            }
+
+	    p = cast(int) precision;
+	    if (x != 0)
+	    {
+		/* Step 15
+		 * Let e and n be integers such that 10**(p-1) <= n < 10**p
+		 * and for which the exact mathematical value of n * 10**(e-p+1) - x
+		 * is as close to zero as possible. If there are two such sets
+		 * of e and n, pick the e and n for which n * 10**(e-p+1) is larger.
+		 */
+		n = deconstruct_real(x, p - 1, e);
+
+		// n still doesn't give 20 digits, only 19
+		m = std.string.sformat(buffer, cast(ulong)n);
+
+		if (e < -6 || e >= p)
+		{
+		    // result = sign + m[0] + "." + m[1 .. p] + "e" + c + e;
+		    tchar[] c = (e >= 0) ? "+" : "";
+		    result = std.string.format("%s%s.%se%s%d",
+			(sign ? "-" : ""), m[0], m[1 .. length], c, e);
+		    goto Ldone;
+		}
+	    }
+	    else
+	    {
+		// Step 12
+		// m = array[p] of '0'
+		tchar* s;
+		s = cast(tchar*)alloca(p * tchar.sizeof);
+		assert(s);
+		m = s[0 .. p];
+		m[] = '0';
+
+		e = 0;
+	    }
+	    if (e != p - 1)
+	    {	tchar* s;
+
+		if (e >= 0)
+		{
+		    // m = m[0 .. e+1] + "." + m[e+1 .. p];
+
+		    s = cast(tchar*)alloca((p + 1) * tchar.sizeof);
+		    assert(s);
+		    i = e + 1;
+		    s[0 .. i] = m[0 .. i];
+		    s[i] = '.';
+		    s[i + 1 .. p + 1] = m[i .. p];
+		    m = s[0 .. p + 1];
+		}
+		else
+		{
+		    // m = "0." + (-(e+1) occurrences of the character '0') + m;
+		    int imax = 2 + -(e + 1);
+
+		    s = cast(tchar*)alloca((imax + p) * tchar.sizeof);
+		    assert(s);
+		    s[0] = '0';
+		    s[1] = '.';
+		    s[2 .. imax] = '0';
+		    s[imax .. imax + p] = m[0 .. p];
+		    m = s[0 .. imax + p];
+		}
+	    }
+	    if (sign)
+		result = TEXT_dash ~ m;
+	    else
+		result = m.dup;
+	}
+    }
+
+Ldone:
+    ret.putVstring(result);
+    return null;
+}
+
+/* ===================== Dnumber_prototype ==================== */
+
+class Dnumber_prototype : Dnumber
+{
+    this(ThreadContext *tc)
+    {
+	super(tc.Dobject_prototype);
+	uint attributes = DontEnum;
+
+	Dobject f = tc.Dfunction_prototype;
+
+	Put(TEXT_constructor, tc.Dnumber_constructor, attributes);
+
+	static NativeFunctionData nfd[] =
+	[
+	    {   &TEXT_toString, &Dnumber_prototype_toString, 1 },
+	    // Permissible to use toString()
+	    {   &TEXT_toLocaleString, &Dnumber_prototype_toLocaleString, 1 },
+	    {   &TEXT_valueOf, &Dnumber_prototype_valueOf, 0 },
+	    {   &TEXT_toFixed, &Dnumber_prototype_toFixed, 1 },
+	    {   &TEXT_toExponential, &Dnumber_prototype_toExponential, 1 },
+	    {   &TEXT_toPrecision, &Dnumber_prototype_toPrecision, 1 },
+	];
+
+	DnativeFunction.init(this, nfd, attributes);
+    }
+}
+
+
+/* ===================== Dnumber ==================== */
+
+class Dnumber : Dobject
+{
+    this(d_number n)
+    {
+	super(getPrototype());
+	classname = TEXT_Number;
+	value.putVnumber(n);
+    }
+
+    this(Dobject prototype)
+    {
+	super(prototype);
+	classname = TEXT_Number;
+	value.putVnumber(0);
+    }
+
+    static Dfunction getConstructor()
+    {
+	ThreadContext *tc = ThreadContext.getThreadContext();
+	assert(tc);
+	return tc.Dnumber_constructor;
+    }
+
+    static Dobject getPrototype()
+    {
+	ThreadContext *tc = ThreadContext.getThreadContext();
+	assert(tc);
+	return tc.Dnumber_prototype;
+    }
+
+    static void init(ThreadContext *tc)
+    {
+	tc.Dnumber_constructor = new Dnumber_constructor(tc);
+	tc.Dnumber_prototype = new Dnumber_prototype(tc);
+
+	tc.Dnumber_constructor.Put(TEXT_prototype, tc.Dnumber_prototype, DontEnum | DontDelete | ReadOnly);
+    }
+}
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/dmdscript_tango/dobject.d	Sun Jan 24 12:34:47 2010 +0200
@@ -0,0 +1,693 @@
+
+/* Digital Mars DMDScript source code.
+ * Copyright (c) 2000-2002 by Chromium Communications
+ * D version Copyright (c) 2004-2006 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.dobject;
+
+import std.string;
+import std.c.stdarg;
+import std.c.string;
+
+import dmdscript.script;
+import dmdscript.value;
+import dmdscript.dfunction;
+import dmdscript.property;
+import dmdscript.threadcontext;
+import dmdscript.iterator;
+import dmdscript.identifier;
+import dmdscript.errmsgs;
+import dmdscript.text;
+import dmdscript.program;
+
+import dmdscript.dboolean;
+import dmdscript.dstring;
+import dmdscript.dnumber;
+import dmdscript.darray;
+import dmdscript.dmath;
+import dmdscript.ddate;
+import dmdscript.dregexp;
+import dmdscript.derror;
+import dmdscript.dnative;
+
+import dmdscript.protoerror;
+int* pfoo = &dmdscript.protoerror.foo;	// link it in
+
+
+//debug = LOG;
+
+/************************** Dobject_constructor *************************/
+
+class Dobject_constructor : Dfunction
+{
+    this(ThreadContext *tc)
+    {
+	super(1, tc.Dfunction_prototype);
+	if (tc.Dobject_prototype)
+	    Put(TEXT_prototype, tc.Dobject_prototype, DontEnum | DontDelete | ReadOnly);
+    }
+
+    void *Construct(CallContext *cc, Value *ret, Value[] arglist)
+    {   Dobject o;
+	Value* v;
+
+	// ECMA 15.2.2
+	if (arglist.length == 0)
+	{
+	    o = new Dobject(Dobject.getPrototype());
+	}
+	else
+	{
+	    v = &arglist[0];
+	    if (v.isPrimitive())
+	    {
+		if (v.isUndefinedOrNull())
+		{
+		    o = new Dobject(Dobject.getPrototype());
+		}
+		else
+		    o = v.toObject();
+	    }
+	    else
+		o = v.toObject();
+	}
+	//printf("constructed object o=%p, v=%p,'%s'\n", o, v,v.getType());
+	ret.putVobject(o);
+	return null;
+    }
+
+    void *Call(CallContext *cc, Dobject othis, Value* ret, Value[] arglist)
+    {   Dobject o;
+	void *result;
+
+	// ECMA 15.2.1
+	if (arglist.length == 0)
+	{
+	    result = Construct(cc, ret, arglist);
+	}
+	else
+	{   Value* v;
+
+	    v = &arglist[0];
+	    if (v.isUndefinedOrNull())
+		result = Construct(cc, ret, arglist);
+	    else
+	    {
+		o = v.toObject();
+		ret.putVobject(o);
+		result = null;
+	    }
+	}
+	return result;
+    }
+}
+
+
+/* ===================== Dobject_prototype_toString ================ */
+
+void* Dobject_prototype_toString(Dobject pthis, CallContext *cc, Dobject othis, Value *ret, Value[] arglist)
+{
+    d_string s;
+    d_string string;
+
+    //debug (LOG) writef("Dobject.prototype.toString(ret = %x)\n", ret);
+
+    s = othis.classname;
+/+
+    // Should we do [object] or [object Object]?
+    if (s == TEXT_Object)
+        string = TEXT_bobjectb;
+    else
++/
+	string = std.string.format("[object %s]", s);
+    ret.putVstring(string);
+    return null;
+}
+
+/* ===================== Dobject_prototype_toLocaleString ================ */
+
+void* Dobject_prototype_toLocaleString(Dobject pthis, CallContext *cc, Dobject othis, Value *ret, Value[] arglist)
+{
+    // ECMA v3 15.2.4.3
+    //	"This function returns the result of calling toString()."
+
+    Value* v;
+
+    //writef("Dobject.prototype.toLocaleString(ret = %x)\n", ret);
+    v = othis.Get(TEXT_toString);
+    if (v && !v.isPrimitive())	// if it's an Object
+    {   void *a;
+	Dobject o;
+
+	o = v.object;
+	a = o.Call(cc, othis, ret, arglist);
+	if (a)			// if exception was thrown
+	    return a;
+    }
+    return null;
+}
+
+/* ===================== Dobject_prototype_valueOf ================ */
+
+void* Dobject_prototype_valueOf(Dobject pthis, CallContext *cc, Dobject othis, Value *ret, Value[] arglist)
+{
+    ret.putVobject(othis);
+    return null;
+}
+
+/* ===================== Dobject_prototype_toSource ================ */
+
+void* Dobject_prototype_toSource(Dobject pthis, CallContext *cc, Dobject othis, Value *ret, Value[] arglist)
+{
+    tchar[] buf;
+    int any;
+
+    //writef("Dobject.prototype.toSource(this = %p, ret = %p)\n", this, ret);
+
+    buf = "{";
+    any = 0;
+    foreach (Value key, Property p; *othis.proptable)
+    {
+	if (!(p.attributes & (DontEnum | Deleted)))
+	{
+	    if (any)
+		buf ~= ',';
+	    any = 1;
+	    buf ~= key.toString();
+	    buf ~= ':';
+	    buf ~= p.value.toSource();
+	}
+    }
+    buf ~= '}';
+    ret.putVstring(buf);
+    return null;
+}
+
+/* ===================== Dobject_prototype_hasOwnProperty ================ */
+
+void* Dobject_prototype_hasOwnProperty(Dobject pthis, CallContext *cc, Dobject othis, Value *ret, Value[] arglist)
+{
+    // ECMA v3 15.2.4.5
+    Value* v;
+
+    v = arglist.length ? &arglist[0] : &vundefined;
+    ret.putVboolean(othis.proptable.hasownproperty(v, 0));
+    return null;
+}
+
+/* ===================== Dobject_prototype_isPrototypeOf ================ */
+
+void* Dobject_prototype_isPrototypeOf(Dobject pthis, CallContext *cc, Dobject othis, Value *ret, Value[] arglist)
+{
+    // ECMA v3 15.2.4.6
+    d_boolean result = false;
+    Value* v;
+    Dobject o;
+
+    v = arglist.length ? &arglist[0] : &vundefined;
+    if (!v.isPrimitive())
+    {
+	o = v.toObject();
+	for (;;)
+	{
+	    o = o.internal_prototype;
+	    if (!o)
+		break;
+	    if (o == othis)
+	    {	result = true;
+		break;
+	    }
+	}
+    }
+
+    ret.putVboolean(result);
+    return null;
+}
+
+/* ===================== Dobject_prototype_propertyIsEnumerable ================ */
+
+void* Dobject_prototype_propertyIsEnumerable(Dobject pthis, CallContext *cc, Dobject othis, Value *ret, Value[] arglist)
+{
+    // ECMA v3 15.2.4.7
+    Value* v;
+
+    v = arglist.length ? &arglist[0] : &vundefined;
+    ret.putVboolean(othis.proptable.hasownproperty(v, 1));
+    return null;
+}
+
+/* ===================== Dobject_prototype ========================= */
+
+class Dobject_prototype : Dobject
+{
+    this(ThreadContext *tc)
+    {
+	super(null);
+    }
+}
+
+
+/* ====================== Dobject ======================= */
+
+class Dobject
+{
+    PropTable* proptable;
+    Dobject internal_prototype;
+    d_string classname;
+    Value value;
+
+    const uint DOBJECT_SIGNATURE = 0xAA31EE31;
+    uint signature;
+
+    invariant
+    {
+	assert(signature == DOBJECT_SIGNATURE);
+    }
+
+    this(Dobject prototype)
+    {
+	//writef("new Dobject = %x, prototype = %x, line = %d, file = '%s'\n", this, prototype, GC.line, ascii2unicode(GC.file));
+	//writef("Dobject(prototype = %p)\n", prototype);
+	proptable = new PropTable;
+	internal_prototype = prototype;
+	if (prototype)
+	    proptable.previous = prototype.proptable;
+	classname = TEXT_Object;
+	value.putVobject(this);
+
+	signature = DOBJECT_SIGNATURE;
+    }
+
+    Dobject Prototype()
+    {
+	return internal_prototype;
+    }
+
+    Value* Get(d_string PropertyName)
+    {
+	return Get(PropertyName, Value.calcHash(PropertyName));
+    }
+
+    Value* Get(Identifier* id)
+    {
+	Value* v;
+
+	//writefln("Dobject.Get(this = %x, '%s', hash = %x)", cast(uint)cast(void*)this, PropertyName, hash);
+	//writef("\tinternal_prototype = %p\n", this.internal_prototype);
+	//writef("\tDfunction.getPrototype() = %p\n", Dfunction.getPrototype());
+	v = proptable.get(&id.value, id.value.hash);
+	//if (v) writef("found it %p\n", v.object);
+	return v;
+    }
+
+    Value* Get(d_string PropertyName, uint hash)
+    {
+	Value* v;
+
+	//writefln("Dobject.Get(this = %x, '%s', hash = %x)", cast(uint)cast(void*)this, PropertyName, hash);
+	//writef("\tinternal_prototype = %p\n", this.internal_prototype);
+	//writef("\tDfunction.getPrototype() = %p\n", Dfunction.getPrototype());
+	v = proptable.get(PropertyName, hash);
+	//if (v) writef("found it %p\n", v.object);
+	return v;
+    }
+
+    Value* Get(d_uint32 index)
+    {
+	Value* v;
+
+	v = proptable.get(index);
+    //    if (!v)
+    //	v = &vundefined;
+	return v;
+    }
+
+    Value* Get(d_uint32 index, Value* vindex)
+    {
+	return proptable.get(vindex, Value.calcHash(index));
+    }
+
+    Value* Put(d_string PropertyName, Value* value, uint attributes)
+    {
+	// ECMA 8.6.2.2
+	//writef("Dobject.Put(this = %p)\n", this);
+	proptable.put(PropertyName, value, attributes);
+	return null;
+    }
+
+    Value* Put(Identifier* key, Value* value, uint attributes)
+    {
+	// ECMA 8.6.2.2
+	//writef("Dobject.Put(this = %p)\n", this);
+	proptable.put(&key.value, key.value.hash, value, attributes);
+	return null;
+    }
+
+    Value* Put(d_string PropertyName, Dobject o, uint attributes)
+    {
+	// ECMA 8.6.2.2
+	Value v;
+	v.putVobject(o);
+
+	proptable.put(PropertyName, &v, attributes);
+	return null;
+    }
+
+    Value* Put(d_string PropertyName, d_number n, uint attributes)
+    {
+	// ECMA 8.6.2.2
+	Value v;
+	v.putVnumber(n);
+
+	proptable.put(PropertyName, &v, attributes);
+	return null;
+    }
+
+    Value* Put(d_string PropertyName, d_string s, uint attributes)
+    {
+	// ECMA 8.6.2.2
+	Value v;
+	v.putVstring(s);
+
+	proptable.put(PropertyName, &v, attributes);
+	return null;
+    }
+
+    Value* Put(d_uint32 index, Value* vindex, Value* value, uint attributes)
+    {
+	// ECMA 8.6.2.2
+	proptable.put(vindex, Value.calcHash(index), value, attributes);
+	return null;
+    }
+
+    Value* Put(d_uint32 index, Value* value, uint attributes)
+    {
+	// ECMA 8.6.2.2
+	proptable.put(index, value, attributes);
+	return null;
+    }
+
+    Value* PutDefault(Value* value)
+    {
+	// Not ECMA, Microsoft extension
+	//writef("Dobject.PutDefault(this = %p)\n", this);
+	ErrInfo errinfo;
+	return RuntimeError(&errinfo, ERR_NO_DEFAULT_PUT);
+    }
+
+    Value* put_Value(Value* ret, Value[] arglist)
+    {
+	// Not ECMA, Microsoft extension
+	//writef("Dobject.put_Value(this = %p)\n", this);
+	ErrInfo errinfo;
+	return RuntimeError(&errinfo, ERR_FUNCTION_NOT_LVALUE);
+    }
+
+    int CanPut(d_string PropertyName)
+    {
+	// ECMA 8.6.2.3
+	return proptable.canput(PropertyName);
+    }
+
+    int HasProperty(d_string PropertyName)
+    {
+	// ECMA 8.6.2.4
+	return proptable.hasproperty(PropertyName);
+    }
+
+    /***********************************
+     * Return:
+     *	TRUE	not found or successful delete
+     *	FALSE	property is marked with DontDelete attribute
+     */
+
+    int Delete(d_string PropertyName)
+    {
+	// ECMA 8.6.2.5
+	//writef("Dobject.Delete('%ls')\n", d_string_ptr(PropertyName));
+	return proptable.del(PropertyName);
+    }
+
+    int Delete(d_uint32 index)
+    {
+	// ECMA 8.6.2.5
+	return proptable.del(index);
+    }
+
+    int implementsDelete()
+    {
+	// ECMA 8.6.2 says every object implements [[Delete]],
+	// but ECMA 11.4.1 says that some objects may not.
+	// Assume the former is correct.
+	return true;
+    }
+
+    void *DefaultValue(Value* ret, tchar[] Hint)
+    {   Dobject o;
+	Value* v;
+	static d_string*[2] table = [ &TEXT_toString, &TEXT_valueOf ];
+	int i = 0;			// initializer necessary for /W4
+
+	// ECMA 8.6.2.6
+	//writef("Dobject.DefaultValue(ret = %x, Hint = '%s')\n", cast(uint)ret, Hint);
+
+	if (Hint == TypeString ||
+	    (Hint == null && this.isDdate()))
+	{
+	    i = 0;
+	}
+	else if (Hint == TypeNumber ||
+		 Hint == null)
+	{
+	    i = 1;
+	}
+	else
+	    assert(0);
+
+	for (int j = 0; j < 2; j++)
+	{   d_string htab = *table[i];
+
+	    //writefln("\ti = %d, htab = '%s'", i, htab);
+	    v = Get(htab, Value.calcHash(htab));
+	    //writefln("\tv = %x", cast(uint)v);
+	    if (v && !v.isPrimitive())	// if it's an Object
+	    {   void *a;
+		CallContext *cc;
+
+		//writefln("\tfound default value");
+		o = v.object;
+		cc = Program.getProgram().callcontext;
+		a = o.Call(cc, this, ret, null);
+		if (a)			// if exception was thrown
+		    return a;
+		if (ret.isPrimitive())
+		    return null;
+	    }
+	    i ^= 1;
+	}
+	ret.putVstring(classname);
+	return null;
+	//ErrInfo errinfo;
+	//return RuntimeError(&errinfo, DTEXT("no Default Value for object"));
+    }
+
+    void *Construct(CallContext *cc, Value *ret, Value[] arglist)
+    {   ErrInfo errinfo;
+	return RuntimeError(&errinfo, errmsgtbl[ERR_S_NO_CONSTRUCT], classname);
+    }
+
+    void *Call(CallContext *cc, Dobject othis, Value* ret, Value[] arglist)
+    {
+	ErrInfo errinfo;
+	return RuntimeError(&errinfo, errmsgtbl[ERR_S_NO_CALL], classname);
+    }
+
+    void *HasInstance(Value* ret, Value* v)
+    {   // ECMA v3 8.6.2
+	ErrInfo errinfo;
+	return RuntimeError(&errinfo, errmsgtbl[ERR_S_NO_INSTANCE], classname);
+    }
+
+    d_string getTypeof()
+    {   // ECMA 11.4.3
+	return TEXT_object;
+    }
+
+
+    int isClass(d_string classname)
+    {
+	return this.classname == classname;
+    }
+
+    int isDarray()	{ return isClass(TEXT_Array); }
+    int isDdate()	{ return isClass(TEXT_Date); }
+    int isDregexp()	{ return isClass(TEXT_RegExp); }
+
+    int isDarguments()	{ return false; }
+    int isCatch()	{ return false; }
+    int isFinally()	{ return false; }
+
+    void getErrInfo(ErrInfo *perrinfo, int linnum)
+    {
+	ErrInfo errinfo;
+	Value v;
+	v.putVobject(this);
+
+	errinfo.message = v.toString();
+	if (perrinfo)
+	    *perrinfo = errinfo;
+    }
+
+    static Value* RuntimeError(ErrInfo *perrinfo, int msgnum)
+    {
+	return RuntimeError(perrinfo, errmsgtbl[msgnum]);
+    }
+
+    static Value* RuntimeError(ErrInfo *perrinfo, ...)
+    {   Dobject o;
+
+	perrinfo.message = null;
+
+	void putc(dchar c)
+	{
+	    std.utf.encode(perrinfo.message, c);
+	}
+
+	std.format.doFormat(&putc, _arguments, _argptr);
+
+	o = new typeerror.D0(perrinfo);
+	Value* v = new Value;
+	v.putVobject(o);
+	return v;
+    }
+
+    static Value* RangeError(ErrInfo *perrinfo, int msgnum)
+    {
+	return RangeError(perrinfo, errmsgtbl[msgnum]);
+    }
+
+    static Value* RangeError(ErrInfo *perrinfo, ...)
+    {   Dobject o;
+
+	perrinfo.message = null;
+
+	void putc(dchar c)
+	{
+	    std.utf.encode(perrinfo.message, c);
+	}
+
+	std.format.doFormat(&putc, _arguments, _argptr);
+
+	o = new rangeerror.D0(perrinfo);
+	Value* v = new Value;
+	v.putVobject(o);
+	return v;
+    }
+
+    Value* putIterator(Value* v)
+    {
+	Iterator* i = new Iterator;
+
+	i.ctor(this);
+	v.putViterator(i);
+	return null;
+    }
+
+    static Dfunction getConstructor()
+    {
+	ThreadContext *tc = ThreadContext.getThreadContext();
+	assert(tc);
+	return tc.Dobject_constructor;
+    }
+
+    static Dobject getPrototype()
+    {
+	ThreadContext *tc = ThreadContext.getThreadContext();
+	assert(tc);
+	return tc.Dobject_prototype;
+    }
+
+    static void init(ThreadContext *tc)
+    {
+	tc.Dobject_prototype = new Dobject_prototype(tc);
+	Dfunction.init(tc);
+	tc.Dobject_constructor = new Dobject_constructor(tc);
+
+	Dobject op = tc.Dobject_prototype;
+	Dobject f = tc.Dfunction_prototype;
+
+	op.Put(TEXT_constructor, tc.Dobject_constructor, DontEnum);
+
+	static NativeFunctionData nfd[] =
+	[
+	    {	&TEXT_toString, &Dobject_prototype_toString, 0 },
+	    {	&TEXT_toLocaleString, &Dobject_prototype_toLocaleString, 0 },
+	    {	&TEXT_toSource, &Dobject_prototype_toSource, 0 },
+	    {	&TEXT_valueOf, &Dobject_prototype_valueOf, 0 },
+	    {	&TEXT_hasOwnProperty, &Dobject_prototype_hasOwnProperty, 1 },
+	    {	&TEXT_isPrototypeOf, &Dobject_prototype_isPrototypeOf, 0 },
+	    {	&TEXT_propertyIsEnumerable, &Dobject_prototype_propertyIsEnumerable, 0 },
+	];
+
+	DnativeFunction.init(op, nfd, DontEnum);
+    }
+}
+
+
+/*********************************************
+ * Initialize the built-in's.
+ */
+
+void dobject_init(ThreadContext *tc)
+{
+    //writef("dobject_init(tc = %x)\n", cast(uint)tc);
+    if (tc.Dobject_prototype)
+	return;			// already initialized for this thread
+
+version (none)
+{
+    writef("sizeof(Dobject) = %d\n", sizeof(Dobject));
+    writef("sizeof(PropTable) = %d\n", sizeof(PropTable));
+    writef("offsetof(proptable) = %d\n", offsetof(Dobject, proptable));
+    writef("offsetof(internal_prototype) = %d\n", offsetof(Dobject, internal_prototype));
+    writef("offsetof(classname) = %d\n", offsetof(Dobject, classname));
+    writef("offsetof(value) = %d\n", offsetof(Dobject, value));
+}
+
+    Dobject.init(tc);
+    Dboolean.init(tc);
+    Dstring.init(tc);
+    Dnumber.init(tc);
+    Darray.init(tc);
+    Dmath.init(tc);
+    Ddate.init(tc);
+    Dregexp.init(tc);
+    Derror.init(tc);
+
+    // Call registered initializer for each object type
+    foreach (void function(ThreadContext*) fpinit; ThreadContext.initTable)
+	(*fpinit)(tc);
+}
+
+void dobject_term(ThreadContext *tc)
+{
+    //writef("dobject_term(program = %x)\n", tc.program);
+
+    memset(&tc.program, 0, ThreadContext.sizeof - Thread.sizeof);
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/dmdscript_tango/dregexp.d	Sun Jan 24 12:34:47 2010 +0200
@@ -0,0 +1,723 @@
+
+/* 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.dregexp;
+
+private import std.regexp;
+
+import dmdscript.script;
+import dmdscript.dobject;
+import dmdscript.value;
+import dmdscript.protoerror;
+import dmdscript.text;
+import dmdscript.darray;
+import dmdscript.threadcontext;
+import dmdscript.dfunction;
+import dmdscript.property;
+import dmdscript.errmsgs;
+import dmdscript.dnative;
+
+//alias script.tchar tchar;
+
+// Values for Dregexp.exec.rettype
+enum { EXEC_STRING, EXEC_ARRAY, EXEC_BOOLEAN, EXEC_INDEX };
+
+
+/* ===================== Dregexp_constructor ==================== */
+
+class Dregexp_constructor : Dfunction
+{
+    Value* input;
+    Value* multiline;
+    Value* lastMatch;
+    Value* lastParen;
+    Value* leftContext;
+    Value* rightContext;
+    Value* dollar[10];
+
+    // Extensions
+    Value* index;
+    Value* lastIndex;
+
+    this(ThreadContext *tc)
+    {
+	super(2, tc.Dfunction_prototype);
+
+	Value v;
+	v.putVstring(null);
+
+	Value vb;
+	vb.putVboolean(false);
+
+	Value vnm1;
+	vnm1.putVnumber(-1);
+
+	name = "RegExp";
+
+	// Static properties
+	Put(TEXT_input, &v, DontDelete);
+	Put(TEXT_multiline, &vb, DontDelete);
+	Put(TEXT_lastMatch, &v, ReadOnly | DontDelete);
+	Put(TEXT_lastParen, &v, ReadOnly | DontDelete);
+	Put(TEXT_leftContext, &v, ReadOnly | DontDelete);
+	Put(TEXT_rightContext, &v, ReadOnly | DontDelete);
+	Put(TEXT_dollar1, &v, ReadOnly | DontDelete);
+	Put(TEXT_dollar2, &v, ReadOnly | DontDelete);
+	Put(TEXT_dollar3, &v, ReadOnly | DontDelete);
+	Put(TEXT_dollar4, &v, ReadOnly | DontDelete);
+	Put(TEXT_dollar5, &v, ReadOnly | DontDelete);
+	Put(TEXT_dollar6, &v, ReadOnly | DontDelete);
+	Put(TEXT_dollar7, &v, ReadOnly | DontDelete);
+	Put(TEXT_dollar8, &v, ReadOnly | DontDelete);
+	Put(TEXT_dollar9, &v, ReadOnly | DontDelete);
+
+	Put(TEXT_index, &vnm1, ReadOnly | DontDelete);
+	Put(TEXT_lastIndex, &vnm1, ReadOnly | DontDelete);
+
+	input = Get(TEXT_input);
+	multiline = Get(TEXT_multiline);
+	lastMatch = Get(TEXT_lastMatch);
+	lastParen = Get(TEXT_lastParen);
+	leftContext = Get(TEXT_leftContext);
+	rightContext = Get(TEXT_rightContext);
+	dollar[0] = lastMatch;
+	dollar[1] = Get(TEXT_dollar1);
+	dollar[2] = Get(TEXT_dollar2);
+	dollar[3] = Get(TEXT_dollar3);
+	dollar[4] = Get(TEXT_dollar4);
+	dollar[5] = Get(TEXT_dollar5);
+	dollar[6] = Get(TEXT_dollar6);
+	dollar[7] = Get(TEXT_dollar7);
+	dollar[8] = Get(TEXT_dollar8);
+	dollar[9] = Get(TEXT_dollar9);
+
+	index = Get(TEXT_index);
+	lastIndex = Get(TEXT_lastIndex);
+
+	// Should lastMatch be an alias for dollar[nparens],
+	// or should it be a separate property?
+	// We implemented it the latter way.
+	// Since both are ReadOnly, I can't see that it makes
+	// any difference.
+    }
+
+    void* Construct(CallContext *cc, Value *ret, Value[] arglist)
+    {
+	// ECMA 262 v3 15.10.4.1
+
+	Value* pattern;
+	Value* flags;
+	d_string P;
+	d_string F;
+	Dregexp r;
+	Dregexp R;
+
+	//writef("Dregexp_constructor.Construct()\n");
+	ret.putVundefined();
+	pattern = &vundefined;
+	flags = &vundefined;
+	switch (arglist.length)
+	{
+	    case 0:
+		break;
+
+	    default:
+		flags = &arglist[1];
+	    case 1:
+		pattern = &arglist[0];
+		break;
+	}
+	R = Dregexp.isRegExp(pattern);
+	if (R)
+	{
+	    if (flags.isUndefined())
+	    {
+		P = R.re.pattern;
+		F = R.re.flags;
+	    }
+	    else
+	    {
+		ErrInfo errinfo;
+		return RuntimeError(&errinfo, ERR_TYPE_ERROR,
+			"RegExp.prototype.constructor");
+	    }
+	}
+	else
+	{
+	    P = pattern.isUndefined() ? "" : pattern.toString();
+	    F = flags.isUndefined() ? "" : flags.toString();
+	}
+	r = new Dregexp(P, F);
+	if (r.re.errors)
+	{   Dobject o;
+	    ErrInfo errinfo;
+
+	    version (none)
+	    {
+		writef("P = '%s'\nF = '%s'\n", d_string_ptr(P), d_string_ptr(F));
+		for (int i = 0; i < d_string_len(P); i++)
+		    writef("x%02x\n", d_string_ptr(P)[i]);
+	    }
+	    errinfo.message = errmsgtbl[ERR_REGEXP_COMPILE];
+	    o = new syntaxerror.D0(&errinfo);
+	    Value* v = new Value;
+	    v.putVobject(o);
+	    return v;
+	}
+	else
+	{
+	    ret.putVobject(r);
+	    return null;
+	}
+    }
+
+    void* Call(CallContext *cc, Dobject othis, Value* ret, Value[] arglist)
+    {
+	// ECMA 262 v3 15.10.3.1
+	if (arglist.length >= 1)
+	{   Value* pattern;
+	    Dobject o;
+
+	    pattern = &arglist[0];
+	    if (!pattern.isPrimitive())
+	    {
+		o = pattern.object;
+		if (o.isDregexp() &&
+		    (arglist.length == 1 || arglist[1].isUndefined())
+		   )
+		{   ret.putVobject(o);
+		    return null;
+		}
+	    }
+	}
+	return Construct(cc, ret, arglist);
+    }
+
+
+    Value* Get(d_string PropertyName)
+    {
+	return Dfunction.Get(perlAlias(PropertyName));
+    }
+
+    Value* Put(d_string PropertyName, Value* value, uint attributes)
+    {
+	return Dfunction.Put(perlAlias(PropertyName), value, attributes);
+    }
+
+    Value* Put(d_string PropertyName, Dobject o, uint attributes)
+    {
+	return Dfunction.Put(perlAlias(PropertyName), o, attributes);
+    }
+
+    Value* Put(d_string PropertyName, d_number n, uint attributes)
+    {
+	return Dfunction.Put(perlAlias(PropertyName), n, attributes);
+    }
+
+    int CanPut(d_string PropertyName)
+    {
+	return Dfunction.CanPut(perlAlias(PropertyName));
+    }
+
+    int HasProperty(d_string PropertyName)
+    {
+	return Dfunction.HasProperty(perlAlias(PropertyName));
+    }
+
+    int Delete(d_string PropertyName)
+    {
+	return Dfunction.Delete(perlAlias(PropertyName));
+    }
+
+    // Translate Perl property names to script property names
+    static d_string perlAlias(d_string s)
+    {
+	d_string t;
+
+	static tchar[6] from = "_*&+`'";
+	static d_string*[] to =
+	[
+	    &TEXT_input,
+	    &TEXT_multiline,
+	    &TEXT_lastMatch,
+	    &TEXT_lastParen,
+	    &TEXT_leftContext,
+	    &TEXT_rightContext,
+	];
+
+	t = s;
+	if (s.length == 2 && s[0] == '$')
+	{   int i;
+
+	    i = std.string.find(from, s[1]);
+	    if (i >= 0)
+		t = *to[i];
+	}
+	return t;
+    }
+}
+
+
+/* ===================== Dregexp_prototype_toString =============== */
+
+void* Dregexp_prototype_toString(Dobject pthis, CallContext *cc, Dobject othis, Value *ret, Value[] arglist)
+{
+    // othis must be a RegExp
+    Dregexp r;
+
+    if (!othis.isDregexp())
+    {
+	ret.putVundefined();
+	ErrInfo errinfo;
+	return Dobject.RuntimeError(&errinfo, ERR_NOT_TRANSFERRABLE,
+		"RegExp.prototype.toString()");
+    }
+    else
+    {
+	d_string s;
+
+	r = cast(Dregexp)(othis);
+	s = "/";
+	s ~= r.re.pattern;
+	s ~= "/";
+	s ~= r.re.flags;
+	ret.putVstring(s);
+    }
+    return null;
+}
+
+/* ===================== Dregexp_prototype_test =============== */
+
+void* Dregexp_prototype_test(Dobject pthis, CallContext *cc, Dobject othis, Value *ret, Value[] arglist)
+{
+    // ECMA v3 15.10.6.3 says this is equivalent to:
+    //	RegExp.prototype.exec(string) != null
+    return Dregexp.exec(othis, ret, arglist, EXEC_BOOLEAN);
+}
+
+/* ===================== Dregexp_prototype_exec ============= */
+
+void* Dregexp_prototype_exec(Dobject pthis, CallContext *cc, Dobject othis, Value *ret, Value[] arglist)
+{
+    return Dregexp.exec(othis, ret, arglist, EXEC_ARRAY);
+}
+
+
+/* ===================== Dregexp_prototype_compile ============= */
+
+void* Dregexp_prototype_compile(Dobject pthis, CallContext *cc, Dobject othis, Value *ret, Value[] arglist)
+{
+    // RegExp.prototype.compile(pattern, attributes)
+
+    // othis must be a RegExp
+    if (!othis.isClass(TEXT_RegExp))
+    {
+	ErrInfo errinfo;
+	ret.putVundefined();
+	return Dobject.RuntimeError(&errinfo, ERR_NOT_TRANSFERRABLE,
+		"RegExp.prototype.compile()");
+    }
+    else
+    {
+	d_string pattern;
+	d_string attributes;
+	Dregexp dr;
+	RegExp r;
+
+	dr = cast(Dregexp)othis;
+	switch (arglist.length)
+	{
+	    case 0:
+		break;
+
+	    default:
+		attributes = arglist[1].toString();
+	    case 1:
+		pattern = arglist[0].toString();
+		break;
+	}
+
+	r = dr.re;
+	try
+	{
+	    r.compile(pattern, attributes);
+	}
+	catch (RegExpException e)
+	{
+	    // Affect source, global and ignoreCase properties
+	    dr.source.putVstring(r.pattern);
+	    dr.global.putVboolean((r.attributes & RegExp.REA.global) != 0);
+	    dr.ignoreCase.putVboolean((r.attributes & RegExp.REA.ignoreCase) != 0);
+	}
+	//writef("r.attributes = x%x\n", r.attributes);
+    }
+    // Documentation says nothing about a return value,
+    // so let's use "undefined"
+    ret.putVundefined();
+    return null;
+}
+
+/* ===================== Dregexp_prototype ==================== */
+
+class Dregexp_prototype : Dregexp
+{
+    this(ThreadContext *tc)
+    {
+	super(tc.Dobject_prototype);
+	classname = TEXT_Object;
+	uint attributes = ReadOnly | DontDelete | DontEnum;
+	Dobject f = tc.Dfunction_prototype;
+
+	Put(TEXT_constructor, tc.Dregexp_constructor, attributes);
+
+	static NativeFunctionData nfd[] =
+	[
+	    {	&TEXT_toString, &Dregexp_prototype_toString, 0 },
+	    {	&TEXT_compile, &Dregexp_prototype_compile, 2 },
+	    {	&TEXT_exec, &Dregexp_prototype_exec, 1 },
+	    {	&TEXT_test, &Dregexp_prototype_test, 1 },
+	];
+
+	DnativeFunction.init(this, nfd, attributes);
+    }
+}
+
+
+/* ===================== Dregexp ==================== */
+
+
+class Dregexp : Dobject
+{
+    Value *global;
+    Value *ignoreCase;
+    Value *multiline;
+    Value *lastIndex;
+    Value *source;
+
+    RegExp re;
+
+    void *Call(CallContext *cc, Dobject othis, Value* ret, Value[] arglist);
+
+    this(d_string pattern, d_string attributes)
+    {
+	super(getPrototype());
+
+	Value v;
+	v.putVstring(null);
+
+	Value vb;
+	vb.putVboolean(false);
+
+	classname = TEXT_RegExp;
+
+	//writef("Dregexp.Dregexp(pattern = '%ls', attributes = '%ls')\n", d_string_ptr(pattern), d_string_ptr(attributes));
+	Put(TEXT_source, &v, ReadOnly | DontDelete | DontEnum);
+	Put(TEXT_global, &vb, ReadOnly | DontDelete | DontEnum);
+	Put(TEXT_ignoreCase, &vb, ReadOnly | DontDelete | DontEnum);
+	Put(TEXT_multiline, &vb, ReadOnly | DontDelete | DontEnum);
+	Put(TEXT_lastIndex, 0.0, DontDelete | DontEnum);
+
+	source = Get(TEXT_source);
+	global = Get(TEXT_global);
+	ignoreCase = Get(TEXT_ignoreCase);
+	multiline = Get(TEXT_multiline);
+	lastIndex = Get(TEXT_lastIndex);
+
+	re = new RegExp(pattern, attributes);
+	if (re.errors == 0)
+	{
+	    source.putVstring(pattern);
+	    //writef("source = '%s'\n", source.x.string.toDchars());
+	    global.putVboolean((re.attributes & RegExp.REA.global) != 0);
+	    ignoreCase.putVboolean((re.attributes & RegExp.REA.ignoreCase) != 0);
+	    multiline.putVboolean((re.attributes & RegExp.REA.multiline) != 0);
+	}
+	else
+	{
+	    // have caller throw SyntaxError
+	}
+    }
+
+    this(Dobject prototype)
+    {
+	super(prototype);
+
+	Value v;
+	v.putVstring(null);
+
+	Value vb;
+	vb.putVboolean(false);
+
+	classname = TEXT_RegExp;
+
+	Put(TEXT_source, &v, ReadOnly | DontDelete | DontEnum);
+	Put(TEXT_global, &vb, ReadOnly | DontDelete | DontEnum);
+	Put(TEXT_ignoreCase, &vb, ReadOnly | DontDelete | DontEnum);
+	Put(TEXT_multiline, &vb, ReadOnly | DontDelete | DontEnum);
+	Put(TEXT_lastIndex, 0.0, DontDelete | DontEnum);
+
+	source = Get(TEXT_source);
+	global = Get(TEXT_global);
+	ignoreCase = Get(TEXT_ignoreCase);
+	multiline = Get(TEXT_multiline);
+	lastIndex = Get(TEXT_lastIndex);
+
+	re = new RegExp(null, null);
+    }
+
+    void* Call(CallContext *cc, Dobject othis, Value* ret, Value[] arglist)
+    {
+	// This is the same as calling RegExp.prototype.exec(str)
+	Value* v;
+
+	v = Get(TEXT_exec);
+	return v.toObject().Call(cc, this, ret, arglist);
+    }
+
+    static Dregexp isRegExp(Value* v)
+    {
+	Dregexp r;
+
+	if (!v.isPrimitive() && v.toObject().isDregexp())
+	{
+	    r = cast(Dregexp)(v.toObject());
+	}
+	return r;
+    }
+
+    static void* exec(Dobject othis, Value* ret, Value[] arglist, int rettype)
+    {
+	//writef("Dregexp.exec(arglist.length = %d, rettype = %d)\n", arglist.length, rettype);
+
+	// othis must be a RegExp
+	if (!othis.isClass(TEXT_RegExp))
+	{
+	    ret.putVundefined();
+	    ErrInfo errinfo;
+	    return RuntimeError(&errinfo, ERR_NOT_TRANSFERRABLE,
+		    "RegExp.prototype.exec()");
+	}
+	else
+	{
+	    d_string s;
+	    Dregexp dr;
+	    RegExp r;
+	    Dregexp_constructor dc;
+	    uint i;
+	    d_int32 lasti;
+
+	    if (arglist.length)
+		s = arglist[0].toString();
+	    else
+	    {   Dfunction df;
+
+		df = Dregexp.getConstructor();
+		s = (cast(Dregexp_constructor)df).input.string;
+	    }
+
+	    dr = cast(Dregexp)othis;
+	    r = dr.re;
+	    dc = cast(Dregexp_constructor)Dregexp.getConstructor();
+
+	    // Decide if we are multiline
+	    if (dr.multiline.dbool)
+		r.attributes |= RegExp.REA.multiline;
+	    else
+		r.attributes &= ~RegExp.REA.multiline;
+
+	    if (r.attributes & RegExp.REA.global && rettype != EXEC_INDEX)
+		lasti = cast(int)dr.lastIndex.toInteger();
+	    else
+		lasti = 0;
+
+	    if (r.test(s, lasti))
+	    {   // Successful match
+		Value* lastv;
+		uint nmatches;
+
+		if (r.attributes & RegExp.REA.global && rettype != EXEC_INDEX)
+		{
+		    dr.lastIndex.putVnumber(r.pmatch[0].rm_eo);
+		}
+
+		dc.input.putVstring(r.input);
+
+		s = r.input[r.pmatch[0].rm_so .. r.pmatch[0].rm_eo];
+		dc.lastMatch.putVstring(s);
+
+		s = r.input[0 .. r.pmatch[0].rm_so];
+		dc.leftContext.putVstring(s);
+
+		s = r.input[r.pmatch[0].rm_eo .. length];
+		dc.rightContext.putVstring(s);
+
+		dc.index.putVnumber(r.pmatch[0].rm_so);
+		dc.lastIndex.putVnumber(r.pmatch[0].rm_eo);
+
+		// Fill in $1..$9
+		lastv = &vundefined;
+		nmatches = 0;
+		for (i = 1; i <= 9; i++)
+		{
+		    if (i <= r.re_nsub)
+		    {   int n;
+
+			// Use last 9 entries for $1..$9
+			n = i;
+			if (r.re_nsub > 9)
+			    n += (r.re_nsub - 9);
+
+			if (r.pmatch[n].rm_so != -1)
+			{   s = r.input[r.pmatch[n].rm_so .. r.pmatch[n].rm_eo];
+			    dc.dollar[i].putVstring(s);
+			    nmatches = i;
+			}
+			else
+			    dc.dollar[i].putVundefined();
+			lastv = dc.dollar[i];
+		    }
+		    else
+			dc.dollar[i].putVundefined();
+		}
+		// Last substring in $1..$9, or "" if none
+		if (r.re_nsub)
+		    Value.copy(dc.lastParen, lastv);
+		else
+		    dc.lastParen.putVstring(null);
+
+		switch (rettype)
+		{
+		    case EXEC_ARRAY:
+		    {
+			Darray a = new Darray();
+
+			a.Put(TEXT_input, r.input, 0);
+			a.Put(TEXT_index, r.pmatch[0].rm_so, 0);
+			a.Put(TEXT_lastIndex, r.pmatch[0].rm_eo, 0);
+
+			a.Put(cast(d_uint32)0, dc.lastMatch, cast(uint)0);
+
+			// [1]..[nparens]
+			for (i = 1; i <= r.re_nsub; i++)
+			{
+			    if (i > nmatches)
+				a.Put(i, TEXT_, 0);
+
+			    // Reuse values already put into dc.dollar[]
+			    else if (r.re_nsub <= 9)
+				a.Put(i, dc.dollar[i], 0);
+			    else if (i > r.re_nsub - 9)
+				a.Put(i, dc.dollar[i - (r.re_nsub - 9)], 0);
+			    else if (r.pmatch[i].rm_so == -1)
+			    {
+				a.Put(i, &vundefined, 0);
+			    }
+			    else
+			    {
+				s = r.input[r.pmatch[i].rm_so .. r.pmatch[i].rm_eo];
+				a.Put(i, s, 0);
+			    }
+			}
+			ret.putVobject(a);
+			break;
+		    }
+		    case EXEC_STRING:
+			Value.copy(ret, dc.lastMatch);
+			break;
+
+		    case EXEC_BOOLEAN:
+			ret.putVboolean(true);	// success
+			break;
+
+		    case EXEC_INDEX:
+			ret.putVnumber(r.pmatch[0].rm_so);
+			break;
+
+		    default:
+			assert(0);
+		}
+	    }
+	    else	// failed to match
+	    {
+		//writef("failed\n");
+		switch (rettype)
+		{
+		    case EXEC_ARRAY:
+			//writef("memcpy\n");
+			ret.putVnull();	    // Return null
+			dr.lastIndex.putVnumber(0);
+			break;
+
+		    case EXEC_STRING:
+			ret.putVstring(null);
+			dr.lastIndex.putVnumber(0);
+			break;
+
+		    case EXEC_BOOLEAN:
+			ret.putVboolean(false);
+			dr.lastIndex.putVnumber(0);
+			break;
+
+		    case EXEC_INDEX:
+			ret.putVnumber(-1.0);
+			// Do not set lastIndex
+			break;
+
+		    default:
+			assert(0);
+		}
+	    }
+	}
+	return null;
+    }
+
+    static Dfunction getConstructor()
+    {
+	ThreadContext *tc = ThreadContext.getThreadContext();
+	assert(tc);
+	return tc.Dregexp_constructor;
+    }
+
+    static Dobject getPrototype()
+    {
+	ThreadContext* tc = ThreadContext.getThreadContext();
+	assert(tc);
+	return tc.Dregexp_prototype;
+    }
+
+    static void init(ThreadContext *tc)
+    {
+	tc.Dregexp_constructor = new Dregexp_constructor(tc);
+	tc.Dregexp_prototype = new Dregexp_prototype(tc);
+
+	version (none)
+	{
+	    writef("tc.Dregexp_constructor = %x\n", tc.Dregexp_constructor);
+	    uint *p;
+	    p = cast(uint *)tc.Dregexp_constructor;
+	    writef("p = %x\n", p);
+	    if (p)
+		writef("*p = %x, %x, %x, %x\n", p[0], p[1], p[2], p[3]);
+	}
+
+	tc.Dregexp_constructor.Put(TEXT_prototype, tc.Dregexp_prototype, DontEnum | DontDelete | ReadOnly);
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/dmdscript_tango/dstring.d	Sun Jan 24 12:34:47 2010 +0200
@@ -0,0 +1,1217 @@
+
+/* Digital Mars DMDScript source code.
+ * Copyright (c) 2000-2002 by Chromium Communications
+ * D version Copyright (c) 2004-2006 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.dstring;
+
+import std.regexp;
+import std.utf;
+import std.c.stdlib;
+import std.c.string;
+
+import dmdscript.script;
+import dmdscript.dobject;
+import dmdscript.dregexp;
+import dmdscript.darray;
+import dmdscript.value;
+import dmdscript.threadcontext;
+import dmdscript.dfunction;
+import dmdscript.text;
+import dmdscript.property;
+import dmdscript.errmsgs;
+import dmdscript.dnative;
+
+//alias script.tchar tchar;
+
+/* ===================== Dstring_fromCharCode ==================== */
+
+void* Dstring_fromCharCode(Dobject pthis, CallContext *cc, Dobject othis, Value *ret, Value[] arglist)
+{
+    // ECMA 15.5.3.2
+    d_string s;
+
+    for (size_t i = 0; i < arglist.length; i++)
+    {	Value* v;
+	uint u;
+
+	v = &arglist[i];
+	u = v.toUint16();
+	//writefln("string.fromCharCode(%x)", u);
+	if (!std.utf.isValidDchar(u))
+	{
+	    ErrInfo errinfo;
+
+	    ret.putVundefined();
+	    return pthis.RuntimeError(&errinfo,
+		    errmsgtbl[ERR_NOT_VALID_UTF],
+		    "String", "fromCharCode()",
+		    u);
+	}
+	std.utf.encode(s, u);
+	//writefln("s[0] = %x, s = '%s'", s[0], s);
+    }
+    ret.putVstring(s);
+    return null;
+}
+
+/* ===================== Dstring_constructor ==================== */
+
+class Dstring_constructor : Dfunction
+{
+    this(ThreadContext *tc)
+    {
+	super(1, tc.Dfunction_prototype);
+	name = "String";
+
+	static NativeFunctionData nfd[] =
+	[
+	    {	&TEXT_fromCharCode, &Dstring_fromCharCode, 1 },
+	];
+
+	DnativeFunction.init(this, nfd, 0);
+    }
+
+    void *Construct(CallContext *cc, Value *ret, Value[] arglist)
+    {
+	// ECMA 15.5.2
+	d_string s;
+	Dobject o;
+
+	s = (arglist.length) ? arglist[0].toString() : TEXT_;
+	o = new Dstring(s);
+	ret.putVobject(o);
+	return null;
+    }
+
+    void *Call(CallContext *cc, Dobject othis, Value* ret, Value[] arglist)
+    {
+	// ECMA 15.5.1
+	d_string s;
+
+	s = (arglist.length) ? arglist[0].toString() : TEXT_;
+	ret.putVstring(s);
+	return null;
+    }
+}
+
+
+/* ===================== Dstring_prototype_toString =============== */
+
+void* Dstring_prototype_toString(Dobject pthis, CallContext *cc, Dobject othis, Value *ret, Value[] arglist)
+{
+    //writef("Dstring.prototype.toString()\n");
+    // othis must be a String
+    if (!othis.isClass(TEXT_String))
+    {
+	ErrInfo errinfo;
+
+	ret.putVundefined();
+	return pthis.RuntimeError(&errinfo,
+		errmsgtbl[ERR_FUNCTION_WANTS_STRING],
+		TEXT_toString,
+		othis.classname);
+    }
+    else
+    {	Value *v;
+
+	v = &(cast(Dstring)othis).value;
+	Value.copy(ret, v);
+    }
+    return null;
+}
+
+/* ===================== Dstring_prototype_valueOf =============== */
+
+void* Dstring_prototype_valueOf(Dobject pthis, CallContext *cc, Dobject othis, Value *ret, Value[] arglist)
+{
+    // Does same thing as String.prototype.toString()
+
+    //writef("string.prototype.valueOf()\n");
+    // othis must be a String
+    if (!othis.isClass(TEXT_String))
+    {
+	ErrInfo errinfo;
+
+	ret.putVundefined();
+	return pthis.RuntimeError(&errinfo,
+		errmsgtbl[ERR_FUNCTION_WANTS_STRING],
+		TEXT_valueOf,
+		othis.classname);
+    }
+    else
+    {	Value *v;
+
+	v = &(cast(Dstring)othis).value;
+	Value.copy(ret, v);
+    }
+    return null;
+}
+
+/* ===================== Dstring_prototype_charAt =============== */
+
+void* Dstring_prototype_charAt(Dobject pthis, CallContext *cc, Dobject othis, Value *ret, Value[] arglist)
+{
+    // ECMA 15.5.4.4
+
+    Value *v;
+    int pos;		// ECMA says pos should be a d_number,
+			// but int should behave the same
+    d_string s;
+    d_string result;
+
+    v = &othis.value;
+    s = v.toString();
+    v = arglist.length ? &arglist[0] : &vundefined;
+    pos = cast(int) v.toInteger();
+
+    result = TEXT_;
+
+    if (pos >= 0)
+    {	size_t idx;
+
+	while (1)
+	{
+	    if (idx == s.length)
+		break;
+	    if (pos == 0)
+	    {
+		result = s[idx .. idx + std.utf.stride(s, idx)];
+		break;
+	    }
+	    idx += std.utf.stride(s, idx);
+	    pos--;
+	}
+    }
+
+    ret.putVstring(result);
+    return null;
+}
+
+/* ===================== Dstring_prototype_charCodeAt ============= */
+
+void* Dstring_prototype_charCodeAt(Dobject pthis, CallContext *cc, Dobject othis, Value *ret, Value[] arglist)
+{
+    // ECMA 15.5.4.5
+
+    Value *v;
+    int pos;		// ECMA says pos should be a d_number,
+			// but int should behave the same
+    d_string s;
+    uint len;
+    d_number result;
+
+    v = &othis.value;
+    s = v.toString();
+    v = arglist.length ? &arglist[0] : &vundefined;
+    pos = cast(int) v.toInteger();
+
+    result = d_number.nan;
+
+    if (pos >= 0)
+    {	size_t idx;
+
+	while (1)
+	{
+	    assert(idx <= s.length);
+	    if (idx == s.length)
+		break;
+	    if (pos == 0)
+	    {
+		result = std.utf.decode(s, idx);
+		break;
+	    }
+	    idx += std.utf.stride(s, idx);
+	    pos--;
+	}
+    }
+
+    ret.putVnumber(result);
+    return null;
+}
+
+/* ===================== Dstring_prototype_concat ============= */
+
+void* Dstring_prototype_concat(Dobject pthis, CallContext *cc, Dobject othis, Value *ret, Value[] arglist)
+{
+    // ECMA v3 15.5.4.6
+    d_string s;
+
+    //writefln("Dstring.prototype.concat()");
+
+    s = othis.value.toString();
+    for (size_t a = 0; a < arglist.length; a++)
+	s ~= arglist[a].toString();
+
+    ret.putVstring(s);
+    return null;
+}
+
+/* ===================== Dstring_prototype_indexOf ============= */
+
+void* Dstring_prototype_indexOf(Dobject pthis, CallContext *cc, Dobject othis, Value *ret, Value[] arglist)
+{
+    // ECMA 15.5.4.6
+    // String.prototype.indexOf(searchString, position)
+
+    Value* v1;
+    Value* v2;
+    int pos;		// ECMA says pos should be a d_number,
+			// but I can't find a reason.
+    d_string s;
+    size_t sUCSdim;
+
+    d_string searchString;
+    int k;
+
+    Value xx;
+    xx.putVobject(othis);
+    s = xx.toString();
+    sUCSdim = std.utf.toUCSindex(s, s.length);
+
+    v1 = arglist.length ? &arglist[0] : &vundefined;
+    v2 = (arglist.length >= 2) ? &arglist[1] : &vundefined;
+
+    searchString = v1.toString();
+    pos = cast(int) v2.toInteger();
+
+    if (pos < 0)
+	pos = 0;
+    else if (pos > sUCSdim)
+	pos = sUCSdim;
+
+    if (searchString.length == 0)
+	k = pos;
+    else
+    {	pos = std.utf.toUTFindex(s, pos);
+	k = std.string.find(s[pos .. length], searchString);
+	if (k != -1)
+	    k = std.utf.toUCSindex(s, pos + k);
+    }
+
+    ret.putVnumber(k);
+    return null;
+}
+
+/* ===================== Dstring_prototype_lastIndexOf ============= */
+
+void* Dstring_prototype_lastIndexOf(Dobject pthis, CallContext *cc, Dobject othis, Value *ret, Value[] arglist)
+{
+    // ECMA v3 15.5.4.8
+    // String.prototype.lastIndexOf(searchString, position)
+
+    Value *v1;
+    int pos;		// ECMA says pos should be a d_number,
+			// but I can't find a reason.
+    d_string s;
+    size_t sUCSdim;
+    d_string searchString;
+    int k;
+
+version (all)
+{
+    {
+    // This is the 'transferable' version
+    Value *v;
+    void *a;
+    v = othis.Get(TEXT_toString);
+    a = v.Call(cc, othis, ret, null);
+    if (a)				// if exception was thrown
+	return a;
+    s = ret.toString();
+    }
+}
+else
+{
+    // the 'builtin' version
+    s = othis.value.toString();
+}
+    sUCSdim = std.utf.toUCSindex(s, s.length);
+
+    v1 = arglist.length ? &arglist[0] : &vundefined;
+    searchString = v1.toString();
+    if (arglist.length >= 2)
+    {	d_number n;
+	Value *v = &arglist[1];
+
+	n = v.toNumber();
+	if (std.math.isnan(n) || n > sUCSdim)
+	    pos = sUCSdim;
+	else if (n < 0)
+	    pos = 0;
+	else
+	    pos = cast(int) n;
+    }
+    else
+	pos = sUCSdim;
+
+    //writef("len = %d, p = '%ls'\n", len, p);
+    //writef("pos = %d, sslen = %d, ssptr = '%ls'\n", pos, sslen, ssptr);
+    //writefln("s = '%s', pos = %s, searchString = '%s'", s, pos, searchString);
+
+    if (searchString.length == 0)
+	k = pos;
+    else
+    {
+	pos = std.utf.toUTFindex(s, pos);
+	pos += searchString.length;
+	if (pos > s.length)
+	    pos = s.length;
+	k = std.string.rfind(s[0 .. pos], searchString);
+	//writefln("s = '%s', pos = %s, searchString = '%s', k = %d", s, pos, searchString, k);
+	if (k != -1)
+	    k = std.utf.toUCSindex(s, k);
+    }
+    ret.putVnumber(k);
+    return null;
+}
+
+/* ===================== Dstring_prototype_localeCompare ============= */
+
+void* Dstring_prototype_localeCompare(Dobject pthis, CallContext *cc, Dobject othis, Value *ret, Value[] arglist)
+{
+    // ECMA v3 15.5.4.9
+    d_string s1;
+    d_string s2;
+    d_number n;
+    Value *v;
+
+    v = &othis.value;
+    s1 = v.toString();
+    s2 = arglist.length ? arglist[0].toString() : vundefined.toString();
+    n = localeCompare(cc, s1, s2);
+    ret.putVnumber(n);
+    return null;
+}
+
+/* ===================== Dstring_prototype_match ============= */
+
+void* Dstring_prototype_match(Dobject pthis, CallContext *cc, Dobject othis, Value *ret, Value[] arglist)
+{
+    // ECMA v3 15.5.4.10
+    Dregexp r;
+    Dobject o;
+
+    if (arglist.length && !arglist[0].isPrimitive() &&
+	(o = arglist[0].toObject()).isDregexp())
+    {
+	;
+    }
+    else
+    {
+	Value regret;
+
+	regret.putVobject(null);
+	Dregexp.getConstructor().Construct(cc, &regret, arglist);
+	o = regret.object;
+    }
+
+    r = cast(Dregexp)o;
+    if (r.global.dbool)
+    {
+	Darray a = new Darray;
+	d_int32 n;
+	d_int32 i;
+	d_int32 lasti;
+
+	i = 0;
+	lasti = 0;
+	for (n = 0; ; n++)
+	{
+	    r.lastIndex.putVnumber(i);
+	    Dregexp.exec(r, ret, (&othis.value)[0 .. 1], EXEC_STRING);
+	    if (!ret.string)		// if match failed
+	    {
+		r.lastIndex.putVnumber(i);
+		break;
+	    }
+	    lasti = i;
+	    i = cast(d_int32) r.lastIndex.toInt32();
+	    if (i == lasti)		// if no source was consumed
+		i++;			// consume a character
+
+	    a.Put(n, ret, 0);		// a[n] = ret;
+	}
+	ret.putVobject(a);
+    }
+    else
+    {
+	Dregexp.exec(r, ret, (&othis.value)[0 .. 1], EXEC_ARRAY);
+    }
+    return null;
+}
+
+/* ===================== Dstring_prototype_replace ============= */
+
+void* Dstring_prototype_replace(Dobject pthis, CallContext *cc, Dobject othis, Value *ret, Value[] arglist)
+{
+    // ECMA v3 15.5.4.11
+    // String.prototype.replace(searchValue, replaceValue)
+
+    d_string string;
+    d_string searchString;
+    d_string newstring;
+    Value *searchValue;
+    Value *replaceValue;
+    Dregexp r;
+    RegExp re;
+    tchar[] replacement;
+    d_string result;
+    int m;
+    int i;
+    int lasti;
+    std.regexp.regmatch_t[1] pmatch;
+    Dfunction f;
+    Value* v;
+
+    v = &othis.value;
+    string = v.toString();
+    searchValue  = (arglist.length >= 1) ? &arglist[0] : &vundefined;
+    replaceValue = (arglist.length >= 2) ? &arglist[1] : &vundefined;
+    r = Dregexp.isRegExp(searchValue);
+    f = Dfunction.isFunction(replaceValue);
+    if (r)
+    {	int offset = 0;
+
+	re = r.re;
+	i = 0;
+	result = string;
+
+	r.lastIndex.putVnumber(0);
+	for (;;)
+	{
+	    Dregexp.exec(r, ret, (&othis.value)[0 .. 1], EXEC_STRING);
+	    if (!ret.string)		// if match failed
+		break;
+
+	    m = re.re_nsub;
+	    if (f)
+	    {
+		Value* alist;
+
+		alist = cast(Value *)alloca((m + 3) * Value.sizeof);
+		assert(alist);
+		alist[0].putVstring(ret.string);
+		for (i = 0; i < m; i++)
+		{
+		    alist[1 + i].putVstring(
+			string[re.pmatch[1 + i].rm_so .. re.pmatch[1 + i].rm_eo]);
+		}
+		alist[m + 1].putVnumber(re.pmatch[0].rm_so);
+		alist[m + 2].putVstring(string);
+		f.Call(cc, f, ret, alist[0 .. m + 3]);
+		replacement = ret.toString();
+	    }
+	    else
+	    {
+		newstring = replaceValue.toString();
+		replacement = re.replace(newstring);
+	    }
+	    int starti = re.pmatch[0].rm_so + offset;
+	    int endi   = re.pmatch[0].rm_eo + offset;
+	    result = string[0 .. starti] ~
+		     replacement ~
+		     string[endi .. length];
+
+	    if (re.attributes & RegExp.REA.global)
+	    {
+		offset += replacement.length - (endi - starti);
+
+		// If no source was consumed, consume a character
+		lasti = i;
+		i = cast(d_int32) r.lastIndex.toInt32();
+		if (i == lasti)
+		{   i++;
+		    r.lastIndex.putVnumber(i);
+		}
+	    }
+	    else
+		break;
+	}
+    }
+    else
+    {	int match;
+
+	searchString = searchValue.toString();
+	match = std.string.find(string, searchString);
+	if (match >= 0)
+	{
+	    pmatch[0].rm_so = match;
+	    pmatch[0].rm_eo = match + searchString.length;
+	    if (f)
+	    {
+		Value[3] alist;
+
+		alist[0].putVstring(searchString);
+		alist[1].putVnumber(pmatch[0].rm_so);
+		alist[2].putVstring(string);
+		f.Call(cc, f, ret, alist);
+		replacement = ret.toString();
+	    }
+	    else
+	    {
+		newstring = replaceValue.toString();
+		replacement = RegExp.replace3(newstring, string, pmatch);
+	    }
+	    result = string[0 .. match] ~
+		     replacement ~
+		     string[match + searchString.length .. length];
+	}
+	else
+	{
+	    result = string;
+	}
+    }
+
+    ret.putVstring(result);
+    return null;
+}
+
+/* ===================== Dstring_prototype_search ============= */
+
+void* Dstring_prototype_search(Dobject pthis, CallContext *cc, Dobject othis, Value *ret, Value[] arglist)
+{
+    // ECMA v3 15.5.4.12
+    Dregexp r;
+    Dobject o;
+
+    //writef("String.prototype.search()\n");
+    if (arglist.length && !arglist[0].isPrimitive() &&
+	(o = arglist[0].toObject()).isDregexp())
+    {
+	;
+    }
+    else
+    {	Value regret;
+
+	regret.putVobject(null);
+	Dregexp.getConstructor().Construct(cc, &regret, arglist);
+	o = regret.object;
+    }
+
+    r = cast(Dregexp)o;
+    Dregexp.exec(r, ret, (&othis.value)[0 .. 1], EXEC_INDEX);
+    return null;
+}
+
+/* ===================== Dstring_prototype_slice ============= */
+
+void* Dstring_prototype_slice(Dobject pthis, CallContext *cc, Dobject othis, Value *ret, Value[] arglist)
+{
+    // ECMA v3 15.5.4.13
+    d_int32 start;
+    d_int32 end;
+    d_int32 sUCSdim;
+    d_string s;
+    d_string r;
+    Value *v;
+
+    v = &othis.value;
+    s = v.toString();
+    sUCSdim = std.utf.toUCSindex(s, s.length);
+    switch (arglist.length)
+    {
+	case 0:
+	    start = 0;
+	    end = sUCSdim;
+	    break;
+
+	case 1:
+	    start = arglist[0].toInt32();
+	    end = sUCSdim;
+	    break;
+
+	default:
+	    start = arglist[0].toInt32();
+	    end   = arglist[1].toInt32();
+	    break;
+    }
+
+    if (start < 0)
+    {
+	start += sUCSdim;
+	if (start < 0)
+	    start = 0;
+    }
+    else if (start >= sUCSdim)
+	start = sUCSdim;
+
+    if (end < 0)
+    {
+	end += sUCSdim;
+	if (end < 0)
+	    end = 0;
+    }
+    else if (end >= sUCSdim)
+	end = sUCSdim;
+
+    if (start > end)
+	end = start;
+
+    start = toUTFindex(s, start);
+    end   = toUTFindex(s, end);
+    r = s[start .. end];
+
+    ret.putVstring(r);
+    return null;
+}
+
+
+/* ===================== Dstring_prototype_split ============= */
+
+void* Dstring_prototype_split(Dobject pthis, CallContext *cc, Dobject othis, Value *ret, Value[] arglist)
+{
+    // ECMA v3 15.5.4.14
+    // String.prototype.split(separator, limit)
+    d_uint32 lim;
+    d_uint32 p;
+    d_uint32 q;
+    d_uint32 e;
+    Value* separator = &vundefined;
+    Value* limit = &vundefined;
+    Dregexp R;
+    RegExp re;
+    d_string rs;
+    d_string T;
+    d_string S;
+    Darray A;
+    int str;
+
+    //writefln("Dstring_prototype_split()");
+    switch (arglist.length)
+    {
+	default:
+	    limit = &arglist[1];
+	case 1:
+	    separator = &arglist[0];
+	case 0:
+	    break;
+    }
+
+    Value *v;
+    v = &othis.value;
+    S = v.toString();
+    A = new Darray;
+    if (limit.isUndefined())
+	lim = ~0u;
+    else
+	lim = limit.toUint32();
+    p = 0;
+    R = Dregexp.isRegExp(separator);
+    if (R)	// regular expression
+    {	re = R.re;
+	assert(re);
+	rs = null;
+	str = 0;
+    }
+    else	// string
+    {	re = null;
+	rs = separator.toString();
+	str = 1;
+    }
+    if (lim == 0)
+	goto Lret;
+
+    // ECMA v3 15.5.4.14 is specific: "If separator is undefined, then the
+    // result array contains just one string, which is the this value
+    // (converted to a string)." However, neither Javascript nor Jscript
+    // do that, they regard an undefined as being the string "undefined".
+    // We match Javascript/Jscript behavior here, not ECMA.
+
+    // Uncomment for ECMA compatibility
+    //if (!separator.isUndefined())
+    {
+	//writefln("test1 S = '%s', rs = '%s'", S, rs);
+	if (S.length)
+	{
+	L10:
+	    for (q = p; q != S.length; q++)
+	    {
+		if (str)		// string
+		{
+		    if (q + rs.length <= S.length && !memcmp(S.ptr + q, rs.ptr, rs.length * tchar.sizeof))
+		    {
+			e = q + rs.length;
+			if (e != p)
+			{
+			    T = S[p .. q];
+			    A.Put(cast(uint) A.length.number, T, 0);
+			    if (A.length.number == lim)
+				goto Lret;
+			    p = e;
+			    goto L10;
+			}
+		    }
+		}
+		else		// regular expression
+		{
+		    if (re.test(S, q))
+		    {	q = re.pmatch[0].rm_so;
+			e = re.pmatch[0].rm_eo;
+			if (e != p)
+			{
+			    T = S[p .. q];
+			    //writefln("S = '%s', T = '%s', p = %d, q = %d, e = %d\n", S, T, p, q, e);
+			    A.Put(cast(uint) A.length.number, T, 0);
+			    if (A.length.number == lim)
+				goto Lret;
+			    p = e;
+			    for (uint i = 0; i < re.re_nsub; i++)
+			    {
+				int so = re.pmatch[1 + i].rm_so;
+				int eo = re.pmatch[1 + i].rm_eo;
+
+				//writefln("i = %d, nsub = %s, so = %s, eo = %s, S.length = %s", i, re.re_nsub, so, eo, S.length);
+				if (so != -1 && eo != -1)
+				    T = S[so .. eo];
+				else
+				    T = null;
+				A.Put(cast(uint) A.length.number, T, 0);
+				if (A.length.number == lim)
+				    goto Lret;
+			    }
+			    goto L10;
+			}
+		    }
+		}
+	    }
+	    T = S[p .. S.length];
+	    A.Put(cast(uint) A.length.number, T, 0);
+	    goto Lret;
+	}
+	if (str)		// string
+	{
+	    if (rs.length <= S.length && S[0 .. rs.length] == rs[])
+		goto Lret;
+	}
+	else		// regular expression
+	{
+	    if (re.test(S, 0))
+		goto Lret;
+	}
+    }
+
+    A.Put(0u, S, 0);
+Lret:
+    ret.putVobject(A);
+    return null;
+}
+
+
+/* ===================== Dstring_prototype_substr ============= */
+
+void *dstring_substring(d_string s, size_t sUCSdim, d_number start, d_number end, Value *ret)
+{
+    d_string sb;
+    d_int32 sb_len;
+
+    if (std.math.isnan(start))
+	start = 0;
+    else if (start > sUCSdim)
+	start = sUCSdim;
+    else if (start < 0)
+	start = 0;
+
+    if (std.math.isnan(end))
+	end = 0;
+    else if (end > sUCSdim)
+	end = sUCSdim;
+    else if (end < 0)
+	end = 0;
+
+    if (end < start)		// swap
+    {	d_number t;
+
+	t = start;
+	start = end;
+	end = t;
+    }
+
+    size_t st = std.utf.toUTFindex(s, cast(size_t)start);
+    size_t en = std.utf.toUTFindex(s, cast(size_t)end);
+    sb = s[st .. en];
+
+    ret.putVstring(sb);
+    return null;
+}
+
+void* Dstring_prototype_substr(Dobject pthis, CallContext *cc, Dobject othis, Value *ret, Value[] arglist)
+{
+    // Javascript: TDG pg. 689
+    // String.prototype.substr(start, length)
+    d_number start;
+    d_number length;
+    d_string s;
+
+    s = othis.value.toString();
+    size_t sUCSdim = std.utf.toUCSindex(s, s.length);
+    start = 0;
+    length = 0;
+    if (arglist.length >= 1)
+    {
+	start = arglist[0].toInteger();
+	if (start < 0)
+	    start = sUCSdim + start;
+	if (arglist.length >= 2)
+	{
+	    length = arglist[1].toInteger();
+	    if (std.math.isnan(length) || length < 0)
+		length = 0;
+	}
+	else
+	    length = sUCSdim - start;
+    }
+
+    return dstring_substring(s, sUCSdim, start, start + length, ret);
+}
+
+/* ===================== Dstring_prototype_substring ============= */
+
+void* Dstring_prototype_substring(Dobject pthis, CallContext *cc, Dobject othis, Value *ret, Value[] arglist)
+{
+    // ECMA 15.5.4.9
+    // String.prototype.substring(start)
+    // String.prototype.substring(start, end)
+    d_number start;
+    d_number end;
+    d_string s;
+
+    //writefln("String.prototype.substring()");
+    s = othis.value.toString();
+    size_t sUCSdim = std.utf.toUCSindex(s, s.length);
+    start = 0;
+    end = sUCSdim;
+    if (arglist.length >= 1)
+    {
+	start = arglist[0].toInteger();
+	if (arglist.length >= 2)
+	    end = arglist[1].toInteger();
+	//writef("s = '%ls', start = %d, end = %d\n", s, start, end);
+    }
+
+    void* p = dstring_substring(s, sUCSdim, start, end, ret);
+    return p;
+}
+
+/* ===================== Dstring_prototype_toLowerCase ============= */
+
+enum CASE
+{
+    Lower,
+    Upper,
+    LocaleLower,
+    LocaleUpper
+};
+
+void *tocase(Dobject othis, Value *ret, CASE caseflag)
+{
+    d_string s;
+
+    s = othis.value.toString();
+    switch (caseflag)
+    {
+	case CASE.Lower:
+	    s = std.string.tolower(s);
+	    break;
+	case CASE.Upper:
+	    s = std.string.toupper(s);
+	    break;
+	case CASE.LocaleLower:
+	    s = std.string.tolower(s);
+	    break;
+	case CASE.LocaleUpper:
+	    s = std.string.toupper(s);
+	    break;
+	default:
+	    assert(0);
+    }
+
+    ret.putVstring(s);
+    return null;
+}
+
+void* Dstring_prototype_toLowerCase(Dobject pthis, CallContext *cc, Dobject othis, Value *ret, Value[] arglist)
+{
+    // ECMA 15.5.4.11
+    // String.prototype.toLowerCase()
+
+    //writef("Dstring_prototype_toLowerCase()\n");
+    return tocase(othis, ret, CASE.Lower);
+}
+
+/* ===================== Dstring_prototype_toLocaleLowerCase ============= */
+
+void* Dstring_prototype_toLocaleLowerCase(Dobject pthis, CallContext *cc, Dobject othis, Value *ret, Value[] arglist)
+{
+    // ECMA v3 15.5.4.17
+
+    //writef("Dstring_prototype_toLocaleLowerCase()\n");
+    return tocase(othis, ret, CASE.LocaleLower);
+}
+
+/* ===================== Dstring_prototype_toUpperCase ============= */
+
+void* Dstring_prototype_toUpperCase(Dobject pthis, CallContext *cc, Dobject othis, Value *ret, Value[] arglist)
+{
+    // ECMA 15.5.4.12
+    // String.prototype.toUpperCase()
+
+    return tocase(othis, ret, CASE.Upper);
+}
+
+/* ===================== Dstring_prototype_toLocaleUpperCase ============= */
+
+void* Dstring_prototype_toLocaleUpperCase(Dobject pthis, CallContext *cc, Dobject othis, Value *ret, Value[] arglist)
+{
+    // ECMA v3 15.5.4.18
+
+    return tocase(othis, ret, CASE.LocaleUpper);
+}
+
+/* ===================== Dstring_prototype_anchor ============= */
+
+void *dstring_anchor(Dobject othis, Value* ret, tchar[] tag, tchar[] name, Value[] arglist)
+{
+    // For example:
+    //	"foo".anchor("bar")
+    // produces:
+    //	<tag name="bar">foo</tag>
+
+    d_string foo = othis.value.toString();
+    Value* va = arglist.length ? &arglist[0] : &vundefined;
+    d_string bar = va.toString();
+
+    d_string s;
+
+    s = "<"	~
+	tag	~
+	" "	~
+	name	~
+	"=\""	~
+	bar	~
+	"\">"	~
+	foo	~
+	"</"	~
+	tag	~
+	">";
+
+    ret.putVstring(s);
+    return null;
+}
+
+
+void* Dstring_prototype_anchor(Dobject pthis, CallContext *cc, Dobject othis, Value *ret, Value[] arglist)
+{
+    // Non-standard extension
+    // String.prototype.anchor(anchor)
+    // For example:
+    //	"foo".anchor("bar")
+    // produces:
+    //	<A NAME="bar">foo</A>
+
+    return dstring_anchor(othis, ret, "A", "NAME", arglist);
+}
+
+void* Dstring_prototype_fontcolor(Dobject pthis, CallContext *cc, Dobject othis, Value *ret, Value[] arglist)
+{
+    return dstring_anchor(othis, ret, "FONT", "COLOR", arglist);
+}
+
+void* Dstring_prototype_fontsize(Dobject pthis, CallContext *cc, Dobject othis, Value *ret, Value[] arglist)
+{
+    return dstring_anchor(othis, ret, "FONT", "SIZE", arglist);
+}
+
+void* Dstring_prototype_link(Dobject pthis, CallContext *cc, Dobject othis, Value *ret, Value[] arglist)
+{
+    return dstring_anchor(othis, ret, "A", "HREF", arglist);
+}
+
+
+/* ===================== Dstring_prototype bracketing ============= */
+
+/***************************
+ * Produce <tag>othis</tag>
+ */
+
+void *dstring_bracket(Dobject othis, Value* ret, char[] tag)
+{
+    d_string foo = othis.value.toString();
+    d_string s;
+
+    s = "<"	~
+	tag	~
+	">"	~
+	foo	~
+	"</"	~
+	tag	~
+	">";
+
+    ret.putVstring(s);
+    return null;
+}
+
+void* Dstring_prototype_big(Dobject pthis, CallContext *cc, Dobject othis, Value *ret, Value[] arglist)
+{
+    // Non-standard extension
+    // String.prototype.big()
+    // For example:
+    //	"foo".big()
+    // produces:
+    //	<BIG>foo</BIG>
+
+    return dstring_bracket(othis, ret, "BIG");
+}
+
+void* Dstring_prototype_blink(Dobject pthis, CallContext *cc, Dobject othis, Value *ret, Value[] arglist)
+{
+    return dstring_bracket(othis, ret, "BLINK");
+}
+
+void* Dstring_prototype_bold(Dobject pthis, CallContext *cc, Dobject othis, Value *ret, Value[] arglist)
+{
+    return dstring_bracket(othis, ret, "B");
+}
+
+void* Dstring_prototype_fixed(Dobject pthis, CallContext *cc, Dobject othis, Value *ret, Value[] arglist)
+{
+    return dstring_bracket(othis, ret, "TT");
+}
+
+void* Dstring_prototype_italics(Dobject pthis, CallContext *cc, Dobject othis, Value *ret, Value[] arglist)
+{
+    return dstring_bracket(othis, ret, "I");
+}
+
+void* Dstring_prototype_small(Dobject pthis, CallContext *cc, Dobject othis, Value *ret, Value[] arglist)
+{
+    return dstring_bracket(othis, ret, "SMALL");
+}
+
+void* Dstring_prototype_strike(Dobject pthis, CallContext *cc, Dobject othis, Value *ret, Value[] arglist)
+{
+    return dstring_bracket(othis, ret, "STRIKE");
+}
+
+void* Dstring_prototype_sub(Dobject pthis, CallContext *cc, Dobject othis, Value *ret, Value[] arglist)
+{
+    return dstring_bracket(othis, ret, "SUB");
+}
+
+void* Dstring_prototype_sup(Dobject pthis, CallContext *cc, Dobject othis, Value *ret, Value[] arglist)
+{
+    return dstring_bracket(othis, ret, "SUP");
+}
+
+
+
+/* ===================== Dstring_prototype ==================== */
+
+class Dstring_prototype : Dstring
+{
+    this(ThreadContext *tc)
+    {
+	super(tc.Dobject_prototype);
+
+	Put(TEXT_constructor, tc.Dstring_constructor, DontEnum);
+
+	static NativeFunctionData nfd[] =
+	[
+	    {   &TEXT_toString, &Dstring_prototype_toString, 0 },
+	    {   &TEXT_valueOf, &Dstring_prototype_valueOf, 0 },
+	    {   &TEXT_charAt, &Dstring_prototype_charAt, 1 },
+	    {   &TEXT_charCodeAt, &Dstring_prototype_charCodeAt, 1 },
+	    {   &TEXT_concat, &Dstring_prototype_concat, 1 },
+	    {   &TEXT_indexOf, &Dstring_prototype_indexOf, 1 },
+	    {   &TEXT_lastIndexOf, &Dstring_prototype_lastIndexOf, 1 },
+	    {   &TEXT_localeCompare, &Dstring_prototype_localeCompare, 1 },
+	    {   &TEXT_match, &Dstring_prototype_match, 1 },
+	    {   &TEXT_replace, &Dstring_prototype_replace, 2 },
+	    {   &TEXT_search, &Dstring_prototype_search, 1 },
+	    {   &TEXT_slice, &Dstring_prototype_slice, 2 },
+	    {   &TEXT_split, &Dstring_prototype_split, 2 },
+	    {   &TEXT_substr, &Dstring_prototype_substr, 2 },
+	    {   &TEXT_substring, &Dstring_prototype_substring, 2 },
+	    {   &TEXT_toLowerCase, &Dstring_prototype_toLowerCase, 0 },
+	    {   &TEXT_toLocaleLowerCase, &Dstring_prototype_toLocaleLowerCase, 0 },
+	    {   &TEXT_toUpperCase, &Dstring_prototype_toUpperCase, 0 },
+	    {   &TEXT_toLocaleUpperCase, &Dstring_prototype_toLocaleUpperCase, 0 },
+	    {   &TEXT_anchor, &Dstring_prototype_anchor, 1 },
+	    {   &TEXT_fontcolor, &Dstring_prototype_fontcolor, 1 },
+	    {   &TEXT_fontsize, &Dstring_prototype_fontsize, 1 },
+	    {   &TEXT_link, &Dstring_prototype_link, 1 },
+	    {   &TEXT_big, &Dstring_prototype_big, 0 },
+	    {   &TEXT_blink, &Dstring_prototype_blink, 0 },
+	    {   &TEXT_bold, &Dstring_prototype_bold, 0 },
+	    {   &TEXT_fixed, &Dstring_prototype_fixed, 0 },
+	    {   &TEXT_italics, &Dstring_prototype_italics, 0 },
+	    {   &TEXT_small, &Dstring_prototype_small, 0 },
+	    {   &TEXT_strike, &Dstring_prototype_strike, 0 },
+	    {   &TEXT_sub, &Dstring_prototype_sub, 0 },
+	    {   &TEXT_sup, &Dstring_prototype_sup, 0 },
+	];
+
+	DnativeFunction.init(this, nfd, DontEnum);
+    }
+}
+
+/* ===================== Dstring ==================== */
+
+class Dstring : Dobject
+{
+    this(d_string s)
+    {
+	super(getPrototype());
+	classname = TEXT_String;
+
+	Put(TEXT_length, std.utf.toUCSindex(s, s.length), DontEnum | DontDelete | ReadOnly);
+	value.putVstring(s);
+    }
+
+    this(Dobject prototype)
+    {
+	super(prototype);
+
+	classname = TEXT_String;
+	Put(TEXT_length, 0, DontEnum | DontDelete | ReadOnly);
+	value.putVstring(null);
+    }
+
+    static void init(ThreadContext *tc)
+    {
+	tc.Dstring_constructor = new Dstring_constructor(tc);
+	tc.Dstring_prototype = new Dstring_prototype(tc);
+
+	tc.Dstring_constructor.Put(TEXT_prototype, tc.Dstring_prototype, DontEnum | DontDelete | ReadOnly);
+    }
+
+    static Dfunction getConstructor()
+    {
+	ThreadContext *tc = ThreadContext.getThreadContext();
+	assert(tc);
+	return tc.Dstring_constructor;
+    }
+
+    static Dobject getPrototype()
+    {
+	ThreadContext *tc = ThreadContext.getThreadContext();
+	assert(tc);
+	return tc.Dstring_prototype;
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/dmdscript_tango/expression.d	Sun Jan 24 12:34:47 2010 +0200
@@ -0,0 +1,1607 @@
+
+/* 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.expression;
+
+import std.string;
+
+import dmdscript.script;
+import dmdscript.lexer;
+import dmdscript.scopex;
+import dmdscript.text;
+import dmdscript.errmsgs;
+import dmdscript.functiondefinition;
+import dmdscript.irstate;
+import dmdscript.ir;
+import dmdscript.opcodes;
+import dmdscript.identifier;
+
+/******************************** Expression **************************/
+
+class Expression
+{
+    const uint EXPRESSION_SIGNATURE = 0x3AF31E3F;
+    uint signature = EXPRESSION_SIGNATURE;
+
+    Loc loc;			// file location
+    TOK op;
+
+    this(Loc loc, TOK op)
+    {
+	this.loc = loc;
+	this.op = op;
+	signature = EXPRESSION_SIGNATURE;
+    }
+
+    invariant
+    {
+	assert(signature == EXPRESSION_SIGNATURE);
+	assert(op != TOKreserved && op < TOKmax);
+    }
+
+    /**************************
+     * Semantically analyze Expression.
+     * Determine types, fold constants, etc.
+     */
+
+    Expression semantic(Scope *sc)
+    {
+	return this;
+    }
+
+    tchar[] toString()
+    {   tchar[] buf;
+
+	toBuffer(buf);
+	return buf;
+    }
+
+    void toBuffer(inout char[] buf)
+    {
+	buf ~= toString();
+    }
+
+    void checkLvalue(Scope *sc)
+    {
+	tchar[] buf;
+
+	//writefln("checkLvalue(), op = %d", op);
+	if (sc.funcdef)
+	{   if (sc.funcdef.isanonymous)
+		buf = "anonymous";
+	    else if (sc.funcdef.name)
+		buf = sc.funcdef.name.toString();
+	}
+	buf ~= std.string.format("(%d) : Error: ", loc);
+	buf ~= std.string.format(errmsgtbl[ERR_CANNOT_ASSIGN_TO], toString());
+
+	if (!sc.errinfo.message)
+	{   sc.errinfo.message = buf;
+	    sc.errinfo.linnum = loc;
+	    sc.errinfo.srcline = Lexer.locToSrcline(sc.getSource().ptr, loc);
+	}
+    }
+
+    // Do we match for purposes of optimization?
+
+    int match(Expression e)
+    {
+	return false;
+    }
+
+    // Is the result of the expression guaranteed to be a boolean?
+
+    int isBooleanResult()
+    {
+	return false;
+    }
+
+    void toIR(IRstate *irs, uint ret)
+    {
+	//writef("Expression::toIR('%s')\n", toChars());
+    }
+
+    void toLvalue(IRstate *irs, out uint base, IR *property, out int opoff)
+    {
+	base = irs.alloc(1);
+	toIR(irs, base);
+	property.index = 0;
+	opoff = 3;
+    }
+}
+
+/******************************** RealExpression **************************/
+
+class RealExpression : Expression
+{
+    real_t value;
+
+    this(Loc loc, real_t value)
+    {
+	super(loc, TOKreal);
+	this.value = value;
+    }
+
+    tchar[] toString()
+    {   tchar[] buf;
+	long i;
+
+	i = cast(long) value;
+	if (i == value)
+	    buf = std.string.format("%d", i);
+	else
+	    buf = std.string.format("%g", value);
+	return buf;
+    }
+
+    void toBuffer(inout tchar[] buf)
+    {
+	buf ~= std.string.format("%g", value);
+    }
+
+    void toIR(IRstate *irs, uint ret)
+    {
+	//writef("RealExpression::toIR(%g)\n", value);
+
+	static assert(value.sizeof == 2 * uint.sizeof);
+	if (ret)
+	    irs.gen(loc, IRnumber, 3, ret, value);
+    }
+}
+
+/******************************** IdentifierExpression **************************/
+
+class IdentifierExpression : Expression
+{
+    Identifier *ident;
+
+    this(Loc loc, Identifier *ident)
+    {
+	super(loc, TOKidentifier);
+	this.ident = ident;
+    }
+
+    Expression semantic(Scope *sc)
+    {
+	return this;
+    }
+
+    tchar[] toString()
+    {
+	return ident.toString();
+    }
+
+    void checkLvalue(Scope *sc)
+    {
+    }
+
+    int match(Expression e)
+    {
+	if (e.op != TOKidentifier)
+	    return 0;
+
+	IdentifierExpression ie = cast(IdentifierExpression)(e);
+
+	return ident == ie.ident;
+    }
+
+    void toIR(IRstate *irs, uint ret)
+    {
+	Identifier* id = ident;
+
+	assert(id.sizeof == uint.sizeof);
+	if (ret)
+	    irs.gen2(loc, IRgetscope, ret, cast(uint)id);
+    }
+
+    void toLvalue(IRstate *irs, out uint base, IR *property, out int opoff)
+    {
+	//irs.gen1(loc, IRthis, base);
+	property.id = ident;
+	opoff = 2;
+	base = ~0u;
+    }
+}
+
+/******************************** ThisExpression **************************/
+
+class ThisExpression : Expression
+{
+    this(Loc loc)
+    {
+	super(loc, TOKthis);
+    }
+
+    tchar[] toString()
+    {
+	return TEXT_this;
+    }
+
+    Expression semantic(Scope *sc)
+    {
+	return this;
+    }
+
+    void toIR(IRstate *irs, uint ret)
+    {
+	if (ret)
+	    irs.gen1(loc, IRthis, ret);
+    }
+}
+
+/******************************** NullExpression **************************/
+
+class NullExpression : Expression
+{
+    this(Loc loc)
+    {
+	super(loc, TOKnull);
+    }
+
+    tchar[] toString()
+    {
+	return TEXT_null;
+    }
+
+    void toIR(IRstate *irs, uint ret)
+    {
+	if (ret)
+	    irs.gen1(loc, IRnull, ret);
+    }
+}
+
+/******************************** StringExpression **************************/
+
+class StringExpression : Expression
+{
+    tchar[] string;
+
+    this(Loc loc, tchar[] string)
+    {
+	//writefln("StringExpression('%s')", string);
+	super(loc, TOKstring);
+	this.string = string;
+    }
+
+    void toBuffer(inout tchar[] buf)
+    {
+	buf ~= '"';
+	foreach (dchar c; string)
+	{
+	    switch (c)
+	    {
+		case '"':
+		    buf ~= '\\';
+		    goto Ldefault;
+
+		default:
+		Ldefault:
+		    if (c & ~0xFF)
+			buf ~= std.string.format("\\u%04x", c);
+		    else if (std.ctype.isprint(c))
+			buf ~= cast(tchar)c;
+		    else
+			buf ~= std.string.format("\\x%02x", c);
+		    break;
+	    }
+	}
+	buf ~= '"';
+    }
+
+    void toIR(IRstate *irs, uint ret)
+    {
+	static assert((Identifier*).sizeof == uint.sizeof);
+	if (ret)
+	{   uint u =  cast(uint)Identifier.build(string);
+	    irs.gen2(loc, IRstring, ret, u);
+	}
+    }
+}
+
+/******************************** RegExpLiteral **************************/
+
+class RegExpLiteral : Expression
+{
+    tchar[] string;
+
+    this(Loc loc, tchar[] string)
+    {
+	//writefln("RegExpLiteral('%s')", string);
+	super(loc, TOKregexp);
+	this.string = string;
+    }
+
+    void toBuffer(inout tchar[] buf)
+    {
+	buf ~= string;
+    }
+
+    void toIR(IRstate *irs, uint ret)
+    {   d_string pattern;
+	d_string attribute = null;
+	int e;
+
+	uint argc;
+	uint argv;
+	uint b;
+
+	// Regular expression is of the form:
+	//	/pattern/attribute
+
+	// Parse out pattern and attribute strings
+	assert(string[0] == '/');
+	e = std.string.rfind(string, '/');
+	assert(e != -1);
+	pattern = string[1 .. e];
+	argc = 1;
+	if (e + 1 < string.length)
+	{   attribute = string[e + 1 .. length];
+	    argc++;
+	}
+
+	// Generate new Regexp(pattern [, attribute])
+
+	b = irs.alloc(1);
+	Identifier* re = Identifier.build(TEXT_RegExp);
+	irs.gen2(loc, IRgetscope, b, cast(uint)re);
+	argv = irs.alloc(argc);
+	irs.gen2(loc, IRstring, argv, cast(uint)Identifier.build(pattern));
+	if (argc == 2)
+	    irs.gen2(loc, IRstring, argv + 1 * INDEX_FACTOR, cast(uint)Identifier.build(attribute));
+	irs.gen4(loc, IRnew, ret,b,argc,argv);
+	irs.release(b, argc + 1);
+    }
+}
+
+/******************************** BooleanExpression **************************/
+
+class BooleanExpression : Expression
+{
+    int boolean;
+
+    this(Loc loc, int boolean)
+    {
+	super(loc, TOKboolean);
+	this.boolean = boolean;
+    }
+
+    tchar[] toString()
+    {
+	return boolean ? "true" : "false";
+    }
+
+    void toBuffer(inout tchar[] buf)
+    {
+	buf ~= toString();
+    }
+
+    int isBooleanResult()
+    {
+	return true;
+    }
+
+    void toIR(IRstate *irs, uint ret)
+    {
+	if (ret)
+	    irs.gen2(loc, IRboolean, ret, boolean);
+    }
+}
+
+/******************************** ArrayLiteral **************************/
+
+class ArrayLiteral : Expression
+{
+    Expression[] elements;
+
+    this(Loc loc, Expression[] elements)
+    {
+	super(loc, TOKarraylit);
+	this.elements = elements;
+    }
+
+    Expression semantic(Scope *sc)
+    {
+	foreach (inout Expression e; elements)
+	{
+	    if (e)
+		e = e.semantic(sc);
+	}
+	return this;
+    }
+
+    void toBuffer(inout tchar[] buf)
+    {   uint i;
+
+	buf ~= '[';
+	foreach (Expression e; elements)
+	{
+	    if (i)
+		buf ~= ',';
+	    i = 1;
+	    if (e)
+		e.toBuffer(buf);
+	}
+	buf ~= ']';
+    }
+
+    void toIR(IRstate *irs, uint ret)
+    {
+	uint argc;
+	uint argv;
+	uint b;
+	uint v;
+
+	b = irs.alloc(1);
+	static Identifier* ar;
+	if (!ar)
+	    ar = Identifier.build(TEXT_Array);
+	irs.gen2(loc, IRgetscope, b, cast(uint)ar);
+	if (elements.length)
+	{   Expression e;
+
+	    argc = elements.length;
+	    argv = irs.alloc(argc);
+	    if (argc > 1)
+	    {   uint i;
+
+		// array literal [a, b, c] is equivalent to:
+		//	new Array(a,b,c)
+		for (i = 0; i < argc; i++)
+		{
+		    e = elements[i];
+		    if (e)
+		    {
+			e.toIR(irs, argv + i * INDEX_FACTOR);
+		    }
+		    else
+			irs.gen1(loc, IRundefined, argv + i * INDEX_FACTOR);
+		}
+		irs.gen4(loc, IRnew, ret,b,argc,argv);
+	    }
+	    else
+	    {   //	[a] translates to:
+		//	ret = new Array(1);
+		//  ret[0] = a
+		irs.gen(loc, IRnumber, 3, argv, 1.0);
+		irs.gen4(loc, IRnew, ret,b,argc,argv);
+
+		e = elements[0];
+		v = irs.alloc(1);
+		if (e)
+		    e.toIR(irs, v);
+		else
+		    irs.gen1(loc, IRundefined, v);
+		irs.gen3(loc, IRputs, v, ret, cast(uint)Identifier.build(TEXT_0));
+		irs.release(v, 1);
+	    }
+	    irs.release(argv, argc);
+	}
+	else
+	{
+	    // Generate new Array()
+	    irs.gen4(loc, IRnew, ret,b,0,0);
+	}
+	irs.release(b, 1);
+    }
+}
+
+/******************************** FieldLiteral **************************/
+
+class Field
+{
+    Identifier* ident;
+    Expression exp;
+
+    this(Identifier *ident, Expression exp)
+    {
+	this.ident = ident;
+	this.exp = exp;
+    }
+}
+
+/******************************** ObjectLiteral **************************/
+
+class ObjectLiteral : Expression
+{
+    Field[] fields;
+
+    this(Loc loc, Field[] fields)
+    {
+	super(loc, TOKobjectlit);
+	this.fields = fields;
+    }
+
+    Expression semantic(Scope *sc)
+    {
+	foreach (Field f; fields)
+	{
+	    f.exp = f.exp.semantic(sc);
+	}
+	return this;
+    }
+
+    void toBuffer(inout tchar[] buf)
+    {   uint i;
+
+	buf ~= '{';
+	foreach (Field f; fields)
+	{
+	    if (i)
+		buf ~= ',';
+	    i = 1;
+	    buf ~= f.ident.toString();
+	    buf ~= ':';
+	    f.exp.toBuffer(buf);
+	}
+	buf ~= '}';
+    }
+
+    void toIR(IRstate *irs, uint ret)
+    {
+	uint b;
+
+	b = irs.alloc(1);
+	//irs.gen2(loc, IRstring, b, TEXT_Object);
+	Identifier* ob = Identifier.build(TEXT_Object);
+	irs.gen2(loc, IRgetscope, b, cast(uint)ob);
+	// Generate new Object()
+	irs.gen4(loc, IRnew, ret,b,0,0);
+	if (fields.length)
+	{
+	    uint x;
+
+	    x = irs.alloc(1);
+	    foreach (Field f; fields)
+	    {
+		f.exp.toIR(irs, x);
+		irs.gen3(loc, IRputs, x, ret, cast(uint)(f.ident));
+	    }
+	}
+    }
+}
+
+/******************************** FunctionLiteral **************************/
+
+class FunctionLiteral : Expression
+{   FunctionDefinition func;
+
+    this(Loc loc, FunctionDefinition func)
+    {
+	super(loc, TOKobjectlit);
+	this.func = func;
+    }
+
+    Expression semantic(Scope *sc)
+    {
+	func = cast(FunctionDefinition)(func.semantic(sc));
+	return this;
+    }
+
+    void toBuffer(inout tchar[] buf)
+    {
+	func.toBuffer(buf);
+    }
+
+    void toIR(IRstate *irs, uint ret)
+    {
+	func.toIR(null);
+	irs.gen2(loc, IRobject, ret, cast(uint)cast(void*)func);
+    }
+}
+
+/***************************** UnaExp *************************************/
+
+class UnaExp : Expression
+{
+    Expression e1;
+
+    this(Loc loc, TOK op, Expression e1)
+    {
+	super(loc, op);
+	this.e1 = e1;
+    }
+
+    Expression semantic(Scope *sc)
+    {
+	e1 = e1.semantic(sc);
+	return this;
+    }
+
+    void toBuffer(inout tchar[] buf)
+    {
+	buf ~= Token.toString(op);
+	buf ~= ' ';
+	e1.toBuffer(buf);
+    }
+}
+
+/***************************** BinExp *************************************/
+
+class BinExp : Expression
+{
+    Expression e1;
+    Expression e2;
+
+    this(Loc loc, TOK op, Expression e1, Expression e2)
+    {
+	super(loc, op);
+	this.e1 = e1;
+	this.e2 = e2;
+    }
+
+    Expression semantic(Scope *sc)
+    {
+	e1 = e1.semantic(sc);
+	e2 = e2.semantic(sc);
+	return this;
+    }
+
+    void toBuffer(inout tchar[] buf)
+    {
+	e1.toBuffer(buf);
+	buf ~= ' ';
+	buf ~= Token.toString(op);
+	buf ~= ' ';
+	e2.toBuffer(buf);
+    }
+
+    void binIR(IRstate *irs, uint ret, uint ircode)
+    {   uint b;
+	uint c;
+
+	if (ret)
+	{
+	    b = irs.alloc(1);
+	    e1.toIR(irs, b);
+	    if (e1.match(e2))
+	    {
+		irs.gen3(loc, ircode, ret, b, b);
+	    }
+	    else
+	    {
+		c = irs.alloc(1);
+		e2.toIR(irs, c);
+		irs.gen3(loc, ircode, ret, b, c);
+		irs.release(c, 1);
+	    }
+	    irs.release(b, 1);
+	}
+	else
+	{
+	    e1.toIR(irs, 0);
+	    e2.toIR(irs, 0);
+	}
+    }
+}
+
+/************************************************************/
+
+/* Handle ++e and --e
+ */
+
+class PreExp : UnaExp
+{
+    uint ircode;
+
+    this(Loc loc, uint ircode, Expression e)
+    {
+	super(loc, TOKplusplus, e);
+	this.ircode = ircode;
+    }
+
+    Expression semantic(Scope *sc)
+    {
+	super.semantic(sc);
+	e1.checkLvalue(sc);
+	return this;
+    }
+
+    void toBuffer(inout tchar[] buf)
+    {
+	e1.toBuffer(buf);
+	buf ~= Token.toString(op);
+    }
+
+    void toIR(IRstate *irs, uint ret)
+    {
+	uint base;
+	IR property;
+	int opoff;
+
+	//writef("PreExp::toIR('%s')\n", toChars());
+	e1.toLvalue(irs, base, &property, opoff);
+	assert(opoff != 3);
+	if (opoff == 2)
+	{
+	    //irs.gen2(loc, ircode + 2, ret, property.index);
+	    irs.gen3(loc, ircode + 2, ret, property.index, property.id.toHash());
+	}
+	else
+	    irs.gen3(loc, ircode + opoff, ret, base, property.index);
+    }
+}
+
+/************************************************************/
+
+class PostIncExp : UnaExp
+{
+    this(Loc loc, Expression e)
+    {
+	super(loc, TOKplusplus, e);
+    }
+
+    Expression semantic(Scope *sc)
+    {
+	super.semantic(sc);
+	e1.checkLvalue(sc);
+	return this;
+    }
+
+    void toBuffer(inout tchar[] buf)
+    {
+	e1.toBuffer(buf);
+	buf ~= Token.toString(op);
+    }
+
+    void toIR(IRstate *irs, uint ret)
+    {
+	uint base;
+	IR property;
+	int opoff;
+
+	//writef("PostIncExp::toIR('%s')\n", toChars());
+	e1.toLvalue(irs, base, &property, opoff);
+	assert(opoff != 3);
+	if (opoff == 2)
+	{
+	    if (ret)
+	    {
+		irs.gen2(loc, IRpostincscope, ret, property.index);
+	    }
+	    else
+	    {
+		//irs.gen2(loc, IRpreincscope, ret, property.index);
+		irs.gen3(loc, IRpreincscope, ret, property.index, property.id.toHash());
+	    }
+	}
+	else
+	    irs.gen3(loc, (ret ? IRpostinc : IRpreinc) + opoff, ret, base, property.index);
+    }
+}
+
+/****************************************************************/
+
+class PostDecExp : UnaExp
+{
+    this(Loc loc, Expression e)
+    {
+	super(loc, TOKplusplus, e);
+    }
+
+    Expression semantic(Scope *sc)
+    {
+	super.semantic(sc);
+	e1.checkLvalue(sc);
+	return this;
+    }
+
+    void toBuffer(inout tchar[] buf)
+    {
+	e1.toBuffer(buf);
+	buf ~= Token.toString(op);
+    }
+
+    void toIR(IRstate *irs, uint ret)
+    {
+	uint base;
+	IR property;
+	int opoff;
+
+	//writef("PostDecExp::toIR('%s')\n", toChars());
+	e1.toLvalue(irs, base, &property, opoff);
+	assert(opoff != 3);
+	if (opoff == 2)
+	{
+	    if (ret)
+	    {
+		irs.gen2(loc, IRpostdecscope, ret, property.index);
+	    }
+	    else
+	    {
+		//irs.gen2(loc, IRpredecscope, ret, property.index);
+		irs.gen3(loc, IRpredecscope, ret, property.index, property.id.toHash());
+	    }
+	}
+	else
+	    irs.gen3(loc, (ret ? IRpostdec : IRpredec) + opoff, ret, base, property.index);
+    }
+}
+
+/************************************************************/
+
+class DotExp : UnaExp
+{
+    Identifier *ident;
+
+    this(Loc loc, Expression e, Identifier *ident)
+    {
+	super(loc, TOKdot, e);
+	this.ident = ident;
+    }
+
+    void checkLvalue(Scope *sc)
+    {
+    }
+
+    void toBuffer(inout tchar[] buf)
+    {
+	e1.toBuffer(buf);
+	buf ~= '.';
+	buf ~= ident.toString();
+    }
+
+    void toIR(IRstate *irs, uint ret)
+    {
+	uint base;
+
+	//writef("DotExp::toIR('%s')\n", toChars());
+      version (all)
+      {
+	// Some test cases depend on things like:
+	//		foo.bar;
+	// generating a property get even if the result is thrown away.
+	base = irs.alloc(1);
+	e1.toIR(irs, base);
+	irs.gen3(loc, IRgets, ret, base, cast(uint)ident);
+      }
+      else
+      {
+	if (ret)
+	{
+	    base = irs.alloc(1);
+	    e1.toIR(irs, base);
+	    irs.gen3(loc, IRgets, ret, base, cast(uint)ident);
+	}
+	else
+	    e1.toIR(irs, 0);
+      }
+    }
+
+    void toLvalue(IRstate *irs, out uint base, IR *property, out int opoff)
+    {
+	base = irs.alloc(1);
+	e1.toIR(irs, base);
+	property.id = ident;
+	opoff = 1;
+    }
+}
+
+/************************************************************/
+
+class CallExp : UnaExp
+{
+    Expression[] arguments;
+
+    this(Loc loc, Expression e, Expression[] arguments)
+    {
+	//writef("CallExp(e1 = %x)\n", e);
+	super(loc, TOKcall, e);
+	this.arguments = arguments;
+    }
+
+    Expression semantic(Scope *sc)
+    {   IdentifierExpression ie;
+
+	//writef("CallExp(e1=%x, %d, vptr=%x)\n", e1, e1.op, *(uint *)e1);
+	//writef("CallExp(e1='%s')\n", e1.toString());
+	e1 = e1.semantic(sc);
+	if (e1.op != TOKcall)
+	    e1.checkLvalue(sc);
+
+	foreach (inout Expression e; arguments)
+	{
+	    e = e.semantic(sc);
+	}
+	if (arguments.length == 1)
+	{
+	    if (e1.op == TOKidentifier)
+	    {
+		ie = cast(IdentifierExpression )e1;
+		if (ie.ident.toString() == "assert")
+		{
+		    return new AssertExp(loc, arguments[0]);
+		}
+	    }
+	}
+	return this;
+    }
+
+    void toBuffer(inout tchar[] buf)
+    {
+	e1.toBuffer(buf);
+	buf ~= '(';
+	for (size_t u = 0; u < arguments.length; u++)
+	{
+	    if (u)
+		buf ~= ", ";
+	    arguments[u].toBuffer(buf);
+	}
+	buf ~= ')';
+    }
+
+    void toIR(IRstate *irs, uint ret)
+    {
+	// ret = base.property(argc, argv)
+	// CALL ret,base,property,argc,argv
+	uint base;
+	uint argc;
+	uint argv;
+	IR property;
+	int opoff;
+
+	//writef("CallExp::toIR('%s')\n", toChars());
+	e1.toLvalue(irs, base, &property, opoff);
+
+	if (arguments.length)
+	{   uint u;
+
+	    argc = arguments.length;
+	    argv = irs.alloc(argc);
+	    for (u = 0; u < argc; u++)
+	    {   Expression e;
+
+		e = arguments[u];
+		e.toIR(irs, argv + u * INDEX_FACTOR);
+	    }
+	    arguments[] = null;		// release to GC
+	    arguments = null;
+	}
+	else
+	{
+	    argc = 0;
+	    argv = 0;
+	}
+
+	if (opoff == 3)
+	    irs.gen4(loc, IRcallv, ret,base,argc,argv);
+	else if (opoff == 2)
+	    irs.gen4(loc, IRcallscope, ret,property.index,argc,argv);
+	else
+	    irs.gen(loc, IRcall + opoff, 5, ret,base,property,argc,argv);
+	irs.release(argv, argc);
+    }
+}
+
+/************************************************************/
+
+class AssertExp : UnaExp
+{
+    this(Loc loc, Expression e)
+    {
+	super(loc, TOKassert, e);
+    }
+
+    void toBuffer(inout tchar[] buf)
+    {
+	buf ~= "assert(";
+	e1.toBuffer(buf);
+	buf ~= ')';
+    }
+
+    void toIR(IRstate *irs, uint ret)
+    {   uint linnum;
+	uint u;
+	uint b;
+
+	b = ret ? ret : irs.alloc(1);
+
+	e1.toIR(irs, b);
+	u = irs.getIP();
+	irs.gen2(loc, IRjt, 0, b);
+	linnum = cast(uint)loc;
+	irs.gen1(loc, IRassert, linnum);
+	irs.patchJmp(u, irs.getIP());
+
+	if (!ret)
+	    irs.release(b, 1);
+    }
+}
+
+/************************* NewExp ***********************************/
+
+class NewExp : UnaExp
+{
+    Expression[] arguments;
+
+    this(Loc loc, Expression e, Expression[] arguments)
+    {
+	super(loc, TOKnew, e);
+	this.arguments = arguments;
+    }
+
+    Expression semantic(Scope *sc)
+    {
+	e1 = e1.semantic(sc);
+	for (size_t a = 0; a < arguments.length; a++)
+	{
+	    arguments[a] = arguments[a].semantic(sc);
+	}
+	return this;
+    }
+
+    void toBuffer(inout tchar[] buf)
+    {
+	buf ~= Token.toString(op);
+	buf ~= ' ';
+
+	e1.toBuffer(buf);
+	buf ~= '(';
+	for (size_t a = 0; a < arguments.length; a++)
+	{
+	    arguments[a].toBuffer(buf);
+	}
+	buf ~= ')';
+    }
+
+    void toIR(IRstate *irs, uint ret)
+    {
+	// ret = new b(argc, argv)
+	// CALL ret,b,argc,argv
+	uint b;
+	uint argc;
+	uint argv;
+
+	//writef("NewExp::toIR('%s')\n", toChars());
+	b = irs.alloc(1);
+	e1.toIR(irs, b);
+	if (arguments.length)
+	{   uint u;
+
+	    argc = arguments.length;
+	    argv = irs.alloc(argc);
+	    for (u = 0; u < argc; u++)
+	    {   Expression e;
+
+		e = arguments[u];
+		e.toIR(irs, argv + u * INDEX_FACTOR);
+	    }
+	}
+	else
+	{
+	    argc = 0;
+	    argv = 0;
+	}
+
+	irs.gen4(loc, IRnew, ret,b,argc,argv);
+	irs.release(argv, argc);
+	irs.release(b, 1);
+    }
+}
+
+/************************************************************/
+
+class XUnaExp : UnaExp
+{
+    uint ircode;
+
+    this(Loc loc, TOK op, uint ircode, Expression e)
+    {
+	super(loc, op, e);
+	this.ircode = ircode;
+    }
+
+    void toIR(IRstate *irs, uint ret)
+    {
+	e1.toIR(irs, ret);
+	if (ret)
+	    irs.gen1(loc, ircode, ret);
+    }
+}
+
+class NotExp : XUnaExp
+{
+    this(Loc loc, Expression e)
+    {
+	super(loc, TOKnot, IRnot, e);
+    }
+
+    int isBooleanResult()
+    {
+	return true;
+    }
+}
+
+class DeleteExp : UnaExp
+{
+    this(Loc loc, Expression e)
+    {
+	super(loc, TOKdelete, e);
+    }
+
+    Expression semantic(Scope *sc)
+    {
+	e1.checkLvalue(sc);
+	return this;
+    }
+
+    void toIR(IRstate *irs, uint ret)
+    {
+	uint base;
+	IR property;
+	int opoff;
+
+	e1.toLvalue(irs, base, &property, opoff);
+	assert(opoff != 3);
+	if (opoff == 2)
+	    irs.gen2(loc, IRdelscope, ret, property.index);
+	else
+	    irs.gen3(loc, IRdel + opoff, ret, base, property.index);
+    }
+}
+
+/************************* CommaExp ***********************************/
+
+class CommaExp : BinExp
+{
+    this(Loc loc, Expression e1, Expression e2)
+    {
+	super(loc, TOKcomma, e1, e2);
+    }
+
+    void checkLvalue(Scope *sc)
+    {
+	e2.checkLvalue(sc);
+    }
+
+    void toIR(IRstate *irs, uint ret)
+    {
+	e1.toIR(irs, 0);
+	e2.toIR(irs, ret);
+    }
+}
+
+/************************* ArrayExp ***********************************/
+
+class ArrayExp : BinExp
+{
+    this(Loc loc, Expression e1, Expression e2)
+    {
+	super(loc, TOKarray, e1, e2);
+    }
+
+    Expression semantic(Scope *sc)
+    {
+	checkLvalue(sc);
+	return this;
+    }
+
+    void checkLvalue(Scope *sc)
+    {
+    }
+
+    void toBuffer(inout tchar[] buf)
+    {
+	e1.toBuffer(buf);
+	buf ~= '[';
+	e2.toBuffer(buf);
+	buf ~= ']';
+    }
+
+    void toIR(IRstate *irs, uint ret)
+    {   uint base;
+	IR property;
+	int opoff;
+
+	if (ret)
+	{
+	    toLvalue(irs, base, &property, opoff);
+	    assert(opoff != 3);
+	    if (opoff == 2)
+		irs.gen2(loc, IRgetscope, ret, property.index);
+	    else
+		irs.gen3(loc, IRget + opoff, ret, base, property.index);
+	}
+	else
+	{
+	    e1.toIR(irs, 0);
+	    e2.toIR(irs, 0);
+	}
+    }
+
+    void toLvalue(IRstate *irs, out uint base, IR *property, out int opoff)
+    {   uint index;
+
+	base = irs.alloc(1);
+	e1.toIR(irs, base);
+	index = irs.alloc(1);
+	e2.toIR(irs, index);
+	property.index = index;
+	opoff = 0;
+    }
+}
+
+/************************* AssignExp ***********************************/
+
+class AssignExp : BinExp
+{
+    this(Loc loc, Expression e1, Expression e2)
+    {
+	super(loc, TOKassign, e1, e2);
+    }
+
+    Expression semantic(Scope *sc)
+    {
+	//writefln("AssignExp.semantic()");
+	super.semantic(sc);
+	if (e1.op != TOKcall)		// special case for CallExp lvalue's
+	    e1.checkLvalue(sc);
+	return this;
+    }
+
+    void toIR(IRstate *irs, uint ret)
+    {
+	uint b;
+
+	//writef("AssignExp::toIR('%s')\n", toChars());
+	if (e1.op == TOKcall)		// if CallExp
+	{
+	    assert(cast(CallExp)(e1));	// make sure we got it right
+
+	    // Special case a function call as an lvalue.
+	    // This can happen if:
+	    //	foo() = 3;
+	    // A Microsoft extension, it means to assign 3 to the default property of
+	    // the object returned by foo(). It only has meaning for com objects.
+	    // This functionality should be worked into toLvalue() if it gets used
+	    // elsewhere.
+
+	    uint base;
+	    uint argc;
+	    uint argv;
+	    IR property;
+	    int opoff;
+	    CallExp ec = cast(CallExp)e1;
+
+	    if (ec.arguments.length)
+		argc = ec.arguments.length + 1;
+	    else
+		argc = 1;
+
+	    argv = irs.alloc(argc);
+
+	    e2.toIR(irs, argv + (argc - 1) * INDEX_FACTOR);
+
+	    ec.e1.toLvalue(irs, base, &property, opoff);
+
+	    if (ec.arguments.length)
+	    {   uint u;
+
+		for (u = 0; u < ec.arguments.length; u++)
+		{   Expression e;
+
+		    e = ec.arguments[u];
+		    e.toIR(irs, argv + (u + 0) * INDEX_FACTOR);
+		}
+		ec.arguments[] = null;		// release to GC
+		ec.arguments = null;
+	    }
+
+	    if (opoff == 3)
+		irs.gen4(loc, IRputcallv, ret,base,argc,argv);
+	    else if (opoff == 2)
+		irs.gen4(loc, IRputcallscope, ret,property.index,argc,argv);
+	    else
+		irs.gen(loc, IRputcall + opoff, 5, ret,base,property,argc,argv);
+	    irs.release(argv, argc);
+	}
+	else
+	{
+	    uint base;
+	    IR property;
+	    int opoff;
+
+	    b = ret ? ret : irs.alloc(1);
+	    e2.toIR(irs, b);
+
+	    e1.toLvalue(irs, base, &property, opoff);
+	    assert(opoff != 3);
+	    if (opoff == 2)
+		irs.gen2(loc, IRputscope, b, property.index);
+	    else
+		irs.gen3(loc, IRput + opoff, b, base, property.index);
+	    if (!ret)
+		irs.release(b, 1);
+	}
+    }
+}
+
+/************************* AddAssignExp ***********************************/
+
+class AddAssignExp : BinExp
+{
+    this(Loc loc, Expression e1, Expression e2)
+    {
+	super(loc, TOKplusass, e1, e2);
+    }
+
+    Expression semantic(Scope *sc)
+    {
+	super.semantic(sc);
+	e1.checkLvalue(sc);
+	return this;
+    }
+
+    void toIR(IRstate *irs, uint ret)
+    {
+	if (ret == 0 && e2.op == TOKreal &&
+	    (cast(RealExpression)e2).value == 1)
+	{
+	    uint base;
+	    IR property;
+	    int opoff;
+
+	    //writef("AddAssign to PostInc('%s')\n", toChars());
+	    e1.toLvalue(irs, base, &property, opoff);
+	    assert(opoff != 3);
+	    if (opoff == 2)
+		irs.gen2(loc, IRpostincscope, ret, property.index);
+	    else
+		irs.gen3(loc, IRpostinc + opoff, ret, base, property.index);
+	}
+	else
+	{
+	    uint r;
+	    uint base;
+	    IR property;
+	    int opoff;
+
+	    //writef("AddAssignExp::toIR('%s')\n", toChars());
+	    e1.toLvalue(irs, base, &property, opoff);
+	    assert(opoff != 3);
+	    r = ret ? ret : irs.alloc(1);
+	    e2.toIR(irs, r);
+	    if (opoff == 2)
+		irs.gen3(loc, IRaddassscope, r, property.index, property.id.toHash());
+	    else
+		irs.gen3(loc, IRaddass + opoff, r, base, property.index);
+	    if (!ret)
+		irs.release(r, 1);
+	}
+    }
+}
+
+/************************* BinAssignExp ***********************************/
+
+class BinAssignExp : BinExp
+{
+    uint ircode = IRerror;
+
+    this(Loc loc, TOK op, uint ircode, Expression e1, Expression e2)
+    {
+	super(loc, op, e1, e2);
+	this.ircode = ircode;
+    }
+
+    Expression semantic(Scope *sc)
+    {
+	super.semantic(sc);
+	e1.checkLvalue(sc);
+	return this;
+    }
+
+    void toIR(IRstate *irs, uint ret)
+    {
+	uint b;
+	uint c;
+	uint r;
+	uint base;
+	IR property;
+	int opoff;
+
+	//writef("BinExp::binAssignIR('%s')\n", toChars());
+	e1.toLvalue(irs, base, &property, opoff);
+	assert(opoff != 3);
+	b = irs.alloc(1);
+	if (opoff == 2)
+	    irs.gen2(loc, IRgetscope, b, property.index);
+	else
+	    irs.gen3(loc, IRget + opoff, b, base, property.index);
+	c = irs.alloc(1);
+	e2.toIR(irs, c);
+	r = ret ? ret : irs.alloc(1);
+	irs.gen3(loc, ircode, r, b, c);
+	if (opoff == 2)
+	    irs.gen2(loc, IRputscope, r, property.index);
+	else
+	    irs.gen3(loc, IRput + opoff, r, base, property.index);
+	if (!ret)
+	    irs.release(r, 1);
+    }
+}
+
+/************************* AddExp *****************************/
+
+class AddExp : BinExp
+{
+    this(Loc loc, Expression e1, Expression e2)
+    {
+	super(loc, TOKplus, e1, e2);;
+    }
+
+    Expression semantic(Scope *sc)
+    {
+	return this;
+    }
+
+    void toIR(IRstate *irs, uint ret)
+    {
+	binIR(irs, ret, IRadd);
+    }
+}
+
+/************************* XBinExp ***********************************/
+
+class XBinExp : BinExp
+{
+    uint ircode = IRerror;
+
+    this(Loc loc, TOK op, uint ircode, Expression e1, Expression e2)
+    {
+	super(loc, op, e1, e2);
+	this.ircode = ircode;
+    }
+
+    void toIR(IRstate *irs, uint ret)
+    {
+	binIR(irs, ret, ircode);
+    }
+}
+
+/************************* OrOrExp ***********************************/
+
+class OrOrExp : BinExp
+{
+    this(Loc loc, Expression e1, Expression e2)
+    {
+	super(loc, TOKoror, e1, e2);
+    }
+
+    void toIR(IRstate *irs, uint ret)
+    {   uint u;
+	uint b;
+
+	if (ret)
+	    b = ret;
+	else
+	    b = irs.alloc(1);
+
+	e1.toIR(irs, b);
+	u = irs.getIP();
+	irs.gen2(loc, IRjt, 0, b);
+	e2.toIR(irs, ret);
+	irs.patchJmp(u, irs.getIP());
+
+	if (!ret)
+	    irs.release(b, 1);
+    }
+}
+
+/************************* AndAndExp ***********************************/
+
+class AndAndExp : BinExp
+{
+    this(Loc loc, Expression e1, Expression e2)
+    {
+	super(loc, TOKandand, e1, e2);
+    }
+
+    void toIR(IRstate *irs, uint ret)
+    {   uint u;
+	uint b;
+
+	if (ret)
+	    b = ret;
+	else
+	    b = irs.alloc(1);
+
+	e1.toIR(irs, b);
+	u = irs.getIP();
+	irs.gen2(loc, IRjf, 0, b);
+	e2.toIR(irs, ret);
+	irs.patchJmp(u, irs.getIP());
+
+	if (!ret)
+	    irs.release(b, 1);
+    }
+}
+
+/************************* CmpExp ***********************************/
+
+
+
+class CmpExp : BinExp
+{
+    uint ircode = IRerror;
+
+    this(Loc loc, TOK tok, uint ircode, Expression e1, Expression e2)
+    {
+	super(loc, tok, e1, e2);
+	this.ircode = ircode;
+    }
+
+    int isBooleanResult()
+    {
+	return true;
+    }
+
+    void toIR(IRstate *irs, uint ret)
+    {
+	binIR(irs, ret, ircode);
+    }
+}
+
+/*************************** InExp **************************/
+
+class InExp : BinExp
+{
+    this(Loc loc, Expression e1, Expression e2)
+    {
+	super(loc, TOKin, e1, e2);
+    }
+}
+
+/****************************************************************/
+
+class CondExp : BinExp
+{
+    Expression econd;
+
+    this(Loc loc, Expression econd, Expression e1, Expression e2)
+    {
+	super(loc, TOKquestion, e1, e2);
+	this.econd = econd;
+    }
+
+    void toIR(IRstate *irs, uint ret)
+    {   uint u1;
+	uint u2;
+	uint b;
+
+	if (ret)
+	    b = ret;
+	else
+	    b = irs.alloc(1);
+
+	econd.toIR(irs, b);
+	u1 = irs.getIP();
+	irs.gen2(loc, IRjf, 0, b);
+	e1.toIR(irs, ret);
+	u2 = irs.getIP();
+	irs.gen1(loc, IRjmp, 0);
+	irs.patchJmp(u1, irs.getIP());
+	e2.toIR(irs, ret);
+	irs.patchJmp(u2, irs.getIP());
+
+	if (!ret)
+	    irs.release(b, 1);
+    }
+}
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/dmdscript_tango/functiondefinition.d	Sun Jan 24 12:34:47 2010 +0200
@@ -0,0 +1,263 @@
+
+/* 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.functiondefinition;
+
+import std.stdio;
+
+import dmdscript.script;
+import dmdscript.identifier;
+import dmdscript.statement;
+import dmdscript.dfunction;
+import dmdscript.scopex;
+import dmdscript.irstate;
+import dmdscript.opcodes;
+import dmdscript.ddeclaredfunction;
+import dmdscript.symbol;
+import dmdscript.dobject;
+import dmdscript.ir;
+import dmdscript.errmsgs;
+import dmdscript.value;
+import dmdscript.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()");
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/dmdscript_tango/identifier.d	Sun Jan 24 12:34:47 2010 +0200
@@ -0,0 +1,57 @@
+
+/* Digital Mars DMDScript source code.
+ * Copyright (c) 2000-2002 by Chromium Communications
+ * D version Copyright (c) 2004-2009 by Digital Mars
+ * All Rights Reserved
+ * written by Walter Bright
+ * http://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.identifier;
+
+import dmdscript.script;
+import dmdscript.value;
+
+/* An Identifier is a special case of a Value - it is a V_STRING
+ * and has the hash value computed and set.
+ */
+
+struct Identifier
+{
+    Value value;
+
+    tchar[] toString()
+    {
+	return value.string;
+    }
+
+    int opEquals(Identifier *id)
+    {
+	return this is id || value.string == id.value.string;
+    }
+
+    static Identifier* build(tchar[] s)
+    {	Identifier* id = new Identifier;
+	id.value.putVstring(s);
+	id.value.toHash();
+	return id;
+    }
+
+    uint toHash()
+    {
+	return value.hash;
+    }
+}
+
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/dmdscript_tango/ir.d	Sun Jan 24 12:34:47 2010 +0200
@@ -0,0 +1,140 @@
+
+/* 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.
+ */
+
+
+// Opcodes for our Intermediate Representation (IR)
+
+module dmdscript.ir;
+
+enum
+{
+    IRerror,
+    IRnop,			// no operation
+    IRend,			// end of function
+    IRstring,
+    IRthisget,
+    IRnumber,
+    IRobject,
+    IRthis,
+    IRnull,
+    IRundefined,
+    IRboolean,
+    IRcall,
+    IRcalls = IRcall + 1,
+    IRcallscope = IRcalls + 1,
+    IRcallv = IRcallscope + 1,
+    IRputcall,
+    IRputcalls = IRputcall + 1,
+    IRputcallscope = IRputcalls + 1,
+    IRputcallv = IRputcallscope + 1,
+    IRget,
+    IRgets = IRget + 1,		// 's' versions must be original + 1
+    IRgetscope = IRgets + 1,
+    IRput,
+    IRputs = IRput + 1,
+    IRputscope = IRputs + 1,
+    IRdel,
+    IRdels = IRdel + 1,
+    IRdelscope = IRdels + 1,
+    IRnext,
+    IRnexts = IRnext + 1,
+    IRnextscope = IRnexts + 1,
+    IRaddass,
+    IRaddasss = IRaddass + 1,
+    IRaddassscope = IRaddasss + 1,
+    IRputthis,
+    IRputdefault,
+    IRmov,
+    IRret,
+    IRretexp,
+    IRimpret,
+    IRneg,
+    IRpos,
+    IRcom,
+    IRnot,
+    IRadd,
+    IRsub,
+    IRmul,
+    IRdiv,
+    IRmod,
+    IRshl,
+    IRshr,
+    IRushr,
+    IRand,
+    IRor,
+    IRxor,
+
+    IRpreinc,
+    IRpreincs = IRpreinc + 1,
+    IRpreincscope = IRpreincs + 1,
+
+    IRpredec,
+    IRpredecs = IRpredec + 1,
+    IRpredecscope = IRpredecs + 1,
+
+    IRpostinc,
+    IRpostincs = IRpostinc + 1,
+    IRpostincscope = IRpostincs + 1,
+
+    IRpostdec,
+    IRpostdecs = IRpostdec + 1,
+    IRpostdecscope = IRpostdecs + 1,
+
+    IRnew,
+
+    IRclt,
+    IRcle,
+    IRcgt,
+    IRcge,
+    IRceq,
+    IRcne,
+    IRcid,
+    IRcnid,
+
+    IRjt,
+    IRjf,
+    IRjtb,
+    IRjfb,
+    IRjmp,
+
+    IRjlt,		// commonly appears as loop control
+    IRjle,		// commonly appears as loop control
+
+    IRjltc,		// commonly appears as loop control
+    IRjlec,		// commonly appears as loop control
+
+    IRtypeof,
+    IRinstance,
+
+    IRpush,
+    IRpop,
+
+    IRiter,
+    IRassert,
+
+    IRthrow,
+    IRtrycatch,
+    IRtryfinally,
+    IRfinallyret,
+
+    IRMAX
+}
+
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/dmdscript_tango/irstate.d	Sun Jan 24 12:34:47 2010 +0200
@@ -0,0 +1,502 @@
+
+/* Digital Mars DMDScript source code.
+ * Copyright (c) 2000-2002 by Chromium Communications
+ * D version Copyright (c) 2004-2006 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.irstate;
+
+import std.c.stdarg;
+import std.c.stdlib;
+import std.c.string;
+import std.outbuffer;
+import std.gc;
+
+import dmdscript.script;
+import dmdscript.statement;
+import dmdscript.opcodes;
+import dmdscript.ir;
+import dmdscript.identifier;
+
+// The state of the interpreter machine as seen by the code generator, not
+// the interpreter.
+
+struct IRstate
+{
+    OutBuffer codebuf;			// accumulate code here
+    Statement breakTarget;		// current statement that 'break' applies to
+    Statement continueTarget;		// current statement that 'continue' applies to
+    ScopeStatement scopeContext;	// current ScopeStatement we're inside
+    uint[] fixups;
+
+    //void next();	// close out current Block, and start a new one
+
+    uint locali = 1;		// leave location 0 as our "null"
+    uint nlocals = 1;
+
+    void ctor()
+    {
+	codebuf = new OutBuffer();
+    }
+
+    void validate()
+    {
+	assert(codebuf.offset <= codebuf.data.length);
+	if (codebuf.data.length > std.gc.capacity(codebuf.data.ptr))
+	    printf("ptr %p, length %d, capacity %d\n", codebuf.data.ptr, codebuf.data.length, std.gc.capacity(codebuf.data.ptr));
+	assert(codebuf.data.length <= std.gc.capacity(codebuf.data.ptr));
+	for (uint u = 0; u < codebuf.offset;)
+	{
+	    IR* code = cast(IR*)(codebuf.data.ptr + u);
+	    assert(code.opcode < IRMAX);
+	    u += IR.size(code.opcode) * 4;
+	}
+    }
+
+    /**********************************
+     * Allocate a block of local variables, and return an
+     * index to them.
+     */
+
+    uint alloc(uint nlocals)
+    {
+	uint n;
+
+	n = locali;
+	locali += nlocals;
+	if (locali > this.nlocals)
+	    this.nlocals = locali;
+	assert(n);
+	return n * INDEX_FACTOR;
+    }
+
+    /****************************************
+     * Release this block of n locals starting at local.
+     */
+
+    void release(uint local, uint n)
+    {
+    /+
+	local /= INDEX_FACTOR;
+	if (local + n == locali)
+	    locali = local;
+    +/
+    }
+
+    uint mark()
+    {
+	return locali;
+    }
+
+    void release(uint i)
+    {
+	//locali = i;
+    }
+
+    static uint combine(uint loc, uint opcode)
+    {
+	return (loc << 16) | opcode;
+    }
+
+    /***************************************
+     * Generate code.
+     */
+
+    void gen0(Loc loc, uint opcode)
+    {
+	codebuf.write(combine(loc, opcode));
+    }
+
+    void gen1(Loc loc, uint opcode, uint arg)
+    {
+	codebuf.reserve(2 * uint.sizeof);
+      version (all)
+      {
+	// Inline ourselves for speed (compiler doesn't do a good job)
+	uint *data = cast(uint *)(codebuf.data.ptr + codebuf.offset);
+	codebuf.offset += 2 * uint.sizeof;
+	data[0] = combine(loc, opcode);
+	data[1] = arg;
+      }
+      else
+      {
+	codebuf.write4n(combine(loc, opcode));
+	codebuf.write4n(arg);
+      }
+    }
+
+    void gen2(Loc loc, uint opcode, uint arg1, uint arg2)
+    {
+	codebuf.reserve(3 * uint.sizeof);
+      version (all)
+      {
+	// Inline ourselves for speed (compiler doesn't do a good job)
+	uint *data = cast(uint *)(codebuf.data.ptr + codebuf.offset);
+	codebuf.offset += 3 * uint.sizeof;
+	data[0] = combine(loc, opcode);
+	data[1] = arg1;
+	data[2] = arg2;
+      }
+      else
+      {
+	codebuf.write4n(combine(loc, opcode));
+	codebuf.write4n(arg1);
+	codebuf.write4n(arg2);
+      }
+    }
+
+    void gen3(Loc loc, uint opcode, uint arg1, uint arg2, uint arg3)
+    {
+	codebuf.reserve(4 * uint.sizeof);
+      version (all)
+      {
+	// Inline ourselves for speed (compiler doesn't do a good job)
+	uint *data = cast(uint *)(codebuf.data.ptr + codebuf.offset);
+	codebuf.offset += 4 * uint.sizeof;
+	data[0] = combine(loc, opcode);
+	data[1] = arg1;
+	data[2] = arg2;
+	data[3] = arg3;
+      }
+      else
+      {
+	codebuf.write4n(combine(loc, opcode));
+	codebuf.write4n(arg1);
+	codebuf.write4n(arg2);
+	codebuf.write4n(arg3);
+      }
+    }
+
+    void gen4(Loc loc, uint opcode, uint arg1, uint arg2, uint arg3, uint arg4)
+    {
+	codebuf.reserve(5 * uint.sizeof);
+      version (all)
+      {
+	// Inline ourselves for speed (compiler doesn't do a good job)
+	uint *data = cast(uint *)(codebuf.data.ptr + codebuf.offset);
+	codebuf.offset += 5 * uint.sizeof;
+	data[0] = combine(loc, opcode);
+	data[1] = arg1;
+	data[2] = arg2;
+	data[3] = arg3;
+	data[4] = arg4;
+      }
+      else
+      {
+	codebuf.write4n(combine(loc, opcode));
+	codebuf.write4n(arg1);
+	codebuf.write4n(arg2);
+	codebuf.write4n(arg3);
+	codebuf.write4n(arg4);
+      }
+    }
+
+    void gen(Loc loc, uint opcode, uint argc, ...)
+    {
+	codebuf.reserve((1 + argc) * uint.sizeof);
+	codebuf.write(combine(loc, opcode));
+	for (uint i = 1; i <= argc; i++)
+	{
+	    codebuf.write(va_arg!(uint)(_argptr));
+	}
+    }
+
+    void pops(uint npops)
+    {
+	while (npops--)
+	    gen0(0, IRpop);
+    }
+
+    /******************************
+     * Get the current "instruction pointer"
+     */
+
+    uint getIP()
+    {
+	if (!codebuf)
+	    return 0;
+	return codebuf.offset / 4;
+    }
+
+    /******************************
+     * Patch a value into the existing codebuf.
+     */
+
+    void patchJmp(uint index, uint value)
+    {
+	assert((index + 1) * 4 < codebuf.offset);
+	(cast(uint *)(codebuf.data))[index + 1] = value - index;
+    }
+
+    /*******************************
+     * Add this IP to list of jump instructions to patch.
+     */
+
+    void addFixup(uint index)
+    {
+	fixups ~= index;
+    }
+
+    /*******************************
+     * Go through the list of fixups and patch them.
+     */
+
+    void doFixups()
+    {
+	uint i;
+	uint index;
+	uint value;
+	Statement s;
+
+	for (i = 0; i < fixups.length; i++)
+	{
+	    index = fixups[i];
+	    assert((index + 1) * 4 < codebuf.offset);
+	    s = (cast(Statement *)codebuf.data)[index + 1];
+	    value = s.getTarget();
+	    patchJmp(index, value);
+	}
+    }
+
+
+    void optimize()
+    {
+	// Determine the length of the code array
+	IR *c;
+	IR *c2;
+	IR *code;
+	uint length;
+	uint i;
+
+	code = cast(IR *) codebuf.data;
+	for (c = code; c.opcode != IRend; c += IR.size(c.opcode))
+	    { }
+	length = c - code + 1;
+
+	// Allocate a bit vector for the array
+	bit[] b = new bit[length];
+
+	// Set bit for each target of a jump
+	for (c = code; c.opcode != IRend; c += IR.size(c.opcode))
+	{
+	    switch (c.opcode)
+	    {
+		case IRjf:
+		case IRjt:
+		case IRjfb:
+		case IRjtb:
+		case IRjmp:
+		case IRjlt:
+		case IRjle:
+		case IRjltc:
+		case IRjlec:
+		case IRtrycatch:
+		case IRtryfinally:
+		    //writef("set %d\n", (c - code) + (c + 1).offset);
+		    b[(c - code) + (c + 1).offset] = true;
+		    break;
+		default:
+		    break;
+	    }
+	}
+
+	// Allocate array of IR contents for locals.
+	IR*[] local;
+	IR*[] p1 = null;
+
+	// Allocate on stack for smaller arrays
+	IR** plocals;
+	if (nlocals < 128)
+	    plocals = cast(IR **)alloca(nlocals * local[0].sizeof);
+
+	if (plocals)
+	{   local = plocals[0 .. nlocals];
+	    local[] = null;
+	}
+	else
+	{   p1 = new IR*[nlocals];
+	    local = p1;
+	}
+
+	// Optimize
+	for (c = code; c.opcode != IRend; c += IR.size(c.opcode))
+	{
+	    uint offset = (c - code);
+
+	    if (b[offset])	// if target of jump
+	    {
+		// Reset contents of locals
+		local[] = null;
+	    }
+
+	    switch (c.opcode)
+	    {
+		case IRnop:
+		    break;
+
+		case IRnumber:
+		case IRstring:
+		case IRboolean:
+		    local[(c + 1).index / INDEX_FACTOR] = c;
+		    break;
+
+		case IRadd:
+		case IRsub:
+		case IRcle:
+		    local[(c + 1).index / INDEX_FACTOR] = c;
+		    break;
+
+		case IRputthis:
+		    local[(c + 1).index / INDEX_FACTOR] = c;
+		    goto Lreset;
+
+		case IRputscope:
+		    local[(c + 1).index / INDEX_FACTOR] = c;
+		    break;
+
+		case IRgetscope:
+		{
+		    Identifier* cs = (c + 2).id;
+		    IR *cimax = null;
+		    for (i = nlocals; i--; )
+		    {
+			IR *ci = local[i];
+			if (ci &&
+			    (ci.opcode == IRgetscope || ci.opcode == IRputscope) &&
+			    (ci + 2).id.value.string == cs.value.string
+			    )
+			{
+			    if (cimax)
+			    {
+				if (cimax < ci)
+				    cimax = ci;	// select most recent instruction
+			    }
+			    else
+				cimax = ci;
+			}
+		    }
+		    if (1 && cimax)
+		    {
+			//writef("IRgetscope . IRmov %d, %d\n", (c + 1).index, (cimax + 1).index);
+			c.opcode = IRmov;
+			(c + 2).index = (cimax + 1).index;
+			local[(c + 1).index / INDEX_FACTOR] = cimax;
+		    }
+		    else
+			local[(c + 1).index / INDEX_FACTOR] = c;
+		    break;
+		}
+
+		case IRnew:
+		    local[(c + 1).index / INDEX_FACTOR] = c;
+		    goto Lreset;
+
+		case IRcallscope:
+		case IRputcall:
+		case IRputcalls:
+		case IRputcallscope:
+		case IRputcallv:
+		case IRcallv:
+		    local[(c + 1).index / INDEX_FACTOR] = c;
+		    goto Lreset;
+
+		case IRmov:
+		    local[(c + 1).index / INDEX_FACTOR] = local[(c + 2).index / INDEX_FACTOR];
+		    break;
+
+		case IRput:
+		case IRpostincscope:
+		case IRaddassscope:
+		    goto Lreset;
+
+		case IRjf:
+		case IRjfb:
+		case IRjtb:
+		case IRjmp:
+		case IRjt:
+		case IRret:
+		case IRjlt:
+		case IRjle:
+		case IRjltc:
+		case IRjlec:
+		    break;
+
+		default:
+		Lreset:
+		    // Reset contents of locals
+		    local[] = null;
+		    break;
+	    }
+	}
+
+	delete p1;
+
+    //return;
+	// Remove all IRnop's
+	for (c = code; c.opcode != IRend; )
+	{
+	    uint offset;
+	    uint o;
+	    uint c2off;
+
+	    if (c.opcode == IRnop)
+	    {
+		offset = (c - code);
+		for (c2 = code; c2.opcode != IRend; c2 += IR.size(c2.opcode))
+		{
+		    switch (c2.opcode)
+		    {
+			case IRjf:
+			case IRjt:
+			case IRjfb:
+			case IRjtb:
+			case IRjmp:
+			case IRjlt:
+			case IRjle:
+			case IRjltc:
+			case IRjlec:
+			case IRnextscope:
+			case IRtryfinally:
+			case IRtrycatch:
+			    c2off = c2 - code;
+			    o = c2off + (c2 + 1).offset;
+			    if (c2off <= offset && offset < o)
+				(c2 + 1).offset--;
+			    else if (c2off > offset && o <= offset)
+				(c2 + 1).offset++;
+			    break;
+    /+
+			case IRtrycatch:
+			    o = (c2 + 1).offset;
+			    if (offset < o)
+				(c2 + 1).offset--;
+			    break;
+    +/
+			default:
+			    continue;
+		    }
+		}
+
+		length--;
+		memmove(c, c + 1, (length - offset) * uint.sizeof);
+	    }
+	    else
+		c += IR.size(c.opcode);
+	}
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/dmdscript_tango/iterator.d	Sun Jan 24 12:34:47 2010 +0200
@@ -0,0 +1,121 @@
+
+/* 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.iterator;
+
+import dmdscript.script;
+import dmdscript.dobject;
+import dmdscript.value;
+import dmdscript.property;
+
+Dobject getPrototype(Dobject o)
+{
+    version (all)
+    {
+	return o.internal_prototype;	// use internal [[Prototype]]
+    }
+    else
+    {
+	// use "prototype"
+	Value *v;
+
+	v = o.Get(TEXT_prototype);
+	if (!v || v.isPrimitive())
+	    return null;
+	o = v.toObject();
+	return o;
+    }
+}
+
+struct Iterator
+{
+    Value[] keys;
+    size_t keyindex;
+    Dobject o;
+    Dobject ostart;
+
+    debug
+    {
+	const uint ITERATOR_VALUE = 0x1992836;
+	uint foo = ITERATOR_VALUE;
+    }
+
+    invariant
+    {
+	debug assert(foo == ITERATOR_VALUE);
+    }
+
+    void ctor(Dobject o)
+    {
+	debug foo = ITERATOR_VALUE;
+	//writef("Iterator: o = %p, p = %p\n", o, p);
+	ostart = o;
+	this.o = o;
+	keys = o.proptable.table.keys.sort;
+	keyindex = 0;
+    }
+
+    Value *next()
+    {	Property* p;
+
+	//writef("Iterator::done() p = %p\n", p);
+
+	for (; ; keyindex++)
+	{
+	    while (keyindex == keys.length)
+	    {
+		delete keys;
+		o = getPrototype(o);
+		if (!o)
+		    return null;
+		keys = o.proptable.table.keys.sort;
+		keyindex = 0;
+	    }
+	    Value* key = &keys[keyindex];
+	    p = *key in o.proptable.table;
+	    if (!p)			// if no longer in property table
+		continue;
+	    if (p.attributes & DontEnum)
+		continue;
+	    else
+	    {
+		// ECMA 12.6.3
+		// Do not enumerate those properties in prototypes
+		// that are overridden
+		if (o != ostart)
+		{
+		    for (Dobject ot = ostart; ot != o; ot = getPrototype(ot))
+		    {
+			// If property p is in t, don't enumerate
+			if (*key in ot.proptable.table)
+			    goto Lcontinue;
+		    }
+		}
+		keyindex++;
+		return key; //&p.value;
+
+	    Lcontinue:
+		;
+	    }
+	}
+	assert(0);
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/dmdscript_tango/lexer.d	Sun Jan 24 12:34:47 2010 +0200
@@ -0,0 +1,1691 @@
+
+/* 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.
+ */
+
+/* Lexical Analyzer
+ */
+
+module dmdscript.lexer;
+
+import std.stdio;
+import std.string;
+import std.utf;
+import std.outbuffer;
+import std.ctype;
+import std.c.stdlib;
+
+import dmdscript.script;
+import dmdscript.text;
+import dmdscript.identifier;
+import dmdscript.scopex;
+import dmdscript.errmsgs;
+
+/* Tokens:
+	(	)
+	[	]
+	{	}
+	<	>	<=	>=	==	!=
+	===     !==
+	<<	>>	<<=	>>=	>>>	>>>=
+	+	-	+=	-=
+	*	/	%	*=	/=	%=
+	&	| 	^	&=	|=	^=
+	=	!	~
+	++	--
+	.	:	,
+	?	&&	||
+ */
+
+alias int TOK;
+
+enum
+{
+	TOKreserved,
+
+	// Other
+	TOKlparen,	TOKrparen,
+	TOKlbracket,	TOKrbracket,
+	TOKlbrace,	TOKrbrace,
+	TOKcolon,	TOKneg,
+	TOKpos,
+	TOKsemicolon,	TOKeof,
+	TOKarray,	TOKcall,
+	TOKarraylit,	TOKobjectlit,
+	TOKcomma,	TOKassert,
+
+	// Operators
+	TOKless,	TOKgreater,
+	TOKlessequal,	TOKgreaterequal,
+	TOKequal,	TOKnotequal,
+	TOKidentity,	TOKnonidentity,
+	TOKshiftleft,	TOKshiftright,
+	TOKshiftleftass, TOKshiftrightass,
+	TOKushiftright,	TOKushiftrightass,
+	TOKplus,	TOKminus,	TOKplusass,	TOKminusass,
+	TOKmultiply,	TOKdivide,	TOKpercent,
+	TOKmultiplyass,	TOKdivideass,	TOKpercentass,
+	TOKand,		TOKor,		TOKxor,
+	TOKandass,	TOKorass,	TOKxorass,
+	TOKassign,	TOKnot,		TOKtilde,
+	TOKplusplus,	TOKminusminus,
+	TOKdot,
+	TOKquestion,	TOKandand,	TOKoror,
+
+	// Leaf operators
+	TOKnumber,	TOKidentifier,	TOKstring,
+	TOKregexp,	TOKreal,
+
+	// Keywords
+	TOKbreak,	TOKcase,	TOKcontinue,
+	TOKdefault,	TOKdelete,	TOKdo,
+	TOKelse,	TOKexport,	TOKfalse,
+	TOKfor,		TOKfunction,	TOKif,
+	TOKimport,	TOKin,		TOKnew,
+	TOKnull,	TOKreturn,	TOKswitch,
+	TOKthis,	TOKtrue,	TOKtypeof,
+	TOKvar,		TOKvoid,	TOKwhile,
+	TOKwith,
+
+	// Reserved for ECMA extensions
+	TOKcatch,	TOKclass,
+	TOKconst,	TOKdebugger,
+	TOKenum,	TOKextends,
+	TOKfinally,	TOKsuper,
+	TOKthrow,	TOKtry,
+
+	// Java keywords reserved for unknown reasons
+	TOKabstract,	TOKboolean,
+	TOKbyte,	TOKchar,
+	TOKdouble,	TOKfinal,
+	TOKfloat,	TOKgoto,
+	TOKimplements,	TOKinstanceof,
+	TOKint,		TOKinterface,
+	TOKlong,	TOKnative,
+	TOKpackage,	TOKprivate,
+	TOKprotected,	TOKpublic,
+	TOKshort,	TOKstatic,
+	TOKsynchronized, TOKthrows,
+	TOKtransient,
+
+	TOKmax
+};
+
+int isoctal(dchar c)		{ return ('0' <= c && c <= '7'); }
+int isasciidigit(dchar c)	{ return ('0' <= c && c <= '9'); }
+int isasciilower(dchar c)	{ return ('a' <= c && c <= 'z'); }
+int isasciiupper(dchar c)	{ return ('A' <= c && c <= 'Z'); }
+int ishex(dchar c)		{ return
+				  ('0' <= c && c <= '9') ||
+				  ('a' <= c && c <= 'f') ||
+				  ('A' <= c && c <= 'F'); }
+
+
+/******************************************************/
+
+struct Token
+{
+    Token *next;
+    tchar *ptr;		// pointer to first character of this token within buffer
+    uint linnum;
+    TOK value;
+    tchar *sawLineTerminator;	// where we saw the last line terminator
+    union
+    {
+	number_t intvalue;
+	real_t realvalue;
+	tchar[] string;
+	Identifier *ident;
+    };
+
+    static tchar[] tochars[TOKmax];
+
+    static Token* alloc(Lexer* lex)
+    {   Token *t;
+
+	if (lex.freelist)
+	{
+	    t = lex.freelist;
+	    lex.freelist = t.next;
+	    return t;
+	}
+
+	return new Token();
+    }
+
+    void print()
+    {
+	writefln(toString());
+    }
+
+    char[] toString()
+    {   char[] p;
+
+	switch (value)
+	{
+	    case TOKnumber:
+		p = std.string.format(intvalue);
+		break;
+
+	    case TOKreal:
+		long l = cast(long)realvalue;
+		if (l == realvalue)
+		    p = std.string.format(l);
+		else
+		    p = std.string.format(realvalue);
+		break;
+
+	    case TOKstring:
+	    case TOKregexp:
+		p = string;
+		break;
+
+	    case TOKidentifier:
+		p = ident.toString();
+		break;
+
+	    default:
+		p = toString(value);
+		break;
+	}
+	return p;
+    }
+
+    static char[] toString(TOK value)
+    {   char[] p;
+
+	p = tochars[value];
+	if (!p)
+	    p = std.string.format("TOK%d", value);
+	return p;
+    }
+}
+
+
+
+
+/*******************************************************************/
+
+class Lexer
+{
+    Identifier[tchar[]] stringtable;
+    Token* freelist;
+
+    char[] sourcename;		// for error message strings
+
+    tchar[] base;		// pointer to start of buffer
+    tchar* end;			// past end of buffer
+    tchar* p;			// current character
+    uint currentline;
+    Token token;
+    OutBuffer stringbuffer;
+    int useStringtable;		// use for Identifiers
+
+    ErrInfo errinfo;		// syntax error information
+    static bool inited;
+
+    this(char[] sourcename, tchar[] base, int useStringtable)
+    {
+	//writefln("Lexer::Lexer(base = '%s')\n",base);
+	if (!inited)
+	    init();
+
+	std.c.string.memset(&token, 0, token.sizeof);
+	this.useStringtable = useStringtable;
+	this.sourcename = sourcename;
+	if (!base.length || (base[length - 1] != 0 && base[length - 1] != 0x1A))
+	    base ~= cast(tchar)0x1A;
+	this.base = base;
+	this.end  = base.ptr + base.length;
+	p = base.ptr;
+	currentline = 1;
+	freelist = null;
+    }
+
+
+    ~this()
+    {
+	//writef(L"~Lexer()\n");
+	freelist = null;
+	sourcename = null;
+	base = null;
+	end = null;
+	p = null;
+    }
+
+    dchar get(tchar* p)
+    {
+	size_t idx = p - base.ptr;
+	return std.utf.decode(base, idx);
+    }
+
+    tchar* inc(tchar* p)
+    {
+	size_t idx = p - base.ptr;
+	std.utf.decode(base, idx);
+	return base.ptr + idx;
+    }
+
+    void error(int msgnum)
+    {
+	error(errmsgtbl[msgnum]);
+    }
+
+    void error(...)
+    {
+	uint linnum = 1;
+	tchar* s;
+	tchar* slinestart;
+	tchar* slineend;
+	tchar[] buf;
+
+	//FuncLog funclog(L"Lexer.error()");
+	//writefln("TEXT START ------------\n%ls\nTEXT END ------------------", base);
+
+	// Find the beginning of the line
+	slinestart = base.ptr;
+	for (s = base.ptr; s != p; s++)
+	{
+	    if (*s == '\n')
+	    {   linnum++;
+		slinestart = s + 1;
+	    }
+	}
+
+	// Find the end of the line
+	for (;;)
+	{
+	    switch (*s)
+	    {
+		case '\n':
+		case 0:
+		case 0x1A:
+		    break;
+		default:
+		    s++;
+		    continue;
+	    }
+	    break;
+	}
+	slineend = s;
+
+	buf = std.string.format("%s(%d) : Error: ", sourcename, linnum);
+
+	void putc(dchar c)
+	{
+	    std.utf.encode(buf, c);
+	}
+
+	std.format.doFormat(&putc, _arguments, _argptr);
+
+	if (!errinfo.message)
+	{   uint len;
+
+	    errinfo.message = buf;
+	    errinfo.linnum = linnum;
+	    errinfo.charpos = p - slinestart;
+
+	    len = slineend - slinestart;
+	    errinfo.srcline = slinestart[0 .. len];
+	}
+
+	// Consume input until the end
+	while (*p != 0x1A && *p != 0)
+	    p++;
+	token.next = null;		// dump any lookahead
+
+	version (none)
+	{
+	    writefln(errinfo.message);
+	    fflush(stdout);
+	    exit(EXIT_FAILURE);
+	}
+    }
+
+    /************************************************
+     * Given source text, convert loc to a string for the corresponding line.
+     */
+
+    static tchar[] locToSrcline(tchar *src, Loc loc)
+    {
+	tchar *slinestart;
+	tchar *slineend;
+	tchar *s;
+	uint linnum = 1;
+	uint len;
+
+	if (!src)
+	    return null;
+	slinestart = src;
+	for (s = src; ; s++)
+	{
+	    switch (*s)
+	    {
+		case '\n':
+		    if (linnum == loc)
+		    {
+			slineend = s;
+			break;
+		    }
+		    slinestart = s + 1;
+		    linnum++;
+		    continue;
+
+		case 0:
+		case 0x1A:
+		    slineend = s;
+		    break;
+
+		default:
+		    continue;
+	    }
+	    break;
+	}
+
+	// Remove trailing \r's
+	while (slinestart < slineend && slineend[-1] == '\r')
+	    --slineend;
+
+	len = slineend - slinestart;
+	return slinestart[0 .. len];
+    }
+
+
+    TOK nextToken()
+    {   Token *t;
+
+	if (token.next)
+	{
+	    t = token.next;
+	    token = *t;
+	    t.next = freelist;
+	    freelist = t;
+	}
+	else
+	{
+	    scan(&token);
+	}
+	//token.print();
+	return token.value;
+    }
+
+    Token *peek(Token *ct)
+    {   Token *t;
+
+	if (ct.next)
+	    t = ct.next;
+	else
+	{
+	    t = Token.alloc(&this);
+	    scan(t);
+	    t.next = null;
+	    ct.next = t;
+	}
+	return t;
+    }
+
+    void insertSemicolon(tchar *loc)
+    {
+	// Push current token back into the input, and
+	// create a new current token that is a semicolon
+	Token *t;
+
+	t = Token.alloc(&this);
+	*t = token;
+	token.next = t;
+	token.value = TOKsemicolon;
+	token.ptr = loc;
+	token.sawLineTerminator = null;
+    }
+
+    /**********************************
+     * Horrible kludge to support disambiguating TOKregexp from TOKdivide.
+     * The idea is, if we are looking for a TOKdivide, and find instead
+     * a TOKregexp, we back up and rescan.
+     */
+
+    void rescan()
+    {
+	token.next = null;	// no lookahead
+			    // should put on freelist
+	p = token.ptr + 1;
+    }
+
+
+    /****************************
+     * Turn next token in buffer into a token.
+     */
+
+    void scan(Token *t)
+    {   tchar c;
+	dchar d;
+
+	//writefln("Lexer.scan()");
+	t.sawLineTerminator = null;
+	for (;;)
+	{
+	    t.ptr = p;
+	    //t.linnum = currentline;
+	    //writefln("p = %x",cast(uint)p);
+	    //writefln("p = %x, *p = x%02x, '%s'",cast(uint)p,*p,*p);
+	    switch (*p)
+	    {
+		case 0:
+		case 0x1A:
+		    t.value = TOKeof;		// end of file
+		    return;
+
+		case ' ':
+		case '\t':
+		case '\v':
+		case '\f':
+		case 0xA0:			// no-break space
+		    p++;
+		    continue;			// skip white space
+
+		case '\n':			// line terminator
+		    currentline++;
+		case '\r':
+		    t.sawLineTerminator = p;
+		    p++;
+		    continue;
+
+		case '"':
+		case '\'':
+		    t.string = string(*p);
+		    t.value = TOKstring;
+		    return;
+
+		case '0':  	case '1':   case '2':   case '3':   case '4':
+		case '5':  	case '6':   case '7':   case '8':   case '9':
+		    t.value = number(t);
+		    return;
+
+		case 'a':  	case 'b':   case 'c':   case 'd':   case 'e':
+		case 'f':  	case 'g':   case 'h':   case 'i':   case 'j':
+		case 'k':  	case 'l':   case 'm':   case 'n':   case 'o':
+		case 'p':  	case 'q':   case 'r':   case 's':   case 't':
+		case 'u':  	case 'v':   case 'w':   case 'x':   case 'y':
+		case 'z':
+		case 'A':  	case 'B':   case 'C':   case 'D':   case 'E':
+		case 'F':  	case 'G':   case 'H':   case 'I':   case 'J':
+		case 'K':  	case 'L':   case 'M':   case 'N':   case 'O':
+		case 'P':  	case 'Q':   case 'R':   case 'S':   case 'T':
+		case 'U':  	case 'V':   case 'W':   case 'X':   case 'Y':
+		case 'Z':
+		case '_':
+		case '$':
+		Lidentifier:
+		{   tchar[] id;
+
+		    do
+		    {
+			p = inc(p);
+			d = get(p);
+			if (d == '\\' && p[1] == 'u')
+			{
+		    Lidentifier2:
+			    id = t.ptr[0 .. p - t.ptr].dup;
+			    p++;
+			    std.utf.encode(id, unicode());
+			    for (;;)
+			    {
+				d = get(p);
+				if (d == '\\' && p[1] == 'u')
+				{
+				    p++;
+				    std.utf.encode(id, unicode());
+				}
+				else if (isalnum(d) || d == '_' || d == '$')
+				{   id ~= cast(tchar)d;
+				    p = inc(p);
+				}
+				else
+				    goto Lidentifier3;
+			    }
+			}
+		    } while (isalnum(d) || d == '_' || d == '$');   // This should be isalnum -- any Unicode letter is allowed
+		    id = t.ptr[0 .. p - t.ptr];
+		Lidentifier3:
+		    t.value = isKeyword(id);
+		    if (t.value)
+			return;
+		    if (useStringtable)
+		    {   //Identifier* i = &stringtable[id];
+			Identifier* i = id in stringtable;
+			if (!i)
+			{   stringtable[id] = Identifier.init;
+			    i = id in stringtable;
+			}
+			i.value.putVstring(id);
+			i.value.toHash();
+			t.ident = i;
+		    }
+		    else
+			t.ident = Identifier.build(id);
+		    t.value = TOKidentifier;
+		    return;
+		}
+
+		case '/':
+		    p++;
+		    c = *p;
+		    if (c == '=')
+		    {
+			p++;
+			t.value = TOKdivideass;
+			return;
+		    }
+		    else if (c == '*')
+		    {
+			p++;
+			for ( ; ; p++)
+			{
+			    c = *p;
+		    Lcomment:
+			    switch (c)
+			    {
+				case '*':
+				    p++;
+				    c = *p;
+				    if (c == '/')
+				    {
+					p++;
+					break;
+				    }
+				    goto Lcomment;
+
+				case '\n':
+				    currentline++;
+				case '\r':
+				    t.sawLineTerminator = p;
+				    continue;
+
+				case 0:
+				case 0x1A:
+				    error(ERR_BAD_C_COMMENT);
+				    t.value = TOKeof;
+				    return;
+
+				default:
+				    continue;
+			    }
+			    break;
+			}
+			continue;
+		    }
+		    else if (c == '/')
+		    {
+			for (;;)
+			{
+			    p++;
+			    switch (*p)
+			    {
+				case '\n':
+				    currentline++;
+				case '\r':
+				    t.sawLineTerminator = p;
+				    break;
+
+				case 0:
+				case 0x1A:			// end of file
+				    t.value = TOKeof;
+				    return;
+
+				default:
+				    continue;
+			    }
+			    break;
+			}
+			p++;
+			continue;
+		    }
+		    else if ((t.string = regexp()) != null)
+			t.value = TOKregexp;
+		    else
+			t.value = TOKdivide;
+		    return;
+
+		case '.':
+		    tchar *q;
+		    q = p + 1;
+		    c = *q;
+		    if (isdigit(c))
+			t.value = number(t);
+		    else
+		    {   t.value = TOKdot;
+			p = q;
+		    }
+		    return;
+
+		case '&':
+		    p++;
+		    c = *p;
+		    if (c == '=')
+		    {
+			p++;
+			t.value = TOKandass;
+		    }
+		    else if (c == '&')
+		    {
+			p++;
+			t.value = TOKandand;
+		    }
+		    else
+			t.value = TOKand;
+		    return;
+
+		case '|':
+		    p++;
+		    c = *p;
+		    if (c == '=')
+		    {
+			p++;
+			t.value = TOKorass;
+		    }
+		    else if (c == '|')
+		    {
+			p++;
+			t.value = TOKoror;
+		    }
+		    else
+			t.value = TOKor;
+		    return;
+
+		case '-':
+		    p++;
+		    c = *p;
+		    if (c == '=')
+		    {
+			p++;
+			t.value = TOKminusass;
+		    }
+		    else if (c == '-')
+		    {
+			p++;
+
+			// If the last token in the file is -. then
+			// treat it as EOF. This is to accept broken
+			// scripts that forgot to protect the closing -.
+			// with a // comment.
+			if (*p == '>')
+			{
+			    // Scan ahead to see if it's the last token
+			    tchar *q;
+
+			    q = p;
+			    for (;;)
+			    {
+				switch (*++q)
+				{
+				    case 0:
+				    case 0x1A:
+					t.value = TOKeof;
+					p = q;
+					return;
+
+				    case ' ':
+				    case '\t':
+				    case '\v':
+				    case '\f':
+				    case '\n':
+				    case '\r':
+				    case 0xA0:		// no-break space
+					continue;
+
+				    default:
+					assert(0);
+				}
+				break;
+			    }
+			}
+			t.value = TOKminusminus;
+		    }
+		    else
+			t.value = TOKminus;
+		    return;
+
+		case '+':
+		    p++;
+		    c = *p;
+		    if (c == '=')
+		    {   p++;
+			t.value = TOKplusass;
+		    }
+		    else if (c == '+')
+		    {   p++;
+			t.value = TOKplusplus;
+		    }
+		    else
+			t.value = TOKplus;
+		    return;
+
+		case '<':
+		    p++;
+		    c = *p;
+		    if (c == '=')
+		    {   p++;
+			t.value = TOKlessequal;
+		    }
+		    else if (c == '<')
+		    {   p++;
+			c = *p;
+			if (c == '=')
+			{   p++;
+			    t.value = TOKshiftleftass;
+			}
+			else
+			    t.value = TOKshiftleft;
+		    }
+		    else if (c == '!' && p[1] == '-' && p[2] == '-')
+		    {   // Special comment to end of line
+			p += 2;
+			for (;;)
+			{
+			    p++;
+			    switch (*p)
+			    {
+				case '\n':
+				    currentline++;
+				case '\r':
+				    t.sawLineTerminator = p;
+				    break;
+
+				case 0:
+				case 0x1A:			// end of file
+				    error(ERR_BAD_HTML_COMMENT);
+				    t.value = TOKeof;
+				    return;
+
+				default:
+				    continue;
+			    }
+			    break;
+			}
+			p++;
+			continue;
+		    }
+		    else
+			t.value = TOKless;
+		    return;
+
+		case '>':
+		    p++;
+		    c = *p;
+		    if (c == '=')
+		    {   p++;
+			t.value = TOKgreaterequal;
+		    }
+		    else if (c == '>')
+		    {   p++;
+			c = *p;
+			if (c == '=')
+			{   p++;
+			    t.value = TOKshiftrightass;
+			}
+			else if (c == '>')
+			{   p++;
+			    c = *p;
+			    if (c == '=')
+			    {   p++;
+				t.value = TOKushiftrightass;
+			    }
+			    else
+				t.value = TOKushiftright;
+			}
+			else
+			    t.value = TOKshiftright;
+		    }
+		    else
+			t.value = TOKgreater;
+		    return;
+
+		case '(': p++; t.value = TOKlparen;    return;
+		case ')': p++; t.value = TOKrparen;    return;
+		case '[': p++; t.value = TOKlbracket;  return;
+		case ']': p++; t.value = TOKrbracket;  return;
+		case '{': p++; t.value = TOKlbrace;    return;
+		case '}': p++; t.value = TOKrbrace;    return;
+		case '~': p++; t.value = TOKtilde;     return;
+		case '?': p++; t.value = TOKquestion;  return;
+		case ',': p++; t.value = TOKcomma;     return;
+		case ';': p++; t.value = TOKsemicolon; return;
+		case ':': p++; t.value = TOKcolon;     return;
+
+		case '*':
+		    p++;
+		    c = *p;
+		    if (c == '=')
+		    {   p++;
+			t.value = TOKmultiplyass;
+		    }
+		    else
+			t.value = TOKmultiply;
+		    return;
+
+		case '%':
+		    p++;
+		    c = *p;
+		    if (c == '=')
+		    {   p++;
+			t.value = TOKpercentass;
+		    }
+		    else
+			t.value = TOKpercent;
+		    return;
+
+		case '^':
+		    p++;
+		    c = *p;
+		    if (c == '=')
+		    {   p++;
+			t.value = TOKxorass;
+		    }
+		    else
+			t.value = TOKxor;
+		    return;
+
+		case '=':
+		    p++;
+		    c = *p;
+		    if (c == '=')
+		    {   p++;
+			c = *p;
+			if (c == '=')
+			{   p++;
+			    t.value = TOKidentity;
+			}
+			else
+			    t.value = TOKequal;
+		    }
+		    else
+			t.value = TOKassign;
+		    return;
+
+		case '!':
+		    p++;
+		    c = *p;
+		    if (c == '=')
+		    {   p++;
+			c = *p;
+			if (c == '=')
+			{   p++;
+			    t.value = TOKnonidentity;
+			}
+			else
+			    t.value = TOKnotequal;
+		    }
+		    else
+			t.value = TOKnot;
+		    return;
+
+		case '\\':
+		    if (p[1] == 'u')
+		    {
+			// \uXXXX starts an identifier
+			goto Lidentifier2;
+		    }
+		default:
+		    d = get(p);
+		    if (isalpha(d))         // This should be isalpha -- any Unicode letter
+			goto Lidentifier;
+		    else
+		    {
+			if (isprint(d))
+			    error(errmsgtbl[ERR_BAD_CHAR_C], d);
+			else
+			    error(errmsgtbl[ERR_BAD_CHAR_X], d);
+		    }
+		    continue;
+	    }
+	}
+    }
+
+    /*******************************************
+     * Parse escape sequence.
+     */
+
+    dchar escapeSequence()
+    {   uint c;
+	int n;
+
+	c = *p;
+	p++;
+	switch (c)
+	{
+	    case '\'':
+	    case '"':
+	    case '?':
+	    case '\\':
+		    break;
+	    case 'a':
+		    c = 7;
+		    break;
+	    case 'b':
+		    c = 8;
+		    break;
+	    case 'f':
+		    c = 12;
+		    break;
+	    case 'n':
+		    c = 10;
+		    break;
+	    case 'r':
+		    c = 13;
+		    break;
+	    case 't':
+		    c = 9;
+		    break;
+
+	    case 'v':
+		    version (JSCRIPT_ESCAPEV_BUG)
+		    {
+		    }
+		    else
+		    {
+			c = 11;
+		    }
+		    break;
+
+	    case 'x':
+		    c = *p;
+		    p++;
+		    if (ishex(c))
+		    {   uint v;
+
+			n = 0;
+			v = 0;
+			for (;;)
+			{
+			    if (isdigit(c))
+				c -= '0';
+			    else if (isasciilower(c))
+				c -= 'a' - 10;
+			    else    // 'A' <= c && c <= 'Z'
+				c -= 'A' - 10;
+			    v = v * 16 + c;
+			    c = *p;
+			    if (++n >= 2 || !ishex(c))
+				break;
+			    p++;
+			}
+			if (n == 1)
+			    error(ERR_BAD_HEX_SEQUENCE);
+			c = v;
+		    }
+		    else
+			error(errmsgtbl[ERR_UNDEFINED_ESC_SEQUENCE], c);
+		    break;
+
+	    default:
+		    if (c > 0x7F)
+		    {   p--;
+			c = get(p);
+			p = inc(p);
+		    }
+		    if (isoctal(c))
+		    {   uint v;
+
+			n = 0;
+			v = 0;
+			for (;;)
+			{
+			    v = v * 8 + (c - '0');
+			    c = *p;
+			    if (++n >= 3 || !isoctal(c))
+				break;
+			    p++;
+			}
+			c = v;
+		    }
+		    // Don't throw error, just accept it
+		    //error("undefined escape sequence \\%c\n",c);
+		    break;
+	}
+	return c;
+    }
+
+    /**************************************
+     */
+
+    tchar[] string(tchar quote)
+    {   tchar c;
+	dchar d;
+	tchar[] stringbuffer;
+
+	//printf("Lexer.string('%c')\n", quote);
+	p++;
+	for (;;)
+	{
+	    c = *p;
+	    switch (c)
+	    {
+		case '"':
+		case '\'':
+		    p++;
+		    if (c == quote)
+			return stringbuffer;
+		    break;
+
+		case '\\':
+		    p++;
+		    if (*p == 'u')
+			d = unicode();
+		    else
+			d = escapeSequence();
+		    std.utf.encode(stringbuffer, d);
+		    continue;
+
+		case '\n':
+		case '\r':
+		    p++;
+		    error(errmsgtbl[ERR_STRING_NO_END_QUOTE], quote);
+		    return null;
+
+		case 0:
+		case 0x1A:
+		    error(ERR_UNTERMINATED_STRING);
+		    return null;
+
+		default:
+		    p++;
+		    break;
+	    }
+	    stringbuffer ~= c;
+	}
+	assert(0);
+    }
+
+    /**************************************
+     * Scan regular expression. Return null with buffer
+     * pointer intact if it is not a regexp.
+     */
+
+    tchar[] regexp()
+    {   tchar c;
+	tchar* s;
+	tchar* start;
+
+	/*
+	    RegExpLiteral:  RegExpBody RegExpFlags
+	      RegExpFlags:
+		  empty
+	       |  RegExpFlags ContinuingIdentifierCharacter
+	      RegExpBody:  / RegExpFirstChar RegExpChars /
+	      RegExpFirstChar: 
+		  OrdinaryRegExpFirstChar
+	       |  \ NonTerminator
+	      OrdinaryRegExpFirstChar:  NonTerminator except \ | / | *
+	      RegExpChars:
+		  empty
+	       |  RegExpChars RegExpChar
+	      RegExpChar:
+		  OrdinaryRegExpChar
+	       |  \ NonTerminator
+	      OrdinaryRegExpChar: NonTerminator except \ | /
+	 */
+
+	//writefln("Lexer.regexp()\n");
+	start = p - 1;
+	s = p;
+
+	// Do RegExpBody
+	for (;;)
+	{
+	    c = *s;
+	    s++;
+	    switch (c)
+	    {
+		case '\\':
+		    if (s == p)
+			return null;
+		    c = *s;
+		    switch (c)
+		    {
+			case '\r':
+			case '\n':		// new line
+			case 0:			// end of file
+			case 0x1A:		// end of file
+			    return null;	// not a regexp
+			default:
+			    break;
+		    }
+		    s++;
+		    continue;
+
+		case '/':
+		    if (s == p + 1)
+			return null;
+		    break;
+
+		case '\r':
+		case '\n':			// new line
+		case 0:				// end of file
+		case 0x1A:			// end of file
+		    return null;		// not a regexp
+
+		case '*':
+		    if (s == p + 1)
+			return null;
+		default:
+		    continue;
+	    }
+	    break;
+	}
+
+	// Do RegExpFlags
+	for (;;)
+	{
+	    c = *s;
+	    if (isalnum(c) || c == '_' || c == '$')
+	    {
+		s++;
+	    }
+	    else
+		break;
+	}
+
+	// Finish pattern & return it
+	p = s;
+	return start[0 .. s - start].dup;
+    }
+
+    /***************************************
+     */
+
+    dchar unicode()
+    {
+	dchar value;
+	uint n;
+	dchar c;
+
+	value = 0;
+	p++;
+	for (n = 0; n < 4; n++)
+	{
+	    c = *p;
+	    if (!ishex(c))
+	    {   error(ERR_BAD_U_SEQUENCE);
+		break;
+	    }
+	    p++;
+	    if (isdigit(c))
+		c -= '0';
+	    else if (isasciilower(c))
+		c -= 'a' - 10;
+	    else    // 'A' <= c && c <= 'Z'
+		c -= 'A' - 10;
+	    value <<= 4;
+	    value |= c;
+	}
+	return value;
+    }
+
+    /********************************************
+     * Read a number.
+     */
+
+    TOK number(Token *t)
+    {   tchar *start;
+	number_t intvalue;
+	real realvalue;
+	int base = 10;
+	tchar c;
+
+	start = p;
+	for (;;)
+	{
+	    c = *p;
+	    p++;
+	    switch (c)
+	    {
+		case '0':
+		    // ECMA grammar implies that numbers with leading 0
+		    // like 015 are illegal. But other scripts allow them.
+		    if (p - start == 1)		// if leading 0
+			base = 8;
+		case '1': case '2': case '3': case '4': case '5':
+		case '6': case '7':
+		    break;
+
+		case '8': case '9':			// decimal digits
+		    if (base == 8)			// and octal base
+			base = 10;			// means back to decimal base
+		    break;
+
+		default:
+		    p--;
+		Lnumber:
+		    if (base == 0)
+			base = 10;
+		    intvalue = 0;
+		    foreach (tchar v; start[0 .. p - start])
+		    {
+			if ('0' <= v && v <= '9')
+			    v -= '0';
+			else if ('a' <= v && v <= 'f')
+			    v -= ('a' - 10);
+			else if ('A' <= v && v <= 'F')
+			    v -= ('A' - 10);
+			else
+			    assert(0);
+			assert(v < base);
+			if ((number_t.max - v) / base < intvalue)
+			{
+			    realvalue = 0;
+			    foreach (tchar w; start[0 .. p - start])
+			    {
+				if ('0' <= w && w <= '9')
+				    w -= '0';
+				else if ('a' <= w && w <= 'f')
+				    w -= ('a' - 10);
+				else if ('A' <= w && w <= 'F')
+				    w -= ('A' - 10);
+				else
+				    assert(0);
+				realvalue *= base;
+				realvalue += v;
+			    }
+			    t.realvalue = realvalue;
+			    return TOKreal;
+			}
+			intvalue *= base;
+			intvalue += v;
+		    }
+		    t.realvalue = cast(double)intvalue;
+		    return TOKreal;
+
+		case 'x':
+		case 'X':
+		    if (p - start != 2 || !ishex(*p))
+			goto Lerr;
+		    do
+			p++;
+		    while (ishex(*p));
+		    start += 2;
+		    base = 16;
+		    goto Lnumber;
+
+		case '.':
+		    while (isdigit(*p))
+			p++;
+		    if (*p == 'e' || *p == 'E')
+		    {   p++;
+			goto Lexponent;
+		    }
+		    goto Ldouble;
+
+		case 'e':
+		case 'E':
+		Lexponent:
+		    if (*p == '+' || *p == '-')
+			p++;
+		    if (!isdigit(*p))
+			goto Lerr;
+		    do
+			p++;
+		    while (isdigit(*p));
+		    goto Ldouble;
+
+		Ldouble:
+		    // convert double
+		    realvalue = std.c.stdlib.strtod(toStringz(start[0 .. p - start]), null);
+		    t.realvalue = realvalue;
+		    return TOKreal;
+	    }
+	}
+
+    Lerr:
+	error(ERR_UNRECOGNIZED_N_LITERAL);
+	return TOKeof;
+    }
+
+    static TOK isKeyword(tchar[] s)
+    {
+      if (s[0] >= 'a' && s[0] <= 'w')
+	switch (s.length)
+	{
+	    case 2:
+		if (s[0] == 'i')
+		{
+		    if (s[1] == 'f')
+			return TOKif;
+		    if (s[1] == 'n')
+			return TOKin;
+		}
+		else if (s[0] == 'd' && s[1] == 'o')
+		    return TOKdo;
+		break;
+
+	    case 3:
+		switch (s[0])
+		{
+		    case 'f':
+			if (s[1] == 'o' && s[2] == 'r')
+			    return TOKfor;
+			break;
+		    case 'i':
+			if (s[1] == 'n' && s[2] == 't')
+			    return TOKint;
+			break;
+		    case 'n':
+			if (s[1] == 'e' && s[2] == 'w')
+			    return TOKnew;
+			break;
+		    case 't':
+			if (s[1] == 'r' && s[2] == 'y')
+			    return TOKtry;
+			break;
+		    case 'v':
+			if (s[1] == 'a' && s[2] == 'r')
+			    return TOKvar;
+			break;
+		    default:
+			break;
+		}
+		break;
+
+	    case 4:
+		switch (s[0])
+		{
+		    case 'b':
+			if (s[1] == 'y' && s[2] == 't' && s[3] == 'e')
+			    return TOKbyte;
+			break;
+		    case 'c':
+			if (s[1] == 'a' && s[2] == 's' && s[3] == 'e')
+			    return TOKcase;
+			if (s[1] == 'h' && s[2] == 'a' && s[3] == 'r')
+			    return TOKchar;
+			break;
+		    case 'e':
+			if (s[1] == 'l' && s[2] == 's' && s[3] == 'e')
+			    return TOKelse;
+			if (s[1] == 'n' && s[2] == 'u' && s[3] == 'm')
+			    return TOKenum;
+			break;
+		    case 'g':
+			if (s[1] == 'o' && s[2] == 't' && s[3] == 'o')
+			    return TOKgoto;
+			break;
+		    case 'l':
+			if (s[1] == 'o' && s[2] == 'n' && s[3] == 'g')
+			    return TOKlong;
+			break;
+		    case 'n':
+			if (s[1] == 'u' && s[2] == 'l' && s[3] == 'l')
+			    return TOKnull;
+			break;
+		    case 't':
+			if (s[1] == 'h' && s[2] == 'i' && s[3] == 's')
+			    return TOKthis;
+			if (s[1] == 'r' && s[2] == 'u' && s[3] == 'e')
+			    return TOKtrue;
+			break;
+		    case 'w':
+			if (s[1] == 'i' && s[2] == 't' && s[3] == 'h')
+			    return TOKwith;
+			break;
+		    case 'v':
+			if (s[1] == 'o' && s[2] == 'i' && s[3] == 'd')
+			    return TOKvoid;
+			break;
+		    default:
+			break;
+		}
+		break;
+
+	    case 5:
+		switch (s)
+		{
+		    case "break":		return TOKbreak;
+		    case "catch":		return TOKcatch;
+		    case "class":		return TOKclass;
+		    case "const":		return TOKconst;
+		    case "false":		return TOKfalse;
+		    case "final":		return TOKfinal;
+		    case "float":		return TOKfloat;
+		    case "short":		return TOKshort;
+		    case "super":		return TOKsuper;
+		    case "throw":		return TOKthrow;
+		    case "while":		return TOKwhile;
+		    default:
+			break;
+		}
+		break;
+
+	    case 6:
+		switch (s)
+		{
+		    case "delete":		return TOKdelete;
+		    case "double":		return TOKdouble;
+		    case "export":		return TOKexport;
+		    case "import":		return TOKimport;
+		    case "native":		return TOKnative;
+		    case "public":		return TOKpublic;
+		    case "return":		return TOKreturn;
+		    case "static":		return TOKstatic;
+		    case "switch":		return TOKswitch;
+		    case "throws":		return TOKthrows;
+		    case "typeof":		return TOKtypeof;
+		    default:
+			break;
+		}
+		break;
+
+	    case 7:
+		switch (s)
+		{
+		    case "boolean":		return TOKboolean;
+		    case "default":		return TOKdefault;
+		    case "extends":		return TOKextends;
+		    case "finally":		return TOKfinally;
+		    case "package":		return TOKpackage;
+		    case "private":		return TOKprivate;
+		    default:
+			break;
+		}
+		break;
+
+	    case 8:
+		switch (s)
+		{
+		    case "abstract":	return TOKabstract;
+		    case "continue":	return TOKcontinue;
+		    case "debugger":	return TOKdebugger;
+		    case "function":	return TOKfunction;
+		    default:
+			break;
+		}
+		break;
+
+	    case 9:
+		switch (s)
+		{
+		    case "interface":	return TOKinterface;
+		    case "protected":	return TOKprotected;
+		    case "transient":	return TOKtransient;
+		    default:
+			break;
+		}
+		break;
+
+	    case 10:
+		switch (s)
+		{
+		    case "implements":	return TOKimplements;
+		    case "instanceof":	return TOKinstanceof;
+		    default:
+			break;
+		}
+		break;
+
+	    case 12:
+		if (s == "synchronized")	return TOKsynchronized;
+		break;
+
+	    default:
+		break;
+	}
+	return TOKreserved;		// not a keyword
+    }
+}
+
+
+/****************************************
+ */
+
+struct Keyword
+{   tchar[] name;
+    TOK value;
+}
+
+static Keyword keywords[] =
+[
+//    {	"",		TOK		},
+
+    {	"break",	TOKbreak	},
+    {	"case",		TOKcase		},
+    {	"continue",	TOKcontinue	},
+    {	"default",	TOKdefault	},
+    {	"delete",	TOKdelete	},
+    {	"do",		TOKdo		},
+    {	"else",		TOKelse		},
+    {	"export",	TOKexport	},
+    {	"false",	TOKfalse	},
+    {	"for",		TOKfor		},
+    {	"function",	TOKfunction	},
+    {	"if",		TOKif		},
+    {	"import",	TOKimport	},
+    {	"in",		TOKin		},
+    {	"new",		TOKnew		},
+    {	"null",		TOKnull		},
+    {	"return",	TOKreturn	},
+    {	"switch",	TOKswitch	},
+    {	"this",		TOKthis		},
+    {	"true",		TOKtrue		},
+    {	"typeof",	TOKtypeof	},
+    {	"var",		TOKvar		},
+    {	"void",		TOKvoid		},
+    {	"while",	TOKwhile	},
+    {	"with",		TOKwith		},
+
+    {	"catch",	TOKcatch	},
+    {	"class",	TOKclass	},
+    {	"const",	TOKconst	},
+    {	"debugger",	TOKdebugger	},
+    {	"enum",		TOKenum		},
+    {	"extends",	TOKextends	},
+    {	"finally",	TOKfinally	},
+    {	"super",	TOKsuper	},
+    {	"throw",	TOKthrow	},
+    {	"try",		TOKtry		},
+
+    {	"abstract",	TOKabstract	},
+    {	"boolean",	TOKboolean	},
+    {	"byte",		TOKbyte		},
+    {	"char",		TOKchar		},
+    {	"double",	TOKdouble	},
+    {	"final",	TOKfinal	},
+    {	"float",	TOKfloat	},
+    {	"goto",		TOKgoto		},
+    {	"implements",	TOKimplements	},
+    {	"instanceof",	TOKinstanceof	},
+    {	"int",		TOKint		},
+    {	"interface",	TOKinterface	},
+    {	"long",		TOKlong		},
+    {	"native",	TOKnative	},
+    {	"package",	TOKpackage	},
+    {	"private",	TOKprivate	},
+    {	"protected",	TOKprotected	},
+    {	"public",	TOKpublic	},
+    {	"short",	TOKshort	},
+    {	"static",	TOKstatic	},
+    {	"synchronized",	TOKsynchronized	},
+    {	"throws",	TOKthrows	},
+    {	"transient",	TOKtransient	},
+];
+
+void init()
+{
+    uint u;
+    TOK v;
+
+    for (u = 0; u < keywords.length; u++)
+    {	tchar[] s;
+
+	//writefln("keyword[%d] = '%s'", u, keywords[u].name);
+	s = keywords[u].name;
+	v = keywords[u].value;
+
+	//writefln("tochars[%d] = '%s'", v, s);
+	Token.tochars[v] = s;
+    }
+
+    Token.tochars[TOKreserved]		= "reserved";
+    Token.tochars[TOKeof]		= "EOF";
+    Token.tochars[TOKlbrace]		= "{";
+    Token.tochars[TOKrbrace]		= "}";
+    Token.tochars[TOKlparen]		= "(";
+    Token.tochars[TOKrparen]		= "";
+    Token.tochars[TOKlbracket]		= "[";
+    Token.tochars[TOKrbracket]		= "]";
+    Token.tochars[TOKcolon]		= ":";
+    Token.tochars[TOKsemicolon]	= ";";
+    Token.tochars[TOKcomma]		= ",";
+    Token.tochars[TOKor]		= "|";
+    Token.tochars[TOKorass]		= "|=";
+    Token.tochars[TOKxor]		= "^";
+    Token.tochars[TOKxorass]		= "^=";
+    Token.tochars[TOKassign]		= "=";
+    Token.tochars[TOKless]		= "<";
+    Token.tochars[TOKgreater]		= ">";
+    Token.tochars[TOKlessequal]	= "<=";
+    Token.tochars[TOKgreaterequal]	= ">=";
+    Token.tochars[TOKequal]		= "==";
+    Token.tochars[TOKnotequal]		= "!=";
+    Token.tochars[TOKidentity]		= "===";
+    Token.tochars[TOKnonidentity]	= "!==";
+    Token.tochars[TOKshiftleft]	= "<<";
+    Token.tochars[TOKshiftright]	= ">>";
+    Token.tochars[TOKushiftright]	= ">>>";
+    Token.tochars[TOKplus]		= "+";
+    Token.tochars[TOKplusass]		= "+=";
+    Token.tochars[TOKminus]		= "-";
+    Token.tochars[TOKminusass]		= "-=";
+    Token.tochars[TOKmultiply]		= "*";
+    Token.tochars[TOKmultiplyass]	= "*=";
+    Token.tochars[TOKdivide]		= "/";
+    Token.tochars[TOKdivideass]	= "/=";
+    Token.tochars[TOKpercent]		= "%";
+    Token.tochars[TOKpercentass]	= "%=";
+    Token.tochars[TOKand]		= "&";
+    Token.tochars[TOKandass]		= "&=";
+    Token.tochars[TOKdot]		= ".";
+    Token.tochars[TOKquestion]		= "?";
+    Token.tochars[TOKtilde]		= "~";
+    Token.tochars[TOKnot]		= "!";
+    Token.tochars[TOKandand]		= "&&";
+    Token.tochars[TOKoror]		= "||";
+    Token.tochars[TOKplusplus]		= "++";
+    Token.tochars[TOKminusminus]	= "--";
+    Token.tochars[TOKcall]		= "CALL";
+
+    Lexer.inited = true;
+}
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/dmdscript_tango/license/gpl.txt	Sun Jan 24 12:34:47 2010 +0200
@@ -0,0 +1,248 @@
+		    GNU GENERAL PUBLIC LICENSE
+		     Version 1, February 1989
+
+ Copyright (C) 1989 Free Software Foundation, Inc.
+                59 Temple Place, Suite 330, Boston, MA 02111-1307, USA
+ Everyone is permitted to copy and distribute verbatim copies
+ of this license document, but changing it is not allowed.
+
+			    Preamble
+
+  The license agreements of most software companies try to keep users
+at the mercy of those companies.  By contrast, our General Public
+License is intended to guarantee your freedom to share and change free
+software--to make sure the software is free for all its users.  The
+General Public License applies to the Free Software Foundation's
+software and to any other program whose authors commit to using it.
+You can use it for your programs, too.
+
+  When we speak of free software, we are referring to freedom, not
+price.  Specifically, the General Public License is designed to make
+sure that you have the freedom to give away or sell copies of free
+software, that you receive source code or can get it if you want it,
+that you can change the software or use pieces of it in new free
+programs; and that you know you can do these things.
+
+  To protect your rights, we need to make restrictions that forbid
+anyone to deny you these rights or to ask you to surrender the rights.
+These restrictions translate to certain responsibilities for you if you
+distribute copies of the software, or if you modify it.
+
+  For example, if you distribute copies of a such a program, whether
+gratis or for a fee, you must give the recipients all the rights that
+you have.  You must make sure that they, too, receive or can get the
+source code.  And you must tell them their rights.
+
+  We protect your rights with two steps: (1) copyright the software, and
+(2) offer you this license which gives you legal permission to copy,
+distribute and/or modify the software.
+
+  Also, for each author's protection and ours, we want to make certain
+that everyone understands that there is no warranty for this free
+software.  If the software is modified by someone else and passed on, we
+want its recipients to know that what they have is not the original, so
+that any problems introduced by others will not reflect on the original
+authors' reputations.
+
+  The precise terms and conditions for copying, distribution and
+modification follow.
+
+		    GNU GENERAL PUBLIC LICENSE
+   TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
+
+  0. This License Agreement applies to any program or other work which
+contains a notice placed by the copyright holder saying it may be
+distributed under the terms of this General Public License.  The
+"Program", below, refers to any such program or work, and a "work based
+on the Program" means either the Program or any work containing the
+Program or a portion of it, either verbatim or with modifications.  Each
+licensee is addressed as "you".
+
+  1. You may copy and distribute verbatim copies of the Program's source
+code as you receive it, in any medium, provided that you conspicuously and
+appropriately publish on each copy an appropriate copyright notice and
+disclaimer of warranty; keep intact all the notices that refer to this
+General Public License and to the absence of any warranty; and give any
+other recipients of the Program a copy of this General Public License
+along with the Program.  You may charge a fee for the physical act of
+transferring a copy.
+
+  2. You may modify your copy or copies of the Program or any portion of
+it, and copy and distribute such modifications under the terms of Paragraph
+1 above, provided that you also do the following:
+
+    a) cause the modified files to carry prominent notices stating that
+    you changed the files and the date of any change; and
+
+    b) cause the whole of any work that you distribute or publish, that
+    in whole or in part contains the Program or any part thereof, either
+    with or without modifications, to be licensed at no charge to all
+    third parties under the terms of this General Public License (except
+    that you may choose to grant warranty protection to some or all
+    third parties, at your option).
+
+    c) If the modified program normally reads commands interactively when
+    run, you must cause it, when started running for such interactive use
+    in the simplest and most usual way, to print or display an
+    announcement including an appropriate copyright notice and a notice
+    that there is no warranty (or else, saying that you provide a
+    warranty) and that users may redistribute the program under these
+    conditions, and telling the user how to view a copy of this General
+    Public License.
+
+    d) You may charge a fee for the physical act of transferring a
+    copy, and you may at your option offer warranty protection in
+    exchange for a fee.
+
+Mere aggregation of another independent work with the Program (or its
+derivative) on a volume of a storage or distribution medium does not bring
+the other work under the scope of these terms.
+
+  3. You may copy and distribute the Program (or a portion or derivative of
+it, under Paragraph 2) in object code or executable form under the terms of
+Paragraphs 1 and 2 above provided that you also do one of the following:
+
+    a) accompany it with the complete corresponding machine-readable
+    source code, which must be distributed under the terms of
+    Paragraphs 1 and 2 above; or,
+
+    b) accompany it with a written offer, valid for at least three
+    years, to give any third party free (except for a nominal charge
+    for the cost of distribution) a complete machine-readable copy of the
+    corresponding source code, to be distributed under the terms of
+    Paragraphs 1 and 2 above; or,
+
+    c) accompany it with the information you received as to where the
+    corresponding source code may be obtained.  (This alternative is
+    allowed only for noncommercial distribution and only if you
+    received the program in object code or executable form alone.)
+
+Source code for a work means the preferred form of the work for making
+modifications to it.  For an executable file, complete source code means
+all the source code for all modules it contains; but, as a special
+exception, it need not include source code for modules which are standard
+libraries that accompany the operating system on which the executable
+file runs, or for standard header files or definitions files that
+accompany that operating system.
+
+  4. You may not copy, modify, sublicense, distribute or transfer the
+Program except as expressly provided under this General Public License.
+Any attempt otherwise to copy, modify, sublicense, distribute or transfer
+the Program is void, and will automatically terminate your rights to use
+the Program under this License.  However, parties who have received
+copies, or rights to use copies, from you under this General Public
+License will not have their licenses terminated so long as such parties
+remain in full compliance.
+
+  5. By copying, distributing or modifying the Program (or any work based
+on the Program) you indicate your acceptance of this license to do so,
+and all its terms and conditions.
+
+  6. Each time you redistribute the Program (or any work based on the
+Program), the recipient automatically receives a license from the original
+licensor to copy, distribute or modify the Program subject to these
+terms and conditions.  You may not impose any further restrictions on the
+recipients' exercise of the rights granted herein.
+
+  7. The Free Software Foundation may publish revised and/or new versions
+of the General Public License from time to time.  Such new versions will
+be similar in spirit to the present version, but may differ in detail to
+address new problems or concerns.
+
+Each version is given a distinguishing version number.  If the Program
+specifies a version number of the license which applies to it and "any
+later version", you have the option of following the terms and conditions
+either of that version or of any later version published by the Free
+Software Foundation.  If the Program does not specify a version number of
+the license, you may choose any version ever published by the Free Software
+Foundation.
+
+  8. If you wish to incorporate parts of the Program into other free
+programs whose distribution conditions are different, write to the author
+to ask for permission.  For software which is copyrighted by the Free
+Software Foundation, write to the Free Software Foundation; we sometimes
+make exceptions for this.  Our decision will be guided by the two goals
+of preserving the free status of all derivatives of our free software and
+of promoting the sharing and reuse of software generally.
+
+			    NO WARRANTY
+
+  9. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
+FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW.  EXCEPT WHEN
+OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
+PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
+OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.  THE ENTIRE RISK AS
+TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU.  SHOULD THE
+PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
+REPAIR OR CORRECTION.
+
+  10. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
+WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
+REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
+INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
+OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
+TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
+YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
+PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGES.
+
+		     END OF TERMS AND CONDITIONS
+
+	Appendix: How to Apply These Terms to Your New Programs
+
+  If you develop a new program, and you want it to be of the greatest
+possible use to humanity, the best way to achieve this is to make it
+free software which everyone can redistribute and change under these
+terms.
+
+  To do so, attach the following notices to the program.  It is safest to
+attach them to the start of each source file to most effectively convey
+the exclusion of warranty; and each file should have at least the
+"copyright" line and a pointer to where the full notice is found.
+
+    <one line to give the program's name and a brief idea of what it does.>
+    Copyright (C) 19yy  <name of author>
+
+    This program is free software; you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation; either version 1, or (at your option)
+    any later version.
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with this program; if not, write to the Free Software Foundation,
+    Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA.
+
+Also add information on how to contact you by electronic and paper mail.
+
+If the program is interactive, make it output a short notice like this
+when it starts in an interactive mode:
+
+    Gnomovision version 69, Copyright (C) 19xx name of author
+    Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
+    This is free software, and you are welcome to redistribute it
+    under certain conditions; type `show c' for details.
+
+The hypothetical commands `show w' and `show c' should show the
+appropriate parts of the General Public License.  Of course, the
+commands you use may be called something other than `show w' and `show
+c'; they could even be mouse-clicks or menu items--whatever suits your
+program.
+
+You should also get your employer (if you work as a programmer) or your
+school, if any, to sign a "copyright disclaimer" for the program, if
+necessary.  Here a sample; alter the names:
+
+  Yoyodyne, Inc., hereby disclaims all copyright interest in the
+  program `Gnomovision' (a program to direct compilers to make passes
+  at assemblers) written by James Hacker.
+
+  <signature of Ty Coon>, 1 April 1989
+  Ty Coon, President of Vice
+
+That's all there is to it!
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/dmdscript_tango/license/saaadel.readme.txt	Sun Jan 24 12:34:47 2010 +0200
@@ -0,0 +1,8 @@
+This project is a modification of the original DMDScript (on D-language).
+This version is not used Phobos library, and instead used Tango.
+The project comes as is. I am not responsible for any problems arising 
+  from the use of it. Use at your own risk.
+
+See gpl.txt file for license.
+
+Original code written by Digital Mars (digitalmars.com)
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/dmdscript_tango/opcodes.d	Sun Jan 24 12:34:47 2010 +0200
@@ -0,0 +1,2672 @@
+
+/* Digital Mars DMDScript source code.
+ * Copyright (c) 2000-2002 by Chromium Communications
+ * D version Copyright (c) 2004-2006 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.opcodes;
+
+import std.stdio;
+import std.string;
+
+import dmdscript.script;
+import dmdscript.dobject;
+import dmdscript.statement;
+import dmdscript.functiondefinition;
+import dmdscript.value;
+import dmdscript.iterator;
+import dmdscript.scopex;
+import dmdscript.identifier;
+import dmdscript.ir;
+import dmdscript.errmsgs;
+import dmdscript.property;
+import dmdscript.ddeclaredfunction;
+import dmdscript.dfunction;
+
+//debug=VERIFY;	// verify integrity of code
+
+version = SCOPECACHING;		// turn scope caching on
+//version = SCOPECACHE_LOG;	// log statistics on it
+
+// Catch & Finally are "fake" Dobjects that sit in the scope
+// chain to implement our exception handling context.
+
+class Catch : Dobject
+{
+    // This is so scope_get() will skip over these objects
+    Value* Get(d_string PropertyName) { return null; }
+    Value* Get(d_string PropertyName, uint hash) { return null; }
+
+    // This is so we can distinguish between a real Dobject
+    // and these fakers
+    d_string getTypeof() { return null; }
+
+    uint offset;	// offset of CatchBlock
+    d_string name;      // catch identifier
+
+    this(uint offset, d_string name)
+    {
+	super(null);
+	this.offset = offset;
+	this.name = name;
+    }
+
+    int isCatch() { return true; }
+}
+
+class Finally : Dobject
+{
+    Value* Get(d_string PropertyName) { return null; }
+    Value* Get(d_string PropertyName, uint hash) { return null; }
+    d_string getTypeof() { return null; }
+
+    IR *finallyblock;    // code for FinallyBlock
+
+    this(IR *finallyblock)
+    {
+	super(null);
+	this.finallyblock = finallyblock;
+    }
+
+    int isFinally() { return true; }
+}
+
+
+/************************
+ * Look for identifier in scope.
+ */
+
+Value* scope_get(Dobject[] scopex, Identifier* id, Dobject *pthis)
+{   uint d;
+    Dobject o;
+    Value* v;
+
+    //writef("scope_get: scope = %p, scope.data = %p\n", scopex, scopex.data);
+    //writefln("scope_get: scopex = %x, length = %d, id = %s", cast(uint)scopex.ptr, scopex.length, id.toString());
+    d = scopex.length;
+    for (;;)
+    {
+        if (!d)
+        {   v = null;
+            *pthis = null;
+            break;
+        }
+        d--;
+        o = scopex[d];
+	//writef("o = %x, hash = x%x, s = '%s'\n", o, hash, s);
+        v = o.Get(id);
+        if (v)
+        {   *pthis = o;
+            break;
+        }
+    }
+    return v;
+}
+
+Value* scope_get_lambda(Dobject[] scopex, Identifier* id, Dobject *pthis)
+{   uint d;
+    Dobject o;
+    Value* v;
+
+    //writefln("scope_get_lambda: scope = %x, length = %d, id = %s", cast(uint)scopex.ptr, scopex.length, id.toString());
+    d = scopex.length;
+    for (;;)
+    {
+        if (!d)
+        {   v = null;
+            *pthis = null;
+            break;
+        }
+        d--;
+        o = scopex[d];
+	//printf("o = %p ", o);
+	//writefln("o = %s", o);
+        //printf("o = %x, hash = x%x, s = '%.*s'\n", o, hash, s);
+        //v = o.GetLambda(s, hash);
+        v = o.Get(id);
+        if (v)
+        {   *pthis = o;
+            break;
+        }
+    }
+    //writefln("v = %x", cast(uint)cast(void*)v);
+    return v;
+}
+
+Value* scope_get(Dobject[] scopex, Identifier* id)
+{   uint d;
+    Dobject o;
+    Value* v;
+
+    //writefln("scope_get: scopex = %x, length = %d, id = %s", cast(uint)scopex.ptr, scopex.length, id.toString());
+    d = scopex.length;
+    // 1 is most common case for d
+    if (d == 1)
+    {
+        return scopex[0].Get(id);
+    }
+    for (;;)
+    {
+        if (!d)
+        {   v = null;
+            break;
+        }
+        d--;
+        o = scopex[d];
+	//writefln("\to = %s", o);
+        v = o.Get(id);
+        if (v)
+            break;
+	//writefln("\tnot found");
+    }
+    return v;
+}
+
+/************************************
+ * Find last object in scopex, null if none.
+ */
+
+Dobject scope_tos(Dobject[] scopex)
+{   uint d;
+    Dobject o;
+
+    for (d = scopex.length; d;)
+    {
+        d--;
+        o = scopex[d];
+        if (o.getTypeof() != null) // if not a Finally or a Catch
+            return o;
+    }
+    return null;
+}
+
+/*****************************************
+ */
+
+void PutValue(CallContext *cc, d_string s, Value* a)
+{
+    // ECMA v3 8.7.2
+    // Look for the object o in the scope chain.
+    // If we find it, put its value.
+    // If we don't find it, put it into the global object
+
+    uint d;
+    uint hash;
+    Value* v;
+    Dobject o;
+
+    d = cc.scopex.length;
+    if (d == cc.globalroot)
+    {
+        o = scope_tos(cc.scopex);
+        o.Put(s, a, 0);
+        return;
+    }
+
+    hash = Value.calcHash(s);
+
+    for (;; d--)
+    {
+        assert(d > 0);
+        o = cc.scopex[d - 1];
+        if (d == cc.globalroot)
+        {
+            o.Put(s, a, 0);
+            return;
+        }
+        v = o.Get(s, hash);
+        if (v)
+        {
+            // Overwrite existing property with new one
+            o.Put(s, a, 0);
+            break;
+        }
+    }
+}
+
+
+void PutValue(CallContext *cc, Identifier* id, Value* a)
+{
+    // ECMA v3 8.7.2
+    // Look for the object o in the scope chain.
+    // If we find it, put its value.
+    // If we don't find it, put it into the global object
+
+    uint d;
+    Value* v;
+    Dobject o;
+
+    d = cc.scopex.length;
+    if (d == cc.globalroot)
+    {
+        o = scope_tos(cc.scopex);
+    }
+    else
+    {
+	for (;; d--)
+	{
+	    assert(d > 0);
+	    o = cc.scopex[d - 1];
+	    if (d == cc.globalroot)
+		break;
+	    v = o.Get(id);
+	    if (v)
+	    {
+		// Overwrite existing property with new one
+		break;
+	    }
+	}
+    }
+    o.Put(id, a, 0);
+}
+
+
+/*****************************************
+ * Helper function for Values that cannot be converted to Objects.
+ */
+
+Value* cannotConvert(Value* b, int linnum)
+{
+    ErrInfo errinfo;
+
+    errinfo.linnum = linnum;
+    if (b.isUndefinedOrNull())
+    {
+	b = Dobject.RuntimeError(&errinfo, errmsgtbl[ERR_CANNOT_CONVERT_TO_OBJECT4],
+		b.getType());
+    }
+    else
+    {
+	b = Dobject.RuntimeError(&errinfo, errmsgtbl[ERR_CANNOT_CONVERT_TO_OBJECT2],
+		b.getType(), b.toString());
+    }
+    return b;
+}
+
+const uint INDEX_FACTOR = 16;	// or 1
+
+struct IR
+{
+    union
+    {
+	struct
+	{
+	    version (LittleEndian)
+	    {
+		ubyte opcode;
+		ubyte padding;
+		ushort linnum;
+	    }
+	    else
+	    {
+		ushort linnum;
+		ubyte padding;
+		ubyte opcode;
+	    }
+	}
+	IR* code;
+	Value* value;
+	uint index;		// index into local variable table
+	uint hash;		// cached hash value
+	int offset;
+	Identifier* id;
+	d_boolean boolean;
+	Statement target;	// used for backpatch fixups
+	Dobject object;
+	void* ptr;
+    }
+
+    /****************************
+     * This is the main interpreter loop.
+     */
+
+    static void *call(CallContext *cc, Dobject othis,
+		IR *code, Value* ret, Value* locals)
+    {   Value* a;
+	Value* b;
+	Value* c;
+	Value* v;
+	Iterator *iter;
+	Identifier *id;
+	d_string s;
+	d_string s2;
+	d_number n;
+	d_boolean bo;
+	d_int32 i32;
+	d_uint32 u32;
+	d_boolean res;
+	tchar[] tx;
+	tchar[] ty;
+	Dobject o;
+	Dobject[] scopex;
+	uint dimsave;
+	uint offset;
+	Catch ca;
+	Finally f;
+	IR* codestart = code;
+	d_number inc;
+
+    /***************************************
+     * Cache for getscope's
+     */
+
+    version (SCOPECACHING)
+    {
+	struct ScopeCache
+	{
+	    d_string s;
+	    Value* v;		// never null, and never from a Dcomobject
+	}
+	int si;
+	ScopeCache zero;
+	ScopeCache[16] scopecache;
+	version (SCOPECACHE_LOG) int scopecache_cnt = 0;
+
+	uint SCOPECACHE_SI(tchar* s) { return (cast(uint)(s)) & 15; }
+	void SCOPECACHE_CLEAR()		   { scopecache[] = zero; }
+    }
+    else
+    {
+	uint SCOPECACHE_SI(d_string s) { return 0; }
+	void SCOPECACHE_CLEAR()		   { }
+    }
+
+    version (all)
+    {
+	// Eliminate the scale factor of Value.sizeof by computing it at compile time
+	Value* GETa(IR* code)  { return cast(Value*)(cast(void*)locals + (code + 1).index * (16 / INDEX_FACTOR)); }
+	Value* GETb(IR* code)  { return cast(Value*)(cast(void*)locals + (code + 2).index * (16 / INDEX_FACTOR)); }
+	Value* GETc(IR* code)  { return cast(Value*)(cast(void*)locals + (code + 3).index * (16 / INDEX_FACTOR)); }
+	Value* GETd(IR* code)  { return cast(Value*)(cast(void*)locals + (code + 4).index * (16 / INDEX_FACTOR)); }
+	Value* GETe(IR* code)  { return cast(Value*)(cast(void*)locals + (code + 5).index * (16 / INDEX_FACTOR)); }
+    }
+    else
+    {
+	Value* GETa(IR* code)  { return &locals[(code + 1).index]; }
+	Value* GETb(IR* code)  { return &locals[(code + 2).index]; }
+	Value* GETc(IR* code)  { return &locals[(code + 3).index]; }
+	Value* GETd(IR* code)  { return &locals[(code + 4).index]; }
+	Value* GETe(IR* code)  { return &locals[(code + 5).index]; }
+    }
+
+    uint GETlinnum(IR* code)	{ return code.linnum; }
+
+    debug (VERIFY) uint checksum = IR.verify(__LINE__, code);
+
+	version (none)
+	{
+	    writef("+printfunc\n");
+	    printfunc(code);
+	    writef("-printfunc\n");
+	}
+	scopex = cc.scopex;
+	//printf("call: scope = %p, length = %d\n", scopex.ptr, scopex.length);
+	dimsave = scopex.length;
+    //if (logflag)
+    //    writef("IR.call(othis = %p, code = %p, locals = %p)\n",othis,code,locals);
+
+    debug
+    {
+	uint debug_scoperoot = cc.scoperoot;
+	uint debug_globalroot = cc.globalroot;
+	uint debug_scopedim = scopex.length;
+	uint debug_scopeallocdim = scopex.allocdim;
+	Dobject debug_global = cc.global;
+	Dobject debug_variable = cc.variable;
+
+	void** debug_pscoperootdata = cast(void**)mem.malloc((void*).sizeof*debug_scoperoot);
+	void** debug_pglobalrootdata = cast(void**)mem.malloc((void*).sizeof*debug_globalroot);
+
+	memcpy(debug_pscoperootdata, scopex.data, (void*).sizeof*debug_scoperoot);
+	memcpy(debug_pglobalrootdata, scopex.data, (void*).sizeof*debug_globalroot);
+    }
+
+	assert(code);
+	//Value.copy(ret, &vundefined);
+	assert(othis);
+
+    Lnext:
+	//writef("cc = %x, interrupt = %d\n", cc, cc.Interrupt);
+	if (cc.Interrupt)			// see if script was interrupted
+	    goto Linterrupt;
+	for (;;)
+	{
+	    version (none)
+	    {
+		writef("%2d:", code - codestart);
+		print(code - codestart, code);
+	    }
+
+    debug
+    {
+	    assert(scopex == cc.scopex);
+	    assert(debug_scoperoot == cc.scoperoot);
+	    assert(debug_globalroot == cc.globalroot);
+	    assert(debug_global == cc.global);
+	    assert(debug_variable == cc.variable);
+	    assert(scopex.length >= debug_scoperoot);
+	    assert(scopex.length >= debug_globalroot);
+	    assert(scopex.length >= debug_scopedim);
+	    assert(scopex.allocdim >= debug_scopeallocdim);
+	    assert(0 == memcmp(debug_pscoperootdata, scopex.data, (void*).sizeof*debug_scoperoot));
+	    assert(0 == memcmp(debug_pglobalrootdata, scopex.data, (void*).sizeof*debug_globalroot));
+	    assert(scopex);
+    }
+
+
+    /+
+	    v = &vundefined;
+	    tx = v.getType();
+	    assert(tx == TypeUndefined);
+    +/
+	    //writef("\tIR%d:\n", code.opcode);
+	    switch (code.opcode)
+	    {
+		case IRerror:
+		    assert(0);
+		    break;
+
+		case IRnop:
+		    code++;
+		    break;
+
+		case IRget:                 // a = b.c
+		    a = GETa(code);
+		    b = GETb(code);
+		    o = b.toObject();
+		    if (!o)
+		    {
+			a = cannotConvert(b, GETlinnum(code));
+			goto Lthrow;
+		    }
+		    c = GETc(code);
+		    if (c.vtype == V_NUMBER &&
+			(i32 = cast(d_int32)c.number) == c.number &&
+			i32 >= 0)
+		    {
+			//writef("IRget %d\n", i32);
+			v = o.Get(cast(d_uint32)i32, c);
+		    }
+		    else
+		    {
+			s = c.toString();
+			v = o.Get(s);
+		    }
+		    if (!v)
+			v = &vundefined;
+		    Value.copy(a,v);
+		    code += 4;
+		    break;
+
+		case IRput:                 // b.c = a
+		    a = GETa(code);
+		    b = GETb(code);
+		    c = GETc(code);
+		    if (c.vtype == V_NUMBER &&
+			(i32 = cast(d_int32)c.number) == c.number &&
+			i32 >= 0)
+		    {
+			//writef("IRput %d\n", i32);
+			if (b.vtype == V_OBJECT)
+			    a = b.object.Put(cast(d_uint32)i32, c, a, 0);
+			else
+			    a = b.Put(cast(d_uint32)i32, c, a);
+		    }
+		    else
+		    {
+			s = c.toString();
+			a = b.Put(s, a);
+		    }
+		    if (a) goto Lthrow;
+		    code += 4;
+		    break;
+
+		case IRgets:                // a = b.s
+		    a = GETa(code);
+		    b = GETb(code);
+		    s = (code + 3).id.value.string;
+		    o = b.toObject();
+		    if (!o)
+		    {
+			//writef("%s %s.%s cannot convert to Object", b.getType(), b.toString(), s);
+			ErrInfo errinfo;
+			a = Dobject.RuntimeError(&errinfo,
+				errmsgtbl[ERR_CANNOT_CONVERT_TO_OBJECT3],
+				b.getType(), b.toString(),
+				s);
+			goto Lthrow;
+		    }
+		    v = o.Get(s);
+		    if (!v)
+		    {
+			//writef("IRgets: %s.%s is undefined\n", b.getType(), d_string_ptr(s));
+			v = &vundefined;
+		    }
+		    Value.copy(a,v);
+		    code += 4;
+		    goto Lnext;
+
+		case IRgetscope:            // a = s
+		    a = GETa(code);
+		    id = (code + 2).id;
+		    s = id.value.string;
+    version (SCOPECACHING)
+    {
+		    si = SCOPECACHE_SI(s.ptr);
+		    if (s is scopecache[si].s)
+		    {
+			version (SCOPECACHE_LOG) scopecache_cnt++;
+			Value.copy(a, scopecache[si].v);
+			code += 3;
+			break;
+		    }
+		    //writefln("miss %s, was %s, s.ptr = %x, cache.ptr = %x", s, scopecache[si].s, cast(uint)s.ptr, cast(uint)scopecache[si].s.ptr);
+    }
+    version (all)
+    {
+		    // Inline scope_get() for speed
+		    {   uint d;
+
+			d = scopex.length;
+			// 1 is most common case for d
+			if (d == 1)
+			{
+			    o = scopex[0];
+			    v = o.Get(id);
+			}
+			else
+			{
+			    o = null;
+			    for (;;)
+			    {
+				if (!d)
+				{   v = null;
+				    break;
+				}
+				d--;
+				o = scopex[d];
+				v = o.Get(id);
+				//writef("o = %x, v = %x\n", o, v);
+				if (v)
+				    break;
+			    }
+			}
+		    }
+		    if (!v)
+			v = &vundefined;
+		    else
+		    {
+	version (SCOPECACHING)
+	{
+			if (1) //!o.isDcomobject())
+			{
+			    scopecache[si].s = s;
+			    scopecache[si].v = v;
+			}
+	}
+		    }
+    }
+    else
+    {
+		    v = scope_get(scopex, id);
+		    if (!v)
+			v = &vundefined;
+    }
+		    //writef("v = %p\n", v);
+		    //writef("v = %g\n", v.toNumber());
+		    //writef("v = %s\n", d_string_ptr(v.toString()));
+		    Value.copy(a, v);
+		    code += 3;
+		    break;
+
+		case IRaddass:              // a = (b.c += a)
+		    c = GETc(code);
+		    s = c.toString();
+		    goto Laddass;
+
+		case IRaddasss:             // a = (b.s += a)
+		    s = (code + 3).id.value.string;
+		Laddass:
+		    b = GETb(code);
+		    v = b.Get(s);
+		    goto Laddass2;
+
+		case IRaddassscope:         // a = (s += a)
+		    b = null;               // Needed for the b.Put() below to shutup a compiler use-without-init warning
+		    id = (code + 2).id;
+		    s = id.value.string;
+    version (SCOPECACHING)
+    {
+		    si = SCOPECACHE_SI(s.ptr);
+		    if (s is scopecache[si].s)
+			v = scopecache[si].v;
+		    else
+			v = scope_get(scopex, id);
+    }
+    else
+    {
+		    v = scope_get(scopex, id);
+    }
+		Laddass2:
+		    a = GETa(code);
+		    if (!v)
+		    {
+			v = &vundefined;
+			a.putVundefined();
+    /+
+			if (b)
+			{
+			    a = b.Put(s, v);
+			    //if (a) goto Lthrow;
+			}
+			else
+			{
+			    PutValue(cc, s, v);
+			}
+    +/
+		    }
+		    else if (a.vtype == V_NUMBER && v.vtype == V_NUMBER)
+		    {   a.number += v.number;
+			v.number = a.number;
+		    }
+		    else
+		    {
+			v.toPrimitive(v, null);
+			a.toPrimitive(a, null);
+			if (v.isString())
+			{
+			    s2 = v.toString() ~ a.toString();
+			    a.putVstring(s2);
+			    Value.copy(v, a);
+			}
+			else if (a.isString())
+			{
+			    s2 = v.toString() ~ a.toString();
+			    a.putVstring(s2);
+			    Value.copy(v, a);
+			}
+			else
+			{
+			    a.putVnumber(a.toNumber() + v.toNumber());
+			    v.number = a.number;
+			}
+		    }
+		    code += 4;
+		    break;
+
+		case IRputs:		// b.s = a
+		    a = GETa(code);
+		    b = GETb(code);
+		    o = b.toObject();
+		    if (!o)
+		    {
+			a = cannotConvert(b, GETlinnum(code));
+			goto Lthrow;
+		    }
+		    a = o.Put((code + 3).id.value.string, a, 0);
+		    if (a) goto Lthrow;
+		    code += 4;
+		    goto Lnext;
+
+		case IRputscope:            // s = a
+		    PutValue(cc, (code + 2).id, GETa(code));
+		    code += 3;
+		    break;
+
+		case IRputdefault:		// b = a
+		    a = GETa(code);
+		    b = GETb(code);
+		    o = b.toObject();
+		    if (!o)
+		    {
+			ErrInfo errinfo;
+			a = Dobject.RuntimeError(&errinfo,
+				errmsgtbl[ERR_CANNOT_ASSIGN], a.getType(),
+				b.getType());
+			goto Lthrow;
+		    }
+		    a = o.PutDefault(a);
+		    if (a)
+			goto Lthrow;
+		    code += 3;
+		    break;
+
+		case IRputthis:             // s = a
+		    a = cc.variable.Put((code + 2).id.value.string, GETa(code), 0);
+		    //if (a) goto Lthrow;
+		    code += 3;
+		    break;
+
+		case IRmov:                 // a = b
+		    Value.copy(GETa(code), GETb(code));
+		    code += 3;
+		    break;
+
+		case IRstring:              // a = "string"
+		    GETa(code).putVstring((code + 2).id.value.string);
+		    code += 3;
+		    break;
+
+		case IRobject:              // a = object
+		{   FunctionDefinition fd;
+		    fd = cast(FunctionDefinition)(code + 2).ptr;
+		    Dfunction fobject = new DdeclaredFunction(fd);
+		    fobject.scopex = scopex;
+		    GETa(code).putVobject(fobject);
+		    code += 3;
+		    break;
+		}
+
+		case IRthis:                // a = this
+		    GETa(code).putVobject(othis);
+		    //writef("IRthis: %s, othis = %x\n", GETa(code).getType(), othis);
+		    code += 2;
+		    break;
+
+		case IRnumber:              // a = number
+		    GETa(code).putVnumber(*cast(d_number *)(code + 2));
+		    code += 4;
+		    break;
+
+		case IRboolean:             // a = boolean
+		    GETa(code).putVboolean((code + 2).boolean);
+		    code += 3;
+		    break;
+
+		case IRnull:                // a = null
+		    GETa(code).putVnull();
+		    code += 2;
+		    break;
+
+		case IRundefined:           // a = undefined
+		    GETa(code).putVundefined();
+		    code += 2;
+		    break;
+
+		case IRthisget:             // a = othis.ident
+		    a = GETa(code);
+		    v = othis.Get((code + 2).id.value.string);
+		    if (!v)
+			v = &vundefined;
+		    Value.copy(a, v);
+		    code += 3;
+		    break;
+
+		case IRneg:                 // a = -a
+		    a = GETa(code);
+		    n = a.toNumber();
+		    a.putVnumber(-n);
+		    code += 2;
+		    break;
+
+		case IRpos:                 // a = a
+		    a = GETa(code);
+		    n = a.toNumber();
+		    a.putVnumber(n);
+		    code += 2;
+		    break;
+
+		case IRcom:                 // a = ~a
+		    a = GETa(code);
+		    i32 = a.toInt32();
+		    a.putVnumber(~i32);
+		    code += 2;
+		    break;
+
+		case IRnot:                 // a = !a
+		    a = GETa(code);
+		    a.putVboolean(!a.toBoolean());
+		    code += 2;
+		    break;
+
+		case IRtypeof:      // a = typeof a
+		    // ECMA 11.4.3 says that if the result of (a)
+		    // is a Reference and GetBase(a) is null,
+		    // then the result is "undefined". I don't know
+		    // what kind of script syntax will generate this.
+		    a = GETa(code);
+		    a.putVstring(a.getTypeof());
+		    code += 2;
+		    break;
+
+		case IRinstance:	// a = b instanceof c
+		{
+		    Dobject co;
+
+		    // ECMA v3 11.8.6
+
+		    b = GETb(code);
+		    o = b.toObject();
+		    c = GETc(code);
+		    if (c.isPrimitive())
+		    {
+			ErrInfo errinfo;
+			a = Dobject.RuntimeError(&errinfo,
+				errmsgtbl[ERR_RHS_MUST_BE_OBJECT],
+				"instanceof", c.getType());
+			goto Lthrow;
+		    }
+		    co = c.toObject();
+		    a = GETa(code);
+		    v = cast(Value*)co.HasInstance(a, b);
+		    if (v)
+		    {   a = v;
+			 goto Lthrow;
+		    }
+		    code += 4;
+		    break;
+		}
+		case IRadd:			// a = b + c
+		    a = GETa(code);
+		    b = GETb(code);
+		    c = GETc(code);
+
+		    if (b.vtype == V_NUMBER && c.vtype == V_NUMBER)
+		    {
+			a.putVnumber(b.number + c.number);
+		    }
+		    else
+		    {
+			char vtmpb[Value.sizeof];
+			Value* vb = cast(Value*)vtmpb;
+			char vtmpc[Value.sizeof];
+			Value* vc = cast(Value*)vtmpc;
+
+			v = cast(Value*)b.toPrimitive(vb, null);
+			if (v)
+			{   a = v;
+			    goto Lthrow;
+			}
+			v = cast(Value*)c.toPrimitive(vc, null);
+			if (v)
+			{   a = v;
+			    goto Lthrow;
+			}
+			if (vb.isString() || vc.isString())
+			{
+			    s = vb.toString() ~ vc.toString();
+			    a.putVstring(s);
+			}
+			else
+			{
+			    a.putVnumber(vb.toNumber() + vc.toNumber());
+			}
+		    }
+
+		    code += 4;
+		    break;
+
+		case IRsub:                 // a = b - c
+		    a = GETa(code);
+		    b = GETb(code);
+		    c = GETc(code);
+		    a.putVnumber(b.toNumber() - c.toNumber());
+		    code += 4;
+		    break;
+
+		case IRmul:                 // a = b * c
+		    a = GETa(code);
+		    b = GETb(code);
+		    c = GETc(code);
+		    a.putVnumber(b.toNumber() * c.toNumber());
+		    code += 4;
+		    break;
+
+		case IRdiv:                 // a = b / c
+		    a = GETa(code);
+		    b = GETb(code);
+		    c = GETc(code);
+
+		    //writef("%g / %g = %g\n", b.toNumber() , c.toNumber(), b.toNumber() / c.toNumber());
+		    a.putVnumber(b.toNumber() / c.toNumber());
+		    code += 4;
+		    break;
+
+		case IRmod:                 // a = b % c
+		    a = GETa(code);
+		    b = GETb(code);
+		    c = GETc(code);
+		    a.putVnumber(b.toNumber() % c.toNumber());
+		    code += 4;
+		    break;
+
+		case IRshl:                 // a = b << c
+		    a = GETa(code);
+		    b = GETb(code);
+		    c = GETc(code);
+		    i32 = b.toInt32();
+		    u32 = c.toUint32() & 0x1F;
+		    i32 <<= u32;
+		    a.putVnumber(i32);
+		    code += 4;
+		    break;
+
+		case IRshr:                 // a = b >> c
+		    a = GETa(code);
+		    b = GETb(code);
+		    c = GETc(code);
+		    i32 = b.toInt32();
+		    u32 = c.toUint32() & 0x1F;
+		    i32 >>= cast(d_int32) u32;
+		    a.putVnumber(i32);
+		    code += 4;
+		    break;
+
+		case IRushr:                // a = b >>> c
+		    a = GETa(code);
+		    b = GETb(code);
+		    c = GETc(code);
+		    i32 = b.toUint32();
+		    u32 = c.toUint32() & 0x1F;
+		    u32 = (cast(d_uint32) i32) >> u32;
+		    a.putVnumber(u32);
+		    code += 4;
+		    break;
+
+		case IRand:         // a = b & c
+		    a = GETa(code);
+		    b = GETb(code);
+		    c = GETc(code);
+		    a.putVnumber(b.toInt32() & c.toInt32());
+		    code += 4;
+		    break;
+
+		case IRor:          // a = b | c
+		    a = GETa(code);
+		    b = GETb(code);
+		    c = GETc(code);
+		    a.putVnumber(b.toInt32() | c.toInt32());
+		    code += 4;
+		    break;
+
+		case IRxor:         // a = b ^ c
+		    a = GETa(code);
+		    b = GETb(code);
+		    c = GETc(code);
+		    a.putVnumber(b.toInt32() ^ c.toInt32());
+		    code += 4;
+		    break;
+
+		/********************/
+
+		case IRpreinc:     // a = ++b.c
+		    c = GETc(code);
+		    s = c.toString();
+		    goto Lpreinc;
+		case IRpreincs:    // a = ++b.s
+		    s = (code + 3).id.value.string;
+		Lpreinc:
+		    inc = 1;
+		Lpre:
+		    a = GETa(code);
+		    b = GETb(code);
+		    v = b.Get(s);
+		    if (!v)
+			v = &vundefined;
+		    n = v.toNumber();
+		    a.putVnumber(n + inc);
+		    b.Put(s, a);
+		    code += 4;
+		    break;
+
+		case IRpreincscope:        // a = ++s
+		    inc = 1;
+		Lprescope:
+		    a = GETa(code);
+		    id = (code + 2).id;
+		    s = id.value.string;
+    version (SCOPECACHING)
+    {
+		    si = SCOPECACHE_SI(s.ptr);
+		    if (s is scopecache[si].s)
+		    {
+			v = scopecache[si].v;
+			n = v.toNumber() + inc;
+			v.putVnumber(n);
+			a.putVnumber(n);
+		    }
+		    else
+		    {
+			v = scope_get(scopex, id, &o);
+			if (v)
+			{   n = v.toNumber() + inc;
+			    v.putVnumber(n);
+			    a.putVnumber(n);
+			}
+			else
+			    a.putVundefined();
+		    }
+    }
+    else
+    {
+		    v = scope_get(scopex, id, &o);
+		    if (v)
+		    {   n = v.toNumber();
+			v.putVnumber(n + inc);
+			Value.copy(a, v);
+		    }
+		    else
+			a.putVundefined();
+    }
+		    code += 4;
+		    break;
+
+		case IRpredec:     // a = --b.c
+		    c = GETc(code);
+		    s = c.toString();
+		    goto Lpredec;
+		case IRpredecs:    // a = --b.s
+		    s = (code + 3).id.value.string;
+		Lpredec:
+		    inc = -1;
+		    goto Lpre;
+
+		case IRpredecscope:        // a = --s
+		    inc = -1;
+		    goto Lprescope;
+
+		/********************/
+
+		case IRpostinc:     // a = b.c++
+		    c = GETc(code);
+		    s = c.toString();
+		    goto Lpostinc;
+		case IRpostincs:    // a = b.s++
+		    s = (code + 3).id.value.string;
+		Lpostinc:
+		    a = GETa(code);
+		    b = GETb(code);
+		    v = b.Get(s);
+		    if (!v)
+			v = &vundefined;
+		    n = v.toNumber();
+		    a.putVnumber(n + 1);
+		    b.Put(s, a);
+		    a.putVnumber(n);
+		    code += 4;
+		    break;
+
+		case IRpostincscope:        // a = s++
+		    id = (code + 2).id;
+		    v = scope_get(scopex, id, &o);
+		    if (v && v != &vundefined)
+		    {
+			n = v.toNumber();
+			a = GETa(code);
+			v.putVnumber(n + 1);
+			a.putVnumber(n);
+		    }
+		    else
+			GETa(code).putVundefined();
+		    code += 3;
+		    break;
+
+		case IRpostdec:     // a = b.c--
+		    c = GETc(code);
+		    s = c.toString();
+		    goto Lpostdec;
+		case IRpostdecs:    // a = b.s--
+		    s = (code + 3).id.value.string;
+		Lpostdec:
+		    a = GETa(code);
+		    b = GETb(code);
+		    v = b.Get(s);
+		    if (!v)
+			v = &vundefined;
+		    n = v.toNumber();
+		    a.putVnumber(n - 1);
+		    b.Put(s, a);
+		    a.putVnumber(n);
+		    code += 4;
+		    break;
+
+		case IRpostdecscope:        // a = s--
+		    id = (code + 2).id;
+		    v = scope_get(scopex, id, &o);
+		    if (v && v != &vundefined)
+		    {   n = v.toNumber();
+			a = GETa(code);
+			v.putVnumber(n - 1);
+			a.putVnumber(n);
+		    }
+		    else
+			GETa(code).putVundefined();
+		    code += 3;
+		    break;
+
+		case IRdel:		// a = delete b.c
+		case IRdels:	// a = delete b.s
+		    b = GETb(code);
+		    if (b.isPrimitive())
+			bo = true;
+		    else
+		    {
+			o = b.toObject();
+			if (!o)
+			{
+			    a = cannotConvert(b, GETlinnum(code));
+			    goto Lthrow;
+			}
+			s = (code.opcode == IRdel)
+			    ? GETc(code).toString()
+			    : (code + 3).id.value.string;
+			if (o.implementsDelete())
+			    bo = o.Delete(s);
+			else
+			    bo = !o.HasProperty(s);
+		    }
+		    GETa(code).putVboolean(bo);
+		    code += 4;
+		    break;
+
+		case IRdelscope:    // a = delete s
+		    id = (code + 2).id;
+		    s = id.value.string;
+		    //o = scope_tos(scopex);		// broken way
+		    if (!scope_get(scopex, id, &o))
+			bo = true;
+		    else if (o.implementsDelete())
+			bo = o.Delete(s);
+		    else
+			bo = !o.HasProperty(s);
+		    GETa(code).putVboolean(bo);
+		    code += 3;
+		    break;
+
+		/* ECMA requires that if one of the numeric operands is NAN,
+		 * then the result of the comparison is false. D generates a
+		 * correct test for NAN operands.
+		 */
+
+		case IRclt:         // a = (b <   c)
+		    a = GETa(code);
+		    b = GETb(code);
+		    c = GETc(code);
+		    if (b.vtype == V_NUMBER && c.vtype == V_NUMBER)
+			res = (b.number < c.number);
+		    else
+		    {
+			b.toPrimitive(b, TypeNumber);
+			c.toPrimitive(c, TypeNumber);
+			if (b.isString() && c.isString())
+			{   d_string x = b.toString();
+			    d_string y = c.toString();
+
+			    res = std.string.cmp(x, y) < 0;
+			}
+			else
+			    res = b.toNumber() < c.toNumber();
+		    }
+		    a.putVboolean(res);
+		    code += 4;
+		    break;
+
+		case IRcle:         // a = (b <=  c)
+		    a = GETa(code);
+		    b = GETb(code);
+		    c = GETc(code);
+		    if (b.vtype == V_NUMBER && c.vtype == V_NUMBER)
+			res = (b.number <= c.number);
+		    else
+		    {
+			b.toPrimitive(b, TypeNumber);
+			c.toPrimitive(c, TypeNumber);
+			if (b.isString() && c.isString())
+			{   d_string x = b.toString();
+			    d_string y = c.toString();
+
+			    res = std.string.cmp(x, y) <= 0;
+			}
+			else
+			    res = b.toNumber() <= c.toNumber();
+		    }
+		    a.putVboolean(res);
+		    code += 4;
+		    break;
+
+		case IRcgt:         // a = (b >   c)
+		    a = GETa(code);
+		    b = GETb(code);
+		    c = GETc(code);
+		    if (b.vtype == V_NUMBER && c.vtype == V_NUMBER)
+			res = (b.number > c.number);
+		    else
+		    {
+			b.toPrimitive(b, TypeNumber);
+			c.toPrimitive(c, TypeNumber);
+			if (b.isString() && c.isString())
+			{   d_string x = b.toString();
+			    d_string y = c.toString();
+
+			    res = std.string.cmp(x, y) > 0;
+			}
+			else
+			    res = b.toNumber() > c.toNumber();
+		    }
+		    a.putVboolean(res);
+		    code += 4;
+		    break;
+
+
+		case IRcge:         // a = (b >=  c)
+		    a = GETa(code);
+		    b = GETb(code);
+		    c = GETc(code);
+		    if (b.vtype == V_NUMBER && c.vtype == V_NUMBER)
+			res = (b.number >= c.number);
+		    else
+		    {
+			b.toPrimitive(b, TypeNumber);
+			c.toPrimitive(c, TypeNumber);
+			if (b.isString() && c.isString())
+			{   d_string x = b.toString();
+			    d_string y = c.toString();
+
+			    res = std.string.cmp(x, y) >= 0;
+			}
+			else
+			    res = b.toNumber() >= c.toNumber();
+		    }
+		    a.putVboolean(res);
+		    code += 4;
+		    break;
+
+		case IRceq:         // a = (b ==  c)
+		case IRcne:         // a = (b !=  c)
+		    a = GETa(code);
+		    b = GETb(code);
+		    c = GETc(code);
+		Lagain:
+		    tx = b.getType();
+		    ty = c.getType();
+		    if (logflag) writef("tx('%s', '%s')\n", tx, ty);
+		    if (tx == ty)
+		    {
+			if (tx == TypeUndefined ||
+			    tx == TypeNull)
+			    res = true;
+			else if (tx == TypeNumber)
+			{   d_number x = b.number;
+			    d_number y = c.number;
+
+			    res = (x == y);
+			    //writef("x = %g, y = %g, res = %d\n", x, y, res);
+			}
+			else if (tx == TypeString)
+			{
+			    if (logflag)
+			    {
+				writef("b = %x, c = %x\n", b, c);
+				writef("cmp('%s', '%s')\n", b.string, c.string);
+				writef("cmp(%d, %d)\n", b.string.length, c.string.length);
+			    }
+			    res = (b.string == c.string);
+			}
+			else if (tx == TypeBoolean)
+			    res = (b.dbool == c.dbool);
+			else // TypeObject
+			{
+			    res = b.object == c.object;
+			}
+		    }
+		    else if (tx == TypeNull && ty == TypeUndefined)
+			res = true;
+		    else if (tx == TypeUndefined && ty == TypeNull)
+			res = true;
+		    else if (tx == TypeNumber && ty == TypeString)
+		    {
+			c.putVnumber(c.toNumber());
+			goto Lagain;
+		    }
+		    else if (tx == TypeString && ty == TypeNumber)
+		    {
+			b.putVnumber(b.toNumber());
+			goto Lagain;
+		    }
+		    else if (tx == TypeBoolean)
+		    {
+			b.putVnumber(b.toNumber());
+			goto Lagain;
+		    }
+		    else if (ty == TypeBoolean)
+		    {
+			c.putVnumber(c.toNumber());
+			goto Lagain;
+		    }
+		    else if (ty == TypeObject)
+		    {
+			v = cast(Value*)c.toPrimitive(c, null);
+			if (v)
+			{   a = v;
+			    goto Lthrow;
+			}
+			goto Lagain;
+		    }
+		    else if (tx == TypeObject)
+		    {
+			v = cast(Value*)b.toPrimitive(b, null);
+			if (v)
+			{   a = v;
+			    goto Lthrow;
+			}
+			goto Lagain;
+		    }
+		    else
+		    {
+			res = false;
+		    }
+
+		    res ^= (code.opcode == IRcne);
+		//Lceq:
+		    a.putVboolean(res);
+		    code += 4;
+		    break;
+
+		case IRcid:         // a = (b === c)
+		case IRcnid:        // a = (b !== c)
+		    a = GETa(code);
+		    b = GETb(code);
+		    c = GETc(code);
+		    tx = b.getType();
+		    ty = c.getType();
+		    if (tx == ty)
+		    {
+			if (tx == TypeUndefined ||
+			    tx == TypeNull)
+			    res = true;
+			else if (tx == TypeNumber)
+			{   d_number x = b.number;
+			    d_number y = c.number;
+
+			    // Ensure that a NAN operand produces false
+			    if (code.opcode == IRcid)
+				res = (x == y);
+			    else
+				res = (x <> y);
+			    goto Lcid;
+			}
+			else if (tx == TypeString)
+			    res = (b.string == c.string);
+			else if (tx == TypeBoolean)
+			    res = (b.dbool == c.dbool);
+			else // TypeObject
+			{
+			    res = b.object == c.object;
+			}
+		    }
+		    else
+		    {
+			res = false;
+		    }
+
+		    res ^= (code.opcode == IRcnid);
+		Lcid:
+		    a.putVboolean(res);
+		    code += 4;
+		    break;
+
+		case IRjt:          // if (b) goto t
+		    b = GETb(code);
+		    if (b.toBoolean())
+			code += (code + 1).offset;
+		    else
+			code += 3;
+		    break;
+
+		case IRjf:          // if (!b) goto t
+		    b = GETb(code);
+		    if (!b.toBoolean())
+			code += (code + 1).offset;
+		    else
+			code += 3;
+		    break;
+
+		case IRjtb:         // if (b) goto t
+		    b = GETb(code);
+		    if (b.dbool)
+			code += (code + 1).offset;
+		    else
+			code += 3;
+		    break;
+
+		case IRjfb:         // if (!b) goto t
+		    b = GETb(code);
+		    if (!b.dbool)
+			code += (code + 1).offset;
+		    else
+			code += 3;
+		    break;
+
+		case IRjmp:
+		    code += (code + 1).offset;
+		    break;
+
+		case IRjlt:         // if (b <   c) goto c
+		    b = GETb(code);
+		    c = GETc(code);
+		    if (b.vtype == V_NUMBER && c.vtype == V_NUMBER)
+		    {
+			if (b.number < c.number)
+			    code += 4;
+			else
+			    code += (code + 1).offset;
+			break;
+		    }
+		    else
+		    {
+			b.toPrimitive(b, TypeNumber);
+			c.toPrimitive(c, TypeNumber);
+			if (b.isString() && c.isString())
+			{   d_string x = b.toString();
+			    d_string y = c.toString();
+
+			    res = std.string.cmp(x, y) < 0;
+			}
+			else
+			    res = b.toNumber() < c.toNumber();
+		    }
+		    if (!res)
+			code += (code + 1).offset;
+		    else
+			code += 4;
+		    break;
+
+		case IRjle:         // if (b <=  c) goto c
+		    b = GETb(code);
+		    c = GETc(code);
+		    if (b.vtype == V_NUMBER && c.vtype == V_NUMBER)
+		    {
+			if (b.number <= c.number)
+			    code += 4;
+			else
+			    code += (code + 1).offset;
+			break;
+		    }
+		    else
+		    {
+			b.toPrimitive(b, TypeNumber);
+			c.toPrimitive(c, TypeNumber);
+			if (b.isString() && c.isString())
+			{   d_string x = b.toString();
+			    d_string y = c.toString();
+
+			    res = std.string.cmp(x, y) <= 0;
+			}
+			else
+			    res = b.toNumber() <= c.toNumber();
+		    }
+		    if (!res)
+			code += (code + 1).offset;
+		    else
+			code += 4;
+		    break;
+
+		case IRjltc:        // if (b < constant) goto c
+		    b = GETb(code);
+		    res = (b.toNumber() < *cast(d_number *)(code + 3));
+		    if (!res)
+			code += (code + 1).offset;
+		    else
+			code += 5;
+		    break;
+
+		case IRjlec:        // if (b <= constant) goto c
+		    b = GETb(code);
+		    res = (b.toNumber() <= *cast(d_number *)(code + 3));
+		    if (!res)
+			code += (code + 1).offset;
+		    else
+			code += 5;
+		    break;
+
+		case IRiter:                // a = iter(b)
+		    a = GETa(code);
+		    b = GETb(code);
+		    o = b.toObject();
+		    if (!o)
+		    {
+			a = cannotConvert(b, GETlinnum(code));
+			goto Lthrow;
+		    }
+		    a = o.putIterator(a);
+		    if (a)
+			goto Lthrow;
+		    code += 3;
+		    break;
+
+		case IRnext:        // a, b.c, iter
+				    // if (!(b.c = iter)) goto a; iter = iter.next
+		    s = GETc(code).toString();
+		    goto case_next;
+
+		case IRnexts:       // a, b.s, iter
+		    s = (code + 3).id.value.string;
+		case_next:
+		    iter = GETd(code).iter;
+		    v = iter.next();
+		    if (!v)
+			code += (code + 1).offset;
+		    else
+		    {
+			b = GETb(code);
+			b.Put(s, v);
+			code += 5;
+		    }
+		    break;
+
+		case IRnextscope:   // a, s, iter
+		    s = (code + 2).id.value.string;
+		    iter = GETc(code).iter;
+		    v = iter.next();
+		    if (!v)
+			code += (code + 1).offset;
+		    else
+		    {
+			o = scope_tos(scopex);
+			o.Put(s, v, 0);
+			code += 4;
+		    }
+		    break;
+
+		case IRcall:        // a = b.c(argc, argv)
+		    s = GETc(code).toString();
+		    goto case_call;
+
+		case IRcalls:       // a = b.s(argc, argv)
+		    s = (code + 3).id.value.string;
+		    goto case_call;
+
+		case_call:
+		    a = GETa(code);
+		    b = GETb(code);
+		    o = b.toObject();
+		    if (!o)
+		    {
+			goto Lcallerror;
+		    }
+		    {
+    //writef("v.call\n");
+			v = o.Get(s);
+			if (!v)
+			    goto Lcallerror;
+			//writef("calling... '%s'\n", v.toString());
+			cc.callerothis = othis;
+			a.putVundefined();
+			a = cast(Value*)v.Call(cc, o, a, GETe(code)[0 .. (code + 4).index]);
+			//writef("regular call, a = %x\n", a);
+		    }
+		    debug (VERIFY)
+			assert(checksum == IR.verify(__LINE__, codestart));
+		    if (a)
+			goto Lthrow;
+		    code += 6;
+		    goto Lnext;
+
+		Lcallerror:
+		{
+		    //writef("%s %s.%s is undefined and has no Call method\n", b.getType(), b.toString(), s);
+		    ErrInfo errinfo;
+		    a = Dobject.RuntimeError(&errinfo,
+			    errmsgtbl[ERR_UNDEFINED_NO_CALL3],
+			    b.getType(), b.toString(),
+			    s);
+		    goto Lthrow;
+		}
+
+		case IRcallscope:   // a = s(argc, argv)
+		    id = (code + 2).id;
+		    s = id.value.string;
+		    a = GETa(code);
+		    v = scope_get_lambda(scopex, id, &o);
+		    //writefln("v.toString() = '%s'", v.toString());
+		    if (!v)
+		    {
+			ErrInfo errinfo;
+			a = Dobject.RuntimeError(&errinfo, errmsgtbl[ERR_UNDEFINED_NO_CALL2], "property", s);
+			goto Lthrow;
+		    }
+		    // Should we pass othis or o? I think othis.
+		    cc.callerothis = othis;        // pass othis to eval()
+		    a.putVundefined();
+		    a = cast(Value*)v.Call(cc, o, a, GETd(code)[0 .. (code + 3).index] );
+		    //writef("callscope result = %x\n", a);
+		    debug (VERIFY)
+			assert(checksum == IR.verify(__LINE__, codestart));
+		    if (a)
+			goto Lthrow;
+		    code += 5;
+		    goto Lnext;
+
+		case IRcallv:	// v(argc, argv) = a
+		    a = GETa(code);
+		    b = GETb(code);
+		    o = b.toObject();
+		    if (!o)
+		    {
+			//writef("%s %s is undefined and has no Call method\n", b.getType(), b.toString());
+			ErrInfo errinfo;
+			a = Dobject.RuntimeError(&errinfo,
+				errmsgtbl[ERR_UNDEFINED_NO_CALL2],
+				b.getType(), b.toString());
+			goto Lthrow;
+		    }
+		    cc.callerothis = othis;        // pass othis to eval()
+		    a.putVundefined();
+		    a = cast(Value*)o.Call(cc, o, a, GETd(code)[0 .. (code + 3).index]);
+		    if (a)
+			goto Lthrow;
+		    code += 5;
+		    goto Lnext;
+
+		case IRputcall:        // b.c(argc, argv) = a
+		    s = GETc(code).toString();
+		    goto case_putcall;
+
+		case IRputcalls:       //  b.s(argc, argv) = a
+		    s = (code + 3).id.value.string;
+		    goto case_putcall;
+
+		case_putcall:
+		    a = GETa(code);
+		    b = GETb(code);
+		    o = b.toObject();
+		    if (!o)
+			goto Lcallerror;
+		    //v = o.GetLambda(s, Value.calcHash(s));
+		    v = o.Get(s, Value.calcHash(s));
+		    if (!v)
+			goto Lcallerror;
+		    //writef("calling... '%s'\n", v.toString());
+		    o = v.toObject();
+		    if (!o)
+		    {
+			ErrInfo errinfo;
+			a = Dobject.RuntimeError(&errinfo,
+				errmsgtbl[ERR_CANNOT_ASSIGN_TO2],
+				b.getType(), s);
+			goto Lthrow;
+		    }
+		    a = cast(Value*)o.put_Value(a, GETe(code)[0 .. (code + 4).index] );
+		    if (a)
+			goto Lthrow;
+		    code += 6;
+		    goto Lnext;
+
+		case IRputcallscope:   // a = s(argc, argv)
+		    id = (code + 2).id;
+		    s = id.value.string;
+		    v = scope_get_lambda(scopex, id, &o);
+		    if (!v)
+		    {
+			ErrInfo errinfo;
+			a = Dobject.RuntimeError(&errinfo,
+				errmsgtbl[ERR_UNDEFINED_NO_CALL2],
+				"property", s);
+			goto Lthrow;
+		    }
+		    o = v.toObject();
+		    if (!o)
+		    {
+			ErrInfo errinfo;
+			a = Dobject.RuntimeError(&errinfo,
+				errmsgtbl[ERR_CANNOT_ASSIGN_TO],
+				s);
+			goto Lthrow;
+		    }
+		    a = cast(Value*)o.put_Value(GETa(code), GETd(code)[0 .. (code + 3).index] );
+		    if (a)
+			goto Lthrow;
+		    code += 5;
+		    goto Lnext;
+
+		case IRputcallv:	// v(argc, argv) = a
+		    b = GETb(code);
+		    o = b.toObject();
+		    if (!o)
+		    {
+			//writef("%s %s is undefined and has no Call method\n", b.getType(), b.toString());
+			ErrInfo errinfo;
+			a = Dobject.RuntimeError(&errinfo,
+				errmsgtbl[ERR_UNDEFINED_NO_CALL2],
+				b.getType(), b.toString());
+			goto Lthrow;
+		    }
+		    a = cast(Value*)o.put_Value(GETa(code), GETd(code)[0 .. (code + 3).index] );
+		    if (a)
+			goto Lthrow;
+		    code += 5;
+		    goto Lnext;
+
+		case IRnew: // a = new b(argc, argv)
+		    a = GETa(code);
+		    b = GETb(code);
+		    a.putVundefined();
+		    a = cast(Value*)b.Construct(cc, a, GETd(code)[0 .. (code + 3).index] );
+		    debug (VERIFY)
+			assert(checksum == IR.verify(__LINE__, codestart));
+		    if (a)
+			goto Lthrow;
+		    code += 5;
+		    goto Lnext;
+
+		case IRpush:
+		    SCOPECACHE_CLEAR();
+		    a = GETa(code);
+		    o = a.toObject();
+		    if (!o)
+		    {
+			a = cannotConvert(a, GETlinnum(code));
+			goto Lthrow;
+		    }
+		    scopex ~= o;		// push entry onto scope chain
+		    cc.scopex = scopex;
+		    code += 2;
+		    break;
+
+		case IRpop:
+		    SCOPECACHE_CLEAR();
+		    o = scopex[length - 1];
+		    scopex = scopex[0 .. length - 1];	// pop entry off scope chain
+		    // If it's a Finally, we need to execute
+		    // the finally block
+		    code += 1;
+		    if (o.isFinally())  // test could be eliminated with virtual func
+		    {
+			f = cast(Finally)o;
+			cc.finallyret = 0;
+			a = cast(Value*)call(cc, othis, f.finallyblock, ret, locals);
+			debug (VERIFY)
+			    assert(checksum == IR.verify(__LINE__, codestart));
+			if (a)
+			    goto Lthrow;
+			if (cc.finallyret)
+			    cc.finallyret = 0;
+			else
+			{   // The rest of any unwinding is already done
+			    return null;
+			}
+		    }
+		    goto Lnext;
+
+		case IRfinallyret:
+		    cc.finallyret = 1;
+		case IRret:
+		    version (SCOPECACHE_LOG)
+			printf("scopecache_cnt = %d\n", scopecache_cnt);
+		    return null;
+
+		case IRretexp:
+		    a = GETa(code);
+		    Value.copy(ret, a);
+		    //writef("returns: %s\n", ret.toString());
+		    return null;
+
+		case IRimpret:
+		    a = GETa(code);
+		    Value.copy(ret, a);
+		    //writef("implicit return: %s\n", ret.toString());
+		    code += 2;
+		    goto Lnext;
+
+		case IRthrow:
+		    a = GETa(code);
+		    cc.linnum = GETlinnum(code);
+		Lthrow:
+		    //writef("Lthrow: linnum = %d\n", GETlinnum(code));
+		    a.getErrInfo(null, GETlinnum(code));
+		    SCOPECACHE_CLEAR();
+		    for (;;)
+		    {
+			if (scopex.length <= dimsave)
+			{
+			    ret.putVundefined();
+			    // 'a' may be pointing into the stack, which means
+			    // it gets scrambled on return. Therefore, we copy
+			    // its contents into a safe area in CallContext.
+			    assert(cc.value.sizeof == Value.sizeof);
+			    Value.copy(cast(Value*)cc.value, a);
+			    return cast(Value*)cc.value;
+			}
+			o = scopex[length - 1];
+			scopex = scopex[0 .. length - 1];	// pop entry off scope chain
+			if (o.isCatch())
+			{   ca = cast(Catch)o;
+			    //writef("catch('%s')\n", ca.name);
+			    o = new Dobject(Dobject.getPrototype());
+version (JSCRIPT_CATCH_BUG)
+{
+			    PutValue(cc, ca.name, a);
+}
+else
+{
+			    o.Put(ca.name, a, DontDelete);
+}
+			    scopex ~= o;
+			    cc.scopex = scopex;
+			    code = codestart + ca.offset;
+			    break;
+			}
+			else
+			{
+			    if (o.isFinally())
+			    {
+				f = cast(Finally)o;
+				v = cast(Value*)call(cc, othis, f.finallyblock, ret, locals);
+				if (v)
+				{   a = v;
+				    //writef("changing a\n");
+				}
+			    }
+			}
+		    }
+		    goto Lnext;
+
+		case IRtrycatch:
+		    SCOPECACHE_CLEAR();
+		    offset = (code - codestart) + (code + 1).offset;
+		    s = (code + 2).id.value.string;
+		    ca = new Catch(offset, s);
+		    scopex ~= ca;
+		    cc.scopex = scopex;
+		    code += 3;
+		    break;
+
+		case IRtryfinally:
+		    SCOPECACHE_CLEAR();
+		    f = new Finally(code + (code + 1).offset);
+		    scopex ~= f;
+		    cc.scopex = scopex;
+		    code += 2;
+		    break;
+
+		case IRassert:
+		{
+		    ErrInfo errinfo;
+		    errinfo.linnum = (code + 1).index;
+		    version (all) // Not supported under some com servers
+		    {
+			a = Dobject.RuntimeError(&errinfo, errmsgtbl[ERR_ASSERT], (code + 1).index);
+			goto Lthrow;
+		    }
+		    else
+		    {
+			RuntimeErrorx(ERR_ASSERT, (code + 1).index);
+		    }
+		    code += 2;
+		    break;
+		}
+
+		default:
+		    //writef("1: Unrecognized IR instruction %d\n", code.opcode);
+		    assert(0);              // unrecognized IR instruction
+	    }
+	}
+
+    Linterrupt:
+	ret.putVundefined();
+	return null;
+    }
+
+    /*******************************************
+     * This is a 'disassembler' for our interpreted code.
+     * Useful for debugging.
+     */
+
+    static void print(uint address, IR *code)
+    {
+	switch (code.opcode)
+	{
+	    case IRerror:
+		writef("\tIRerror\n");
+		break;
+
+	    case IRnop:
+		writef("\tIRnop\n");
+		break;
+
+	    case IRend:
+		writef("\tIRend\n");
+		break;
+
+	    case IRget:             // a = b.c
+		writef("\tIRget       %d, %d, %d\n",(code + 1).index, (code + 2).index, (code + 3).index);
+		break;
+
+	    case IRput:             // b.c = a
+		writef("\tIRput       %d, %d, %d\n",(code + 1).index, (code + 2).index, (code + 3).index);
+		break;
+
+	    case IRgets:            // a = b.s
+		writef("\tIRgets      %d, %d, '%s'\n",(code + 1).index, (code + 2).index, (code + 3).id.value.string);
+		break;
+
+	    case IRgetscope:        // a = othis.ident
+		writef("\tIRgetscope  %d, '%s', hash=%d\n",(code + 1).index,(code + 2).id.value.string,(code + 2).id.value.hash);
+		break;
+
+	    case IRaddass:          // b.c += a
+		writef("\tIRaddass    %d, %d, %d\n",(code + 1).index, (code + 2).index, (code + 3).index);
+		break;
+
+	    case IRaddasss:         // b.s += a
+		writef("\tIRaddasss   %d, %d, '%s'\n",(code + 1).index, (code + 2).index, (code + 3).id.value.string);
+		break;
+
+	    case IRaddassscope:     // othis.ident += a
+		writef("\tIRaddassscope  %d, '%s', hash=%d\n",(code + 1).index,(code + 2).id.value.string,(code + 3).index);
+		break;
+
+	    case IRputs:            // b.s = a
+		writef("\tIRputs      %d, %d, '%s'\n",(code + 1).index, (code + 2).index, (code + 3).id.value.string);
+		break;
+
+	    case IRputscope:        // s = a
+		writef("\tIRputscope  %d, '%s'\n",(code + 1).index, (code + 2).id.value.string);
+		break;
+
+	    case IRputdefault:            // b = a
+		writef("\tIRputdefault %d, %d\n",(code + 1).index, (code + 2).index);
+		break;
+
+	    case IRputthis:         // b = s
+		writef("\tIRputthis   '%s', %d\n",(code + 2).id.value.string,(code + 1).index);
+		break;
+
+	    case IRmov:             // a = b
+		writef("\tIRmov       %d, %d\n", (code + 1).index, (code + 2).index);
+		break;
+
+	    case IRstring:          // a = "string"
+		writef("\tIRstring    %d, '%s'\n",(code + 1).index,(code + 2).id.value.string);
+		break;
+
+	    case IRobject:          // a = object
+		writef("\tIRobject    %d, %x\n",(code + 1).index,cast(void*)(code + 2).object);
+		break;
+
+	    case IRthis:            // a = this
+		writef("\tIRthis      %d\n",(code + 1).index);
+		break;
+
+	    case IRnumber:          // a = number
+		writef("\tIRnumber    %d, %g\n",(code + 1).index,*cast(d_number *)(code + 2));
+		break;
+
+	    case IRboolean:         // a = boolean
+		writef("\tIRboolean   %d, %d\n",(code + 1).index, (code + 2).boolean);
+		break;
+
+	    case IRnull:            // a = null
+		writef("\tIRnull      %d\n",(code + 1).index);
+		break;
+
+	    case IRundefined:       // a = undefined
+		writef("\tIRundefined %d\n",(code + 1).index);
+		break;
+
+	    case IRthisget:         // a = othis.ident
+		writef("\tIRthisget   %d, '%s'\n",(code + 1).index,(code + 2).id.value.string);
+		break;
+
+	    case IRneg:             // a = -a
+		writef("\tIRneg      %d\n",(code + 1).index);
+		break;
+
+	    case IRpos:             // a = a
+		writef("\tIRpos      %d\n",(code + 1).index);
+		break;
+
+	    case IRcom:             // a = ~a
+		writef("\tIRcom      %d\n",(code + 1).index);
+		break;
+
+	    case IRnot:             // a = !a
+		writef("\tIRnot      %d\n",(code + 1).index);
+		break;
+
+	    case IRtypeof:          // a = typeof a
+		writef("\tIRtypeof   %d\n", (code + 1).index);
+		break;
+
+	    case IRinstance:        // a = b instanceof c
+		writef("\tIRinstance  %d, %d, %d\n", (code + 1).index, (code + 2).index, (code + 3).index);
+		break;
+
+	    case IRadd:             // a = b + c
+		writef("\tIRadd       %d, %d, %d\n",(code + 1).index, (code + 2).index, (code + 3).index);
+		break;
+
+	    case IRsub:             // a = b - c
+		writef("\tIRsub       %d, %d, %d\n",(code + 1).index, (code + 2).index, (code + 3).index);
+		break;
+
+	    case IRmul:             // a = b * c
+		writef("\tIRmul       %d, %d, %d\n",(code + 1).index, (code + 2).index, (code + 3).index);
+		break;
+
+	    case IRdiv:             // a = b / c
+		writef("\tIRdiv       %d, %d, %d\n",(code + 1).index, (code + 2).index, (code + 3).index);
+		break;
+
+	    case IRmod:             // a = b % c
+		writef("\tIRmod       %d, %d, %d\n",(code + 1).index, (code + 2).index, (code + 3).index);
+		break;
+
+	    case IRshl:             // a = b << c
+		writef("\tIRshl       %d, %d, %d\n",(code + 1).index, (code + 2).index, (code + 3).index);
+		break;
+
+	    case IRshr:             // a = b >> c
+		writef("\tIRshr       %d, %d, %d\n",(code + 1).index, (code + 2).index, (code + 3).index);
+		break;
+
+	    case IRushr:            // a = b >>> c
+		writef("\tIRushr      %d, %d, %d\n",(code + 1).index, (code + 2).index, (code + 3).index);
+		break;
+
+	    case IRand:             // a = b & c
+		writef("\tIRand       %d, %d, %d\n",(code + 1).index, (code + 2).index, (code + 3).index);
+		break;
+
+	    case IRor:              // a = b | c
+		writef("\tIRor        %d, %d, %d\n",(code + 1).index, (code + 2).index, (code + 3).index);
+		break;
+
+	    case IRxor:             // a = b ^ c
+		writef("\tIRxor       %d, %d, %d\n",(code + 1).index, (code + 2).index, (code + 3).index);
+		break;
+
+	    case IRpreinc:		// a = ++b.c
+		writef("\tIRpreinc  %d, %d, %d\n",(code + 1).index, (code + 2).index, (code + 3).index);
+		break;
+
+	    case IRpreincs:        // a = ++b.s
+		writef("\tIRpreincs %d, %d, %s\n",(code + 1).index, (code + 2).index, (code + 3).id.value.string);
+		break;
+
+	    case IRpreincscope:    // a = ++s
+		writef("\tIRpreincscope %d, '%s', hash=%d\n",(code + 1).index, (code + 2).id.value.string, (code + 3).hash);
+		break;
+
+	    case IRpredec:         // a = --b.c
+		writef("\tIRpredec  %d, %d, %d\n",(code + 1).index, (code + 2).index, (code + 3).index);
+		break;
+
+	    case IRpredecs:        // a = --b.s
+		writef("\tIRpredecs %d, %d, %s\n",(code + 1).index, (code + 2).index, (code + 3).id.value.string);
+		break;
+
+	    case IRpredecscope:    // a = --s
+		writef("\tIRpredecscope %d, '%s', hash=%d\n",(code + 1).index, (code + 2).id.value.string, (code + 3).hash);
+		break;
+
+	    case IRpostinc: // a = b.c++
+		writef("\tIRpostinc  %d, %d, %d\n",(code + 1).index, (code + 2).index, (code + 3).index);
+		break;
+
+	    case IRpostincs:        // a = b.s++
+		writef("\tIRpostincs %d, %d, %s\n",(code + 1).index, (code + 2).index, (code + 3).id.value.string);
+		break;
+
+	    case IRpostincscope:    // a = s++
+		writef("\tIRpostincscope %d, %s\n",(code + 1).index, (code + 2).id.value.string);
+		break;
+
+	    case IRpostdec:         // a = b.c--
+		writef("\tIRpostdec  %d, %d, %d\n",(code + 1).index, (code + 2).index, (code + 3).index);
+		break;
+
+	    case IRpostdecs:        // a = b.s--
+		writef("\tIRpostdecs %d, %d, %s\n",(code + 1).index, (code + 2).index, (code + 3).id.value.string);
+		break;
+
+	    case IRpostdecscope:    // a = s--
+		writef("\tIRpostdecscope %d, %s\n",(code + 1).index, (code + 2).id.value.string);
+		break;
+
+	    case IRdel:             // a = delete b.c
+		writef("\tIRdel       %d, %d, %d\n",(code + 1).index, (code + 2).index, (code + 3).index);
+		break;
+
+	    case IRdels:            // a = delete b.s
+		writef("\tIRdels      %d, %d, '%s'\n",(code + 1).index, (code + 2).index, (code + 3).id.value.string);
+		break;
+
+	    case IRdelscope:        // a = delete s
+		writef("\tIRdelscope  %d, '%s'\n",(code + 1).index, (code + 2).id.value.string);
+		break;
+
+	    case IRclt:             // a = (b <   c)
+		writef("\tIRclt       %d, %d, %d\n",(code + 1).index, (code + 2).index, (code + 3).index);
+		break;
+
+	    case IRcle:             // a = (b <=  c)
+		writef("\tIRcle       %d, %d, %d\n",(code + 1).index, (code + 2).index, (code + 3).index);
+		break;
+
+	    case IRcgt:             // a = (b >   c)
+		writef("\tIRcgt       %d, %d, %d\n",(code + 1).index, (code + 2).index, (code + 3).index);
+		break;
+
+	    case IRcge:             // a = (b >=  c)
+		writef("\tIRcge       %d, %d, %d\n",(code + 1).index, (code + 2).index, (code + 3).index);
+		break;
+
+	    case IRceq:             // a = (b ==  c)
+		writef("\tIRceq       %d, %d, %d\n",(code + 1).index, (code + 2).index, (code + 3).index);
+		break;
+
+	    case IRcne:             // a = (b !=  c)
+		writef("\tIRcne       %d, %d, %d\n",(code + 1).index, (code + 2).index, (code + 3).index);
+		break;
+
+	    case IRcid:             // a = (b === c)
+		writef("\tIRcid       %d, %d, %d\n",(code + 1).index, (code + 2).index, (code + 3).index);
+		break;
+
+	    case IRcnid:    // a = (b !== c)
+		writef("\tIRcnid      %d, %d, %d\n",(code + 1).index, (code + 2).index, (code + 3).index);
+		break;
+
+	    case IRjt:              // if (b) goto t
+		writef("\tIRjt        %d, %d\n", (code + 1).index + address, (code + 2).index);
+		break;
+
+	    case IRjf:              // if (!b) goto t
+		writef("\tIRjf        %d, %d\n", (code + 1).index + address, (code + 2).index);
+		break;
+
+	    case IRjtb:             // if (b) goto t
+		writef("\tIRjtb       %d, %d\n", (code + 1).index + address, (code + 2).index);
+		break;
+
+	    case IRjfb:             // if (!b) goto t
+		writef("\tIRjfb       %d, %d\n", (code + 1).index + address, (code + 2).index);
+		break;
+
+	    case IRjmp:
+		writef("\tIRjmp       %d\n", (code + 1).offset + address);
+		break;
+
+	    case IRjlt:             // if (b < c) goto t
+		writef("\tIRjlt       %d, %d, %d\n",(code + 1).index + address, (code + 2).index, (code + 3).index);
+		break;
+
+	    case IRjle:             // if (b <= c) goto t
+		writef("\tIRjle       %d, %d, %d\n",(code + 1).index + address, (code + 2).index, (code + 3).index);
+		break;
+
+	    case IRjltc:            // if (b < constant) goto t
+		writef("\tIRjltc      %d, %d, %g\n",(code + 1).index + address, (code + 2).index, *cast(d_number *)(code + 3));
+		break;
+
+	    case IRjlec:            // if (b <= constant) goto t
+		writef("\tIRjlec      %d, %d, %g\n",(code + 1).index + address, (code + 2).index, *cast(d_number *)(code + 3));
+		break;
+
+	    case IRiter:            // a = iter(b)
+		writef("\tIRiter    %d, %d\n",(code + 1).index, (code + 2).index);
+		break;
+
+	    case IRnext:            // a, b.c, iter
+		writef("\tIRnext    %d, %d, %d, %d\n",
+			(code + 1).index,
+			(code + 2).index,
+			(code + 3).index,
+			(code + 4).index);
+		break;
+
+	    case IRnexts:           // a, b.s, iter
+		writef("\tIRnexts   %d, %d, '%s', %d\n",
+			(code + 1).index,
+			(code + 2).index,
+			(code + 3).id.value.string,
+			(code + 4).index);
+		break;
+
+	    case IRnextscope:       // a, s, iter
+		writef
+		    ("\tIRnextscope   %d, '%s', %d\n",
+			(code + 1).index,
+			(code + 2).id.value.string,
+			(code + 3).index);
+		break;
+
+	    case IRcall:            // a = b.c(argc, argv)
+		writef("\tIRcall     %d,%d,%d, argc=%d, argv=%d \n",
+			(code + 1).index,
+			(code + 2).index,
+			(code + 3).index,
+			(code + 4).index,
+			(code + 5).index);
+		break;
+
+	    case IRcalls:           // a = b.s(argc, argv)
+		writef
+		    ("\tIRcalls     %d,%d,'%s', argc=%d, argv=%d \n",
+			(code + 1).index,
+			(code + 2).index,
+			(code + 3).id.value.string,
+			(code + 4).index,
+			(code + 5).index);
+		break;
+
+	    case IRcallscope:       // a = s(argc, argv)
+		writef
+		    ("\tIRcallscope %d,'%s', argc=%d, argv=%d \n",
+			(code + 1).index,
+			(code + 2).id.value.string,
+			(code + 3).index,
+			(code + 4).index);
+		break;
+
+	    case IRputcall:            // a = b.c(argc, argv)
+		writef("\tIRputcall  %d,%d,%d, argc=%d, argv=%d \n",
+			(code + 1).index,
+			(code + 2).index,
+			(code + 3).index,
+			(code + 4).index,
+			(code + 5).index);
+		break;
+
+	    case IRputcalls:           // a = b.s(argc, argv)
+		writef
+		    ("\tIRputcalls  %d,%d,'%s', argc=%d, argv=%d \n",
+			(code + 1).index,
+			(code + 2).index,
+			(code + 3).id.value.string,
+			(code + 4).index,
+			(code + 5).index);
+		break;
+
+	    case IRputcallscope:       // a = s(argc, argv)
+		writef
+		    ("\tIRputcallscope %d,'%s', argc=%d, argv=%d \n",
+			(code + 1).index,
+			(code + 2).id.value.string,
+			(code + 3).index,
+			(code + 4).index);
+		break;
+
+	    case IRcallv:           // a = v(argc, argv)
+		writef("\tIRcallv    %d, %d(argc=%d, argv=%d)\n",
+			(code + 1).index,
+			(code + 2).index,
+			(code + 3).index,
+			(code + 4).index);
+		break;
+
+	    case IRputcallv:           // a = v(argc, argv)
+		writef("\tIRputcallv %d, %d(argc=%d, argv=%d)\n",
+			(code + 1).index,
+			(code + 2).index,
+			(code + 3).index,
+			(code + 4).index);
+		break;
+
+	    case IRnew:     // a = new b(argc, argv)
+		writef("\tIRnew      %d,%d, argc=%d, argv=%d \n",
+			(code + 1).index,
+			(code + 2).index,
+			(code + 3).index,
+			(code + 4).index);
+		break;
+
+	    case IRpush:
+		writef("\tIRpush    %d\n",(code + 1).index);
+		break;
+
+	    case IRpop:
+		writef("\tIRpop\n");
+		break;
+
+	    case IRret:
+		writef("\tIRret\n");
+		return;
+
+	    case IRretexp:
+		writef("\tIRretexp    %d\n",(code + 1).index);
+		return;
+
+	    case IRimpret:
+		writef("\tIRimpret    %d\n",(code + 1).index);
+		return;
+
+	    case IRthrow:
+		writef("\tIRthrow     %d\n",(code + 1).index);
+		break;
+
+	    case IRassert:
+		writef("\tIRassert    %d\n",(code + 1).index);
+		break;
+
+	    case IRtrycatch:
+		writef("\tIRtrycatch  %d, '%s'\n", (code + 1).offset + address, (code + 2).id.value.string);
+		break;
+
+	    case IRtryfinally:
+		writef("\tIRtryfinally %d\n", (code + 1).offset + address);
+		break;
+
+	    case IRfinallyret:
+		writef("\tIRfinallyret\n");
+		break;
+
+	    default:
+		writef("2: Unrecognized IR instruction %d\n", code.opcode);
+		assert(0);          // unrecognized IR instruction
+	}
+    }
+
+    /*********************************
+     * Give size of opcode.
+     */
+
+    static uint size(uint opcode)
+    {   uint sz = 9999;
+
+	switch (opcode)
+	{
+	    case IRerror:
+	    case IRnop:
+	    case IRend:
+		sz = 1;
+		break;
+
+	    case IRget:             // a = b.c
+	    case IRaddass:
+		sz = 4;
+		break;
+
+	    case IRput:             // b.c = a
+		sz = 4;
+		break;
+
+	    case IRgets:            // a = b.s
+	    case IRaddasss:
+		sz = 4;
+		break;
+
+	    case IRgetscope:        // a = s
+		sz = 3;
+		break;
+
+	    case IRaddassscope:
+		sz = 4;
+		break;
+
+	    case IRputs:            // b.s = a
+		sz = 4;
+		break;
+
+	    case IRputscope:        // s = a
+	    case IRputdefault:	// b = a
+		sz = 3;
+		break;
+
+	    case IRputthis:         // a = s
+		sz = 3;
+		break;
+
+	    case IRmov:             // a = b
+		sz = 3;
+		break;
+
+	    case IRstring:          // a = "string"
+		sz = 3;
+		break;
+
+	    case IRobject:          // a = object
+		sz = 3;
+		break;
+
+	    case IRthis:            // a = this
+		sz = 2;
+		break;
+
+	    case IRnumber:          // a = number
+		sz = 4;
+		break;
+
+	    case IRboolean:         // a = boolean
+		sz = 3;
+		break;
+
+	    case IRnull:            // a = null
+		sz = 2;
+		break;
+
+	    case IRundefined:       // a = undefined
+		sz = 2;
+		break;
+
+	    case IRthisget:         // a = othis.ident
+		sz = 3;
+		break;
+
+	    case IRneg:             // a = -a
+	    case IRpos:             // a = a
+	    case IRcom:             // a = ~a
+	    case IRnot:             // a = !a
+	    case IRtypeof:          // a = typeof a
+		sz = 2;
+		break;
+
+	    case IRinstance:        // a = b instanceof c
+	    case IRadd:             // a = b + c
+	    case IRsub:             // a = b - c
+	    case IRmul:             // a = b * c
+	    case IRdiv:             // a = b / c
+	    case IRmod:             // a = b % c
+	    case IRshl:             // a = b << c
+	    case IRshr:             // a = b >> c
+	    case IRushr:            // a = b >>> c
+	    case IRand:             // a = b & c
+	    case IRor:              // a = b | c
+	    case IRxor:             // a = b ^ c
+		sz = 4;
+		break;
+
+	    case IRpreinc:         // a = ++b.c
+	    case IRpreincs:        // a = ++b.s
+	    case IRpredec:         // a = --b.c
+	    case IRpredecs:        // a = --b.s
+	    case IRpostinc:         // a = b.c++
+	    case IRpostincs:        // a = b.s++
+	    case IRpostdec:         // a = b.c--
+	    case IRpostdecs:        // a = b.s--
+		sz = 4;
+		break;
+
+	    case IRpostincscope:    // a = s++
+	    case IRpostdecscope:    // a = s--
+		sz = 3;
+		break;
+
+	    case IRpreincscope:	// a = ++s
+	    case IRpredecscope:	// a = --s
+		sz = 4;
+		break;
+
+	    case IRdel:             // a = delete b.c
+	    case IRdels:            // a = delete b.s
+		sz = 4;
+		break;
+
+	    case IRdelscope:        // a = delete s
+		sz = 3;
+		break;
+
+	    case IRclt:             // a = (b <   c)
+	    case IRcle:             // a = (b <=  c)
+	    case IRcgt:             // a = (b >   c)
+	    case IRcge:             // a = (b >=  c)
+	    case IRceq:             // a = (b ==  c)
+	    case IRcne:             // a = (b !=  c)
+	    case IRcid:             // a = (b === c)
+	    case IRcnid:            // a = (b !== c)
+	    case IRjlt:             // if (b < c) goto t
+	    case IRjle:             // if (b <= c) goto t
+		sz = 4;
+		break;
+
+	    case IRjltc:            // if (b < constant) goto t
+	    case IRjlec:            // if (b <= constant) goto t
+		sz = 5;
+		break;
+
+	    case IRjt:              // if (b) goto t
+	    case IRjf:              // if (!b) goto t
+	    case IRjtb:             // if (b) goto t
+	    case IRjfb:             // if (!b) goto t
+		sz = 3;
+		break;
+
+	    case IRjmp:
+		sz = 2;
+		break;
+
+	    case IRiter:            // a = iter(b)
+		sz = 3;
+		break;
+
+	    case IRnext:            // a, b.c, iter
+	    case IRnexts:           // a, b.s, iter
+		sz = 5;
+		break;
+
+	    case IRnextscope:       // a, s, iter
+		sz = 4;
+		break;
+
+	    case IRcall:            // a = b.c(argc, argv)
+	    case IRcalls:           // a = b.s(argc, argv)
+	    case IRputcall:         //  b.c(argc, argv) = a
+	    case IRputcalls:        //  b.s(argc, argv) = a
+		sz = 6;
+		break;
+
+	    case IRcallscope:       // a = s(argc, argv)
+	    case IRputcallscope:    // s(argc, argv) = a
+	    case IRcallv:
+	    case IRputcallv:
+		sz = 5;
+		break;
+
+	    case IRnew:             // a = new b(argc, argv)
+		sz = 5;
+		break;
+
+	    case IRpush:
+		sz = 2;
+		break;
+
+	    case IRpop:
+		sz = 1;
+		break;
+
+	    case IRfinallyret:
+	    case IRret:
+		sz = 1;
+		break;
+
+	    case IRretexp:
+	    case IRimpret:
+	    case IRthrow:
+		sz = 2;
+		break;
+
+	    case IRtrycatch:
+		sz = 3;
+		break;
+
+	    case IRtryfinally:
+		sz = 2;
+		break;
+
+	    case IRassert:
+		sz = 2;
+		break;
+
+	    default:
+		writef("3: Unrecognized IR instruction %d, IRMAX = %d\n", opcode, IRMAX);
+		assert(0);          // unrecognized IR instruction
+	}
+	assert(sz <= 6);
+	return sz;
+    }
+
+    static void printfunc(IR *code)
+    {
+	IR *codestart = code;
+
+	for (;;)
+	{
+	    writef("%2d(%d):", code - codestart, code.linnum);
+	    print(code - codestart, code);
+	    if (code.opcode == IRend)
+		return;
+	    code += size(code.opcode);
+	}
+    }
+
+    /***************************************
+     * Verify that it is a correct sequence of code.
+     * Useful for isolating memory corruption bugs.
+     */
+
+    static uint verify(uint linnum, IR *codestart)
+    {
+      debug (VERIFY)
+      {
+	uint checksum = 0;
+	uint sz;
+	uint i;
+	IR *code;
+
+	// Verify code
+	for (code = codestart;;)
+	{
+	    switch (code.opcode)
+	    {
+		case IRend:
+		    return checksum;
+
+		case IRerror:
+		    writef("verify failure line %u\n", linnum);
+		    assert(0);
+		    break;
+
+		default:
+		    if (code.opcode >= IRMAX)
+		    {   writef("undefined opcode %d in code %p\n", code.opcode, codestart);
+			assert(0);
+		    }
+		    sz = IR.size(code.opcode);
+		    for (i = 0; i < sz; i++)
+		    {   checksum += code.opcode;
+			code++;
+		    }
+		    break;
+	    }
+	}
+      }
+      else
+	return 0;
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/dmdscript_tango/parse.d	Sun Jan 24 12:34:47 2010 +0200
@@ -0,0 +1,1427 @@
+
+/* 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.parse;
+
+import dmdscript.script;
+import dmdscript.lexer;
+import dmdscript.functiondefinition;
+import dmdscript.expression;
+import dmdscript.statement;
+import dmdscript.identifier;
+import dmdscript.ir;
+import dmdscript.errmsgs;
+
+class Parser : Lexer
+{
+    uint flags;
+
+    enum
+    {
+	normal		= 0,
+	initial		= 1,
+
+	allowIn		= 0,
+	noIn		= 2,
+
+	// Flag if we're in the for statement header, as
+	// automatic semicolon insertion is suppressed inside it.
+	inForHeader	= 4,
+    }
+
+    FunctionDefinition lastnamedfunc;
+
+
+    this(char[] sourcename, tchar[] base, int useStringtable)
+    {
+	//writefln("Parser.this(base = '%s')", base);
+	super(sourcename, base, useStringtable);
+	nextToken();		// start up the scanner
+    }
+
+    ~this()
+    {
+	lastnamedfunc = null;
+    }
+
+
+    /**********************************************
+     * Return !=0 on error, and fill in *perrinfo.
+     */
+
+    static int parseFunctionDefinition(out FunctionDefinition pfd,
+	    d_string params, d_string bdy, out ErrInfo perrinfo)
+    {
+	Parser p;
+	Identifier*[] parameters;
+	TopStatement[] topstatements;
+	FunctionDefinition fd = null;
+	int result;
+
+	p = new Parser("anonymous", params, 0);
+
+	// Parse FormalParameterList
+	while (p.token.value != TOKeof)
+	{
+	    if (p.token.value != TOKidentifier)
+	    {
+		p.error(errmsgtbl[ERR_FPL_EXPECTED_IDENTIFIER], p.token.toString());
+		goto Lreturn;
+	    }
+	    parameters ~= p.token.ident;
+	    p.nextToken();
+	    if (p.token.value == TOKcomma)
+		p.nextToken();
+	    else if (p.token.value == TOKeof)
+		break;
+	    else
+	    {
+		p.error(errmsgtbl[ERR_FPL_EXPECTED_COMMA], p.token.toString());
+		goto Lreturn;
+	    }
+	}
+	if (p.errinfo.message)
+	    goto Lreturn;
+
+	delete p;
+
+	// Parse StatementList
+	p = new Parser("anonymous", bdy, 0);
+	for (;;)
+	{   TopStatement ts;
+
+	    if (p.token.value == TOKeof)
+		break;
+	    ts = p.parseStatement();
+	    topstatements ~= ts;
+	}
+
+	fd = new FunctionDefinition(0, 0, null, parameters, topstatements);
+	fd.isanonymous = 1;
+
+    Lreturn:
+	pfd = fd;
+	perrinfo = p.errinfo;
+	result = (p.errinfo.message != null);
+	delete p;
+	p = null;
+	return result;
+    }
+
+    /**********************************************
+     * Return !=0 on error, and fill in *perrinfo.
+     */
+
+    int parseProgram(out TopStatement[] topstatements, ErrInfo *perrinfo)
+    {
+	topstatements = parseTopStatements();
+	check(TOKeof);
+	//writef("parseProgram done\n");
+	*perrinfo = errinfo;
+	//clearstack();
+	return errinfo.message != null;
+    }
+
+    TopStatement[] parseTopStatements()
+    {
+	TopStatement[] topstatements;
+	TopStatement ts;
+
+	//writefln("parseTopStatements()");
+	for (;;)
+	{
+	    switch (token.value)
+	    {
+		case TOKfunction:
+		    ts = parseFunction(0);
+		    topstatements ~= ts;
+		    break;
+
+		case TOKeof:
+		    return topstatements;
+
+		case TOKrbrace:
+		    return topstatements;
+
+		default:
+		    ts = parseStatement();
+		    topstatements ~= ts;
+		    break;
+	    }
+	}
+	assert(0);
+    }
+
+    /***************************
+     * flag:
+     *	0	Function statement
+     *	1	Function literal
+     */
+
+    TopStatement parseFunction(int flag)
+    {   Identifier* name;
+	Identifier*[] parameters;
+	TopStatement[] topstatements;
+	FunctionDefinition f;
+	Expression e = null;
+	Loc loc;
+
+	//writef("parseFunction()\n");
+	loc = currentline;
+	nextToken();
+	name = null;
+	if (token.value == TOKidentifier)
+	{
+	    name = token.ident;
+	    nextToken();
+
+	    if (!flag && token.value == TOKdot)
+	    {
+		// Regard:
+		//	function A.B() { }
+		// as:
+		//	A.B = function() { }
+		// This is not ECMA, but a jscript feature
+
+		e = new IdentifierExpression(loc, name);
+		name = null;
+
+		while (token.value == TOKdot)
+		{
+		    nextToken();
+		    if (token.value == TOKidentifier)
+		    {	e = new DotExp(loc, e, token.ident);
+			nextToken();
+		    }
+		    else
+		    {
+			error(errmsgtbl[ERR_EXPECTED_IDENTIFIER_2PARAM], ".", token.toString());
+			break;
+		    }
+		}
+	    }
+	}
+
+	check(TOKlparen);
+	if (token.value == TOKrparen)
+	    nextToken();
+	else
+	{
+	    for (;;)
+	    {
+		if (token.value == TOKidentifier)
+		{
+		    parameters ~= token.ident;
+		    nextToken();
+		    if (token.value == TOKcomma)
+		    {   nextToken();
+			continue;
+		    }
+		    if (!check(TOKrparen))
+			break;
+		}
+		else
+		    error(ERR_EXPECTED_IDENTIFIER);
+		break;
+	    }
+	}
+
+	check(TOKlbrace);
+	topstatements = parseTopStatements();
+	check(TOKrbrace);
+
+	f = new FunctionDefinition(loc, 0, name, parameters, topstatements);
+
+	lastnamedfunc = f;
+
+	//writef("parseFunction() done\n");
+	if (!e)
+	    return f;
+
+	// Construct:
+	//	A.B = function() { }
+
+	Expression e2 = new FunctionLiteral(loc, f);
+
+	e = new AssignExp(loc, e, e2);
+
+	Statement s = new ExpStatement(loc, e);
+
+	return s;
+    }
+
+    /*****************************************
+     */
+
+    Statement parseStatement()
+    {   Statement s;
+	Token *t;
+	Loc loc;
+
+	//writefln("parseStatement()");
+	loc = currentline;
+	switch (token.value)
+	{
+	    case TOKidentifier:
+	    case TOKthis:
+		// Need to look ahead to see if it is a declaration, label, or expression
+		t = peek(&token);
+		if (t.value == TOKcolon && token.value == TOKidentifier)
+		{   // It's a label
+		    Identifier *ident;
+
+		    ident = token.ident;
+		    nextToken();
+		    nextToken();
+		    s = parseStatement();
+		    s = new LabelStatement(loc, ident, s);
+		}
+		else if (t.value == TOKassign ||
+			 t.value == TOKdot ||
+			 t.value == TOKlbracket)
+		{   Expression exp;
+
+		    exp = parseExpression();
+		    parseOptionalSemi();
+		    s = new ExpStatement(loc, exp);
+		}
+		else
+		{   Expression exp;
+
+		    exp = parseExpression(initial);
+		    parseOptionalSemi();
+		    s = new ExpStatement(loc, exp);
+		}
+		break;
+
+	    case TOKreal:
+	    case TOKstring:
+	    case TOKdelete:
+	    case TOKlparen:
+	    case TOKplusplus:
+	    case TOKminusminus:
+	    case TOKplus:
+	    case TOKminus:
+	    case TOKnot:
+	    case TOKtilde:
+	    case TOKtypeof:
+	    case TOKnull:
+	    case TOKnew:
+	    case TOKtrue:
+	    case TOKfalse:
+	    case TOKvoid:
+	    {   Expression exp;
+
+		exp = parseExpression(initial);
+		parseOptionalSemi();
+		s = new ExpStatement(loc, exp);
+		break;
+	    }
+
+	    case TOKvar:
+	    {
+		Identifier *ident;
+		Expression init;
+		VarDeclaration v;
+		VarStatement vs;
+
+		vs = new VarStatement(loc);
+		s = vs;
+
+		nextToken();
+		for (;;)
+		{   loc = currentline;
+
+		    if (token.value != TOKidentifier)
+		    {
+			error(errmsgtbl[ERR_EXPECTED_IDENTIFIER_PARAM], token.toString());
+			break;
+		    }
+		    ident = token.ident;
+		    init = null;
+		    nextToken();
+		    if (token.value == TOKassign)
+		    {   uint flags_save;
+
+			nextToken();
+			flags_save = flags;
+			flags &= ~initial;
+			init = parseAssignExp();
+			flags = flags_save;
+		    }
+		    v = new VarDeclaration(loc, ident, init);
+		    vs.vardecls ~= v;
+		    if (token.value != TOKcomma)
+			break;
+		    nextToken();
+		}
+		if (!(flags & inForHeader))
+		    parseOptionalSemi();
+		break;
+	    }
+
+	    case TOKlbrace:
+	    {   BlockStatement bs;
+
+		nextToken();
+		bs = new BlockStatement(loc);
+		while (token.value != TOKrbrace)
+		{
+		    if (token.value == TOKeof)
+		    {   /* { */
+			error(ERR_UNTERMINATED_BLOCK);
+			break;
+		    }
+		    bs.statements ~= parseStatement();
+		}
+		s = bs;
+		nextToken();
+
+		// The following is to accommodate the jscript bug:
+		//	if (i) {return(0);}; else ...
+		if (token.value == TOKsemicolon)
+		    nextToken();
+
+		break;
+	    }
+
+	    case TOKif:
+	    {   Expression condition;
+		Statement ifbody;
+		Statement elsebody;
+
+		nextToken();
+		condition = parseParenExp();
+		ifbody = parseStatement();
+		if (token.value == TOKelse)
+		{
+		    nextToken();
+		    elsebody = parseStatement();
+		}
+		else
+		    elsebody = null;
+		s = new IfStatement(loc, condition, ifbody, elsebody);
+		break;
+	    }
+
+	    case TOKswitch:
+	    {   Expression condition;
+		Statement bdy;
+
+		nextToken();
+		condition = parseParenExp();
+		bdy = parseStatement();
+		s = new SwitchStatement(loc, condition, bdy);
+		break;
+	    }
+
+	    case TOKcase:
+	    {   Expression exp;
+
+		nextToken();
+		exp = parseExpression();
+		check(TOKcolon);
+		s = new CaseStatement(loc, exp);
+		break;
+	    }
+
+	    case TOKdefault:
+		nextToken();
+		check(TOKcolon);
+		s = new DefaultStatement(loc);
+		break;
+
+	    case TOKwhile:
+	    {   Expression condition;
+		Statement bdy;
+
+		nextToken();
+		condition = parseParenExp();
+		bdy = parseStatement();
+		s = new WhileStatement(loc, condition, bdy);
+		break;
+	    }
+
+	    case TOKsemicolon:
+		nextToken();
+		s = new EmptyStatement(loc);
+		break;
+
+	    case TOKdo:
+	    {   Statement bdy;
+		Expression condition;
+
+		nextToken();
+		bdy = parseStatement();
+		check(TOKwhile);
+		condition = parseParenExp();
+		parseOptionalSemi();
+		s = new DoStatement(loc, bdy, condition);
+		break;
+	    }
+
+	    case TOKfor:
+	    {
+		Statement init;
+		Statement bdy;
+
+		nextToken();
+		flags |= inForHeader;
+		check(TOKlparen);
+		if (token.value == TOKvar)
+		{
+		    init = parseStatement();
+		}
+		else
+		{   Expression e;
+
+		    e = parseOptionalExpression(noIn);
+		    init = e ? new ExpStatement(loc, e) : null;
+		}
+
+		if (token.value == TOKsemicolon)
+		{   Expression condition;
+		    Expression increment;
+
+		    nextToken();
+		    condition = parseOptionalExpression();
+		    check(TOKsemicolon);
+		    increment = parseOptionalExpression();
+		    check(TOKrparen);
+		    flags &= ~inForHeader;
+
+		    bdy = parseStatement();
+		    s = new ForStatement(loc, init, condition, increment, bdy);
+		}
+		else if (token.value == TOKin)
+		{   Expression inexp;
+		    VarStatement vs;
+
+		    // Check that there's only one VarDeclaration
+		    // in init.
+		    if (init.st == VARSTATEMENT)
+		    {
+			vs = cast(VarStatement)init;
+			if (vs.vardecls.length != 1)
+			    error(errmsgtbl[ERR_TOO_MANY_IN_VARS], vs.vardecls.length);
+		    }
+
+		    nextToken();
+		    inexp = parseExpression();
+		    check(TOKrparen);
+		    flags &= ~inForHeader;
+		    bdy = parseStatement();
+		    s = new ForInStatement(loc, init, inexp, bdy);
+		}
+		else
+		{
+		    error(errmsgtbl[ERR_IN_EXPECTED], token.toString());
+		    s = null;
+		}
+		break;
+	    }
+
+	    case TOKwith:
+	    {   Expression exp;
+		Statement bdy;
+
+		nextToken();
+		exp = parseParenExp();
+		bdy = parseStatement();
+		s = new WithStatement(loc, exp, bdy);
+		break;
+	    }
+
+	    case TOKbreak:
+	    {   Identifier *ident;
+
+		nextToken();
+		if (token.sawLineTerminator && token.value != TOKsemicolon)
+		{   // Assume we saw a semicolon
+		    ident = null;
+		}
+		else
+		{
+		    if (token.value == TOKidentifier)
+		    {   ident = token.ident;
+			nextToken();
+		    }
+		    else
+			ident = null;
+		    parseOptionalSemi();
+		}
+		s = new BreakStatement(loc, ident);
+		break;
+	    }
+
+	    case TOKcontinue:
+	    {   Identifier *ident;
+
+		nextToken();
+		if (token.sawLineTerminator && token.value != TOKsemicolon)
+		{   // Assume we saw a semicolon
+		    ident = null;
+		}
+		else
+		{
+		    if (token.value == TOKidentifier)
+		    {   ident = token.ident;
+			nextToken();
+		    }
+		    else
+			ident = null;
+		    parseOptionalSemi();
+		}
+		s = new ContinueStatement(loc, ident);
+		break;
+	    }
+
+	    case TOKgoto:
+	    {   Identifier *ident;
+
+		nextToken();
+		if (token.value != TOKidentifier)
+		{   error(errmsgtbl[ERR_GOTO_LABEL_EXPECTED], token.toString());
+		    s = null;
+		    break;
+		}
+		ident = token.ident;
+		nextToken();
+		parseOptionalSemi();
+		s = new GotoStatement(loc, ident);
+		break;
+	    }
+
+	    case TOKreturn:
+	    {   Expression exp;
+
+		nextToken();
+		if (token.sawLineTerminator && token.value != TOKsemicolon)
+		{   // Assume we saw a semicolon
+		    s = new ReturnStatement(loc, null);
+		}
+		else
+		{   exp = parseOptionalExpression();
+		    parseOptionalSemi();
+		    s = new ReturnStatement(loc, exp);
+		}
+		break;
+	    }
+
+	    case TOKthrow:
+	    {   Expression exp;
+
+		nextToken();
+		exp = parseExpression();
+		parseOptionalSemi();
+		s = new ThrowStatement(loc, exp);
+		break;
+	    }
+
+	    case TOKtry:
+	    {   Statement bdy;
+		Identifier *catchident;
+		Statement catchbody;
+		Statement finalbody;
+
+		nextToken();
+		bdy = parseStatement();
+		if (token.value == TOKcatch)
+		{
+		    nextToken();
+		    check(TOKlparen);
+		    catchident = null;
+		    if (token.value == TOKidentifier)
+			catchident = token.ident;
+		    check(TOKidentifier);
+		    check(TOKrparen);
+		    catchbody = parseStatement();
+		}
+		else
+		{   catchident = null;
+		    catchbody = null;
+		}
+
+		if (token.value == TOKfinally)
+		{   nextToken();
+		    finalbody = parseStatement();
+		}
+		else
+		    finalbody = null;
+
+		if (!catchbody && !finalbody)
+		{   error(ERR_TRY_CATCH_EXPECTED);
+		    s = null;
+		}
+		else
+		{
+		    s = new TryStatement(loc, bdy, catchident, catchbody, finalbody);
+		}
+		break;
+	    }
+
+	    default:
+		error(errmsgtbl[ERR_STATEMENT_EXPECTED], token.toString());
+		nextToken();
+		s = null;
+		break;
+	}
+
+	//writefln("parseStatement() done");
+	return s;
+    }
+
+
+
+    Expression parseOptionalExpression(uint flags = 0)
+    {
+	Expression e;
+
+	if (token.value == TOKsemicolon || token.value == TOKrparen)
+	    e = null;
+	else
+	    e = parseExpression(flags);
+	return e;
+    }
+
+    // Follow ECMA 7.8.1 rules for inserting semicolons
+    void parseOptionalSemi()
+    {
+	if (token.value != TOKeof &&
+	    token.value != TOKrbrace &&
+	    !(token.sawLineTerminator && (flags & inForHeader) == 0)
+	   )
+	    check(TOKsemicolon);
+    }
+
+    int check(TOK value)
+    {
+	if (token.value != value)
+	{
+	    error(errmsgtbl[ERR_EXPECTED_GENERIC], token.toString(), Token.toString(value));
+	    return 0;
+	}
+	nextToken();
+	return 1;
+    }
+
+    /********************************* Expression Parser ***************************/
+
+
+    Expression parseParenExp()
+    {   Expression e;
+
+	check(TOKlparen);
+	e = parseExpression();
+	check(TOKrparen);
+	return e;
+    }
+
+    Expression parsePrimaryExp(int innew)
+    {   Expression e;
+	Loc loc;
+
+	loc = currentline;
+	switch (token.value)
+	{
+	    case TOKthis:
+		e = new ThisExpression(loc);
+		nextToken();
+		break;
+
+	    case TOKnull:
+		e = new NullExpression(loc);
+		nextToken();
+		break;
+
+	    case TOKtrue:
+		e = new BooleanExpression(loc, 1);
+		nextToken();
+		break;
+
+	    case TOKfalse:
+		e = new BooleanExpression(loc, 0);
+		nextToken();
+		break;
+
+	    case TOKreal:
+		e = new RealExpression(loc, token.realvalue);
+		nextToken();
+		break;
+
+	    case TOKstring:
+		e = new StringExpression(loc, token.string);
+		token.string = null;	// release to gc
+		nextToken();
+		break;
+
+	    case TOKregexp:
+		e = new RegExpLiteral(loc, token.string);
+		token.string = null;	// release to gc
+		nextToken();
+		break;
+
+	    case TOKidentifier:
+		e = new IdentifierExpression(loc, token.ident);
+		token.ident = null;		// release to gc
+		nextToken();
+		break;
+
+	    case TOKlparen:
+		e = parseParenExp();
+		break;
+
+	    case TOKlbracket:
+		e = parseArrayLiteral();
+		break;
+
+	    case TOKlbrace:
+		if (flags & initial)
+		{
+		    error(ERR_OBJ_LITERAL_IN_INITIALIZER);
+		    nextToken();
+		    return null;
+		}
+		e = parseObjectLiteral();
+		break;
+
+	    case TOKfunction:
+    //	    if (flags & initial)
+    //		goto Lerror;
+		e = parseFunctionLiteral();
+		break;
+
+	    case TOKnew:
+	    {   Expression newarg;
+		Expression[] arguments;
+
+		nextToken();
+		newarg = parsePrimaryExp(1);
+		arguments = parseArguments();
+		e = new NewExp(loc, newarg, arguments);
+		break;
+	    }
+
+	    default:
+    //	Lerror:
+		error(errmsgtbl[ERR_EXPECTED_EXPRESSION], token.toString());
+		nextToken();
+		return null;
+	}
+	return parsePostExp(e, innew);
+    }
+
+    Expression[] parseArguments()
+    {
+	Expression[] arguments = null;
+
+	if (token.value == TOKlparen)
+	{
+	    nextToken();
+	    if (token.value != TOKrparen)
+	    {
+		for (;;)
+		{   Expression arg;
+
+		    arg = parseAssignExp();
+		    arguments ~= arg;
+		    if (token.value == TOKrparen)
+			break;
+		    if (!check(TOKcomma))
+			break;
+		}
+	    }
+	    nextToken();
+	}
+	return arguments;
+    }
+
+    Expression parseArrayLiteral()
+    {
+	Expression e;
+	Expression[] elements;
+	Loc loc;
+
+	//writef("parseArrayLiteral()\n");
+	loc = currentline;
+	check(TOKlbracket);
+	if (token.value != TOKrbracket)
+	{
+	    for (;;)
+	    {
+		if (token.value == TOKcomma)
+		    // Allow things like [1,2,,,3,]
+		    // Like Explorer 4, and unlike Netscape, the
+		    // trailing , indicates another null element.
+		    elements ~= cast(Expression)null;
+		else if (token.value == TOKrbracket)
+		{
+		    elements ~= cast(Expression)null;
+		    break;
+		}
+		else
+		{   e = parseAssignExp();
+		    elements ~= e;
+		    if (token.value != TOKcomma)
+			break;
+		}
+		nextToken();
+	    }
+	}
+	check(TOKrbracket);
+	e = new ArrayLiteral(loc, elements);
+	return e;
+    }
+
+    Expression parseObjectLiteral()
+    {
+	Expression e;
+	Field[] fields;
+	Loc loc;
+
+	//writef("parseObjectLiteral()\n");
+	loc = currentline;
+	check(TOKlbrace);
+	if (token.value == TOKrbrace)
+	    nextToken();
+	else
+	{
+	    for (;;)
+	    {   Field f;
+		Identifier* ident;
+
+		if (token.value != TOKidentifier)
+		{   error(ERR_EXPECTED_IDENTIFIER);
+		    break;
+		}
+		ident = token.ident;
+		nextToken();
+		check(TOKcolon);
+		f = new Field(ident, parseAssignExp());
+		fields ~= f;
+		if (token.value != TOKcomma)
+		    break;
+		nextToken();
+	    }
+	    check(TOKrbrace);
+	}
+	e = new ObjectLiteral(loc, fields);
+	return e;
+    }
+
+    Expression parseFunctionLiteral()
+    {   FunctionDefinition f;
+	Loc loc;
+
+	loc = currentline;
+	f = cast(FunctionDefinition)parseFunction(1);
+	return new FunctionLiteral(loc, f);
+    }
+
+    Expression parsePostExp(Expression e, int innew)
+    {   Loc loc;
+
+	for (;;)
+	{
+	    loc = currentline;
+	    //loc = (Loc)token.ptr;
+	    switch (token.value)
+	    {
+		case TOKdot:
+		    nextToken();
+		    if (token.value == TOKidentifier)
+		    {
+			e = new DotExp(loc, e, token.ident);
+		    }
+		    else
+		    {
+			error(errmsgtbl[ERR_EXPECTED_IDENTIFIER_2PARAM], ".", token.toString());
+			return e;
+		    }
+		    break;
+
+		case TOKplusplus:
+		    if (token.sawLineTerminator && !(flags & inForHeader))
+			goto Linsert;
+		    e = new PostIncExp(loc, e);
+		    break;
+
+		case TOKminusminus:
+		    if (token.sawLineTerminator && !(flags & inForHeader))
+		    {
+		    Linsert:
+			// insert automatic semicolon
+			insertSemicolon(token.sawLineTerminator);
+			return e;
+		    }
+		    e = new PostDecExp(loc, e);
+		    break;
+
+		case TOKlparen:
+		{   // function call
+		    Expression[] arguments;
+
+		    if (innew)
+			return e;
+		    arguments = parseArguments();
+		    e = new CallExp(loc, e, arguments);
+		    continue;
+		}
+
+		case TOKlbracket:
+		{   // array dereference
+		    Expression index;
+
+		    nextToken();
+		    index = parseExpression();
+		    check(TOKrbracket);
+		    e = new ArrayExp(loc, e, index);
+		    continue;
+		}
+
+		default:
+		    return e;
+	    }
+	    nextToken();
+	}
+	assert(0);
+    }
+
+    Expression parseUnaryExp()
+    {   Expression e;
+	Loc loc;
+
+	loc = currentline;
+	switch (token.value)
+	{
+	    case TOKplusplus:
+		nextToken();
+		e = parseUnaryExp();
+		e = new PreExp(loc, IRpreinc, e);
+		break;
+
+	    case TOKminusminus:
+		nextToken();
+		e = parseUnaryExp();
+		e = new PreExp(loc, IRpredec, e);
+		break;
+
+	    case TOKminus:
+		nextToken();
+		e = parseUnaryExp();
+		e = new XUnaExp(loc, TOKneg, IRneg, e);
+		break;
+
+	    case TOKplus:
+		nextToken();
+		e = parseUnaryExp();
+		e = new XUnaExp(loc, TOKpos, IRpos, e);
+		break;
+
+	    case TOKnot:
+		nextToken();
+		e = parseUnaryExp();
+		e = new NotExp(loc, e);
+		break;
+
+	    case TOKtilde:
+		nextToken();
+		e = parseUnaryExp();
+		e = new XUnaExp(loc, TOKtilde, IRcom, e);
+		break;
+
+	    case TOKdelete:
+		nextToken();
+		e = parsePrimaryExp(0);
+		e = new DeleteExp(loc, e);
+		break;
+
+	    case TOKtypeof:
+		nextToken();
+		e = parseUnaryExp();
+		e = new XUnaExp(loc, TOKtypeof, IRtypeof, e);
+		break;
+
+	    case TOKvoid:
+		nextToken();
+		e = parseUnaryExp();
+		e = new XUnaExp(loc, TOKvoid, IRundefined, e);
+		break;
+
+	    default:
+		e = parsePrimaryExp(0);
+		break;
+	}
+	return e;
+    }
+
+    Expression parseMulExp()
+    {   Expression e;
+	Expression e2;
+	Loc loc;
+
+	loc = currentline;
+	e = parseUnaryExp();
+	for (;;)
+	{
+	    switch (token.value)
+	    {
+		case TOKmultiply:
+		    nextToken();
+		    e2 = parseUnaryExp();
+		    e = new XBinExp(loc, TOKmultiply, IRmul, e, e2);
+		    continue;
+
+		case TOKregexp:
+		    // Rescan as if it was a "/"
+		    rescan();
+		case TOKdivide:
+		    nextToken();
+		    e2 = parseUnaryExp();
+		    e = new XBinExp(loc, TOKdivide, IRdiv, e, e2);
+		    continue;
+
+		case TOKpercent:
+		    nextToken();
+		    e2 = parseUnaryExp();
+		    e = new XBinExp(loc, TOKpercent, IRmod, e, e2);
+		    continue;
+
+		default:
+		    break;
+	    }
+	    break;
+	}
+	return e;
+    }
+
+    Expression parseAddExp()
+    {   Expression e;
+	Expression e2;
+	Loc loc;
+
+	loc = currentline;
+	e = parseMulExp();
+	for (;;)
+	{
+	    switch (token.value)
+	    {
+		case TOKplus:
+		    nextToken();
+		    e2 = parseMulExp();
+		    e = new AddExp(loc, e, e2);
+		    continue;
+
+		case TOKminus:
+		    nextToken();
+		    e2 = parseMulExp();
+		    e = new XBinExp(loc, TOKminus, IRsub, e, e2);
+		    continue;
+
+		default:
+		    break;
+	    }
+	    break;
+	}
+	return e;
+    }
+
+    Expression parseShiftExp()
+    {   Expression e;
+	Expression e2;
+	Loc loc;
+
+	loc = currentline;
+	e = parseAddExp();
+	for (;;)
+	{   uint ircode;
+	    TOK op = token.value;
+
+	    switch (op)
+	    {
+		case TOKshiftleft:	ircode = IRshl;		goto L1;
+		case TOKshiftright:	ircode = IRshr;		goto L1;
+		case TOKushiftright:	ircode = IRushr;	goto L1;
+
+		L1: nextToken();
+		    e2 = parseAddExp();
+		    e = new XBinExp(loc, op, ircode, e, e2);
+		    continue;
+
+		default:
+		    break;
+	    }
+	    break;
+	}
+	return e;
+    }
+
+    Expression parseRelExp()
+    {   Expression e;
+	Expression e2;
+	Loc loc;
+
+	loc = currentline;
+	e = parseShiftExp();
+	for (;;)
+	{   uint ircode;
+	    TOK op = token.value;
+
+	    switch (op)
+	    {
+		case TOKless:		ircode = IRclt;	goto L1;
+		case TOKlessequal:	ircode = IRcle;	goto L1;
+		case TOKgreater:	ircode = IRcgt;	goto L1;
+		case TOKgreaterequal:	ircode = IRcge;	goto L1;
+
+		L1:
+		    nextToken();
+		    e2 = parseShiftExp();
+		    e = new CmpExp(loc, op, ircode, e, e2);
+		    continue;
+
+		case TOKinstanceof:
+		    nextToken();
+		    e2 = parseShiftExp();
+		    e = new XBinExp(loc, TOKinstanceof, IRinstance, e, e2);
+		    continue;
+
+		case TOKin:
+		    if (flags & noIn)
+			break;		// disallow
+		    nextToken();
+		    e2 = parseShiftExp();
+		    e = new InExp(loc, e, e2);
+		    continue;
+
+		default:
+		    break;
+	    }
+	    break;
+	}
+	return e;
+    }
+
+    Expression parseEqualExp()
+    {   Expression e;
+	Expression e2;
+	Loc loc;
+
+	loc = currentline;
+	e = parseRelExp();
+	for (;;)
+	{   uint ircode;
+	    TOK op = token.value;
+
+	    switch (op)
+	    {
+		case TOKequal:	     ircode = IRceq;	    goto L1;
+		case TOKnotequal:    ircode = IRcne;	    goto L1;
+		case TOKidentity:    ircode = IRcid;	    goto L1;
+		case TOKnonidentity: ircode = IRcnid;	    goto L1;
+
+		L1:
+		    nextToken();
+		    e2 = parseRelExp();
+		    e = new CmpExp(loc, op, ircode, e, e2);
+		    continue;
+
+		default:
+		    break;
+	    }
+	    break;
+	}
+	return e;
+    }
+
+    Expression parseAndExp()
+    {   Expression e;
+	Expression e2;
+	Loc loc;
+
+	loc = currentline;
+	e = parseEqualExp();
+	while (token.value == TOKand)
+	{
+	    nextToken();
+	    e2 = parseEqualExp();
+	    e = new XBinExp(loc, TOKand, IRand, e, e2);
+	}
+	return e;
+    }
+
+    Expression parseXorExp()
+    {   Expression e;
+	Expression e2;
+	Loc loc;
+
+	loc = currentline;
+	e = parseAndExp();
+	while (token.value == TOKxor)
+	{
+	    nextToken();
+	    e2 = parseAndExp();
+	    e = new XBinExp(loc, TOKxor, IRxor, e, e2);
+	}
+	return e;
+    }
+
+    Expression parseOrExp()
+    {   Expression e;
+	Expression e2;
+	Loc loc;
+
+	loc = currentline;
+	e = parseXorExp();
+	while (token.value == TOKor)
+	{
+	    nextToken();
+	    e2 = parseXorExp();
+	    e = new XBinExp(loc, TOKor, IRor, e, e2);
+	}
+	return e;
+    }
+
+    Expression parseAndAndExp()
+    {   Expression e;
+	Expression e2;
+	Loc loc;
+
+	loc = currentline;
+	e = parseOrExp();
+	while (token.value == TOKandand)
+	{
+	    nextToken();
+	    e2 = parseOrExp();
+	    e = new AndAndExp(loc, e, e2);
+	}
+	return e;
+    }
+
+    Expression parseOrOrExp()
+    {   Expression e;
+	Expression e2;
+	Loc loc;
+
+	loc = currentline;
+	e = parseAndAndExp();
+	while (token.value == TOKoror)
+	{
+	    nextToken();
+	    e2 = parseAndAndExp();
+	    e = new OrOrExp(loc, e, e2);
+	}
+	return e;
+    }
+
+    Expression parseCondExp()
+    {   Expression e;
+	Expression e1;
+	Expression e2;
+	Loc loc;
+
+	loc = currentline;
+	e = parseOrOrExp();
+	if (token.value == TOKquestion)
+	{
+	    nextToken();
+	    e1 = parseAssignExp();
+	    check(TOKcolon);
+	    e2 = parseAssignExp();
+	    e = new CondExp(loc, e, e1, e2);
+	}
+	return e;
+    }
+
+    Expression parseAssignExp()
+    {   Expression e;
+	Expression e2;
+	Loc loc;
+
+	loc = currentline;
+	e = parseCondExp();
+	for (;;)
+	{   uint ircode;
+	    TOK op = token.value;
+
+	    switch (op)
+	    {
+		case TOKassign:
+		    nextToken();
+		    e2 = parseAssignExp();
+		    e = new AssignExp(loc, e, e2);
+		    continue;
+
+		case TOKplusass:
+		    nextToken();
+		    e2 = parseAssignExp();
+		    e = new AddAssignExp(loc, e, e2);
+		    continue;
+
+		case TOKminusass:	ircode = IRsub;	 goto L1;
+		case TOKmultiplyass:	ircode = IRmul;	 goto L1;
+		case TOKdivideass:	ircode = IRdiv;	 goto L1;
+		case TOKpercentass:	ircode = IRmod;	 goto L1;
+		case TOKandass:		ircode = IRand;	 goto L1;
+		case TOKorass:		ircode = IRor;	 goto L1;
+		case TOKxorass:		ircode = IRxor;	 goto L1;
+		case TOKshiftleftass:	ircode = IRshl;	 goto L1;
+		case TOKshiftrightass:	ircode = IRshr;	 goto L1;
+		case TOKushiftrightass:	ircode = IRushr; goto L1;
+
+		L1: nextToken();
+		    e2 = parseAssignExp();
+		    e = new BinAssignExp(loc, op, ircode, e, e2);
+		    continue;
+
+		default:
+		    break;
+	    }
+	    break;
+	}
+	return e;
+    }
+
+    Expression parseExpression(uint flags = 0)
+    {   Expression e;
+	Expression e2;
+	Loc loc;
+	uint flags_save;
+
+	//writefln("Parser.parseExpression()");
+	flags_save = this.flags;
+	this.flags = flags;
+	loc = currentline;
+	e = parseAssignExp();
+	while (token.value == TOKcomma)
+	{
+	    nextToken();
+	    e2 = parseAssignExp();
+	    e = new CommaExp(loc, e, e2);
+	}
+	this.flags = flags_save;
+	return e;
+    }
+
+}
+
+/********************************* ***************************/
+
--- /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;
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/dmdscript_tango/property.d	Sun Jan 24 12:34:47 2010 +0200
@@ -0,0 +1,544 @@
+
+/* Digital Mars DMDScript source code.
+ * Copyright (c) 2000-2002 by Chromium Communications
+ * D version Copyright (c) 2004-2006 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.property;
+
+import dmdscript.script;
+import dmdscript.value;
+import dmdscript.identifier;
+
+import std.c.string;
+
+// attribute flags
+enum
+{
+    ReadOnly       = 0x001,
+    DontEnum       = 0x002,
+    DontDelete     = 0x004,
+    Internal       = 0x008,
+    Deleted        = 0x010,
+    Locked         = 0x020,
+    DontOverride   = 0x040,
+    KeyWord        = 0x080,
+    DebugFree      = 0x100,       // for debugging help
+    Instantiate    = 0x200,       // For COM named item namespace support
+}
+
+struct Property
+{
+    uint attributes;
+
+    Value value;
+}
+
+extern (C)
+{
+    /* These functions are part of the internal implementation of Phobos
+     * associative arrays. It's faster to use them when we have precomputed
+     * values to use.
+     */
+
+    struct Array
+    {
+	int length;
+	void* ptr;
+    }
+
+    struct aaA
+    {
+	aaA *left;
+	aaA *right;
+	hash_t hash;
+	/* key   */
+	/* value */
+    }
+
+    struct BB
+    {
+	aaA*[] b;
+	size_t nodes;	// total number of aaA nodes
+    }
+
+    struct AA
+    {
+	BB* a;
+	version (X86_64)
+	{
+	}
+	else
+	{
+	    // This is here only to retain binary compatibility with the
+	    // old way we did AA's. Should eventually be removed.
+	    int reserved;
+	}
+    }
+
+    long _aaRehash(AA* paa, TypeInfo keyti);
+
+    /************************
+     * Alternate Get() version
+     */
+
+    Property* _aaGetY(hash_t hash, Property[Value]* bb, Value* key)
+    {
+	aaA* e;
+	auto aa = cast(AA*)bb;
+
+	if (!aa.a)
+	    aa.a = new BB();
+
+	auto aalen = aa.a.b.length;
+	if (!aalen)
+	{
+	    alias aaA *pa;
+
+	    aalen = 97;
+	    aa.a.b = new pa[aalen];
+	}
+
+	//printf("hash = %d\n", hash);
+	size_t i = hash % aalen;
+	auto pe = &aa.a.b[i];
+	while ((e = *pe) != null)
+	{
+	    if (hash == e.hash)
+	    {
+		Value* v = cast(Value*)(e + 1);
+		if (key.vtype == V_NUMBER)
+		{   if (v.vtype == V_NUMBER && key.number == v.number)
+			goto Lret;
+		}
+		else if (key.vtype == V_STRING)
+		{   if (v.vtype == V_STRING && key.string is v.string)
+			goto Lret;
+		}
+		auto c = key.opCmp(v);
+		if (c == 0)
+		    goto Lret;
+		pe = (c < 0) ? &e.left : &e.right;
+	    }
+	    else
+		pe = (hash < e.hash) ? &e.left : &e.right;
+	}
+
+	// Not found, create new elem
+	//printf("\tcreate new one\n");
+	e = cast(aaA *) cast(void*) new void[aaA.sizeof + Value.sizeof + Property.sizeof];
+	std.c.string.memcpy(e + 1, key, Value.sizeof);
+	e.hash = hash;
+	*pe = e;
+
+	auto nodes = ++aa.a.nodes;
+	//printf("length = %d, nodes = %d\n", (*aa).length, nodes);
+	if (nodes > aalen * 4)
+	{
+	    _aaRehash(aa, typeid(Value));
+	}
+
+    Lret:
+	return cast(Property*)(cast(void *)(e + 1) + Value.sizeof);
+    }
+
+    /************************************
+     * Alternate In() with precomputed values.
+     */
+
+    Property* _aaInY(hash_t hash, Property[Value] bb, Value* key)
+    {
+	size_t i;
+	AA aa = *cast(AA*)&bb;
+
+	//printf("_aaIn(), aa.length = %d, .ptr = %x\n", aa.length, cast(uint)aa.ptr);
+	if (aa.a && aa.a.b.length)
+	{
+	    //printf("hash = %d\n", hash);
+	    i = hash % aa.a.b.length;
+	    auto e = aa.a.b[i];
+	    while (e != null)
+	    {
+		if (hash == e.hash)
+		{
+		    Value* v = cast(Value*)(e + 1);
+		    if (key.vtype == V_NUMBER && v.vtype == V_NUMBER &&
+			key.number == v.number)
+			goto Lfound;
+		    auto c = key.opCmp(v);
+		    if (c == 0)
+		    {
+		     Lfound:
+			return cast(Property*)(cast(void *)(e + 1) + Value.sizeof);
+		    }
+		    else
+			e = (c < 0) ? e.left : e.right;
+		}
+		else
+		    e = (hash < e.hash) ? e.left : e.right;
+	    }
+	}
+
+	// Not found
+	return null;
+    }
+}
+
+/*********************************** PropTable *********************/
+
+struct PropTable
+{
+    Property[Value] table;
+    PropTable* previous;
+
+    int opApply(int delegate(inout Property) dg)
+    {	int result;
+
+	foreach (inout Property p; table)
+	{
+	    result = dg(p);
+	    if (result)
+		break;
+	}
+	return result;
+    }
+
+    int opApply(int delegate(inout Value, inout Property) dg)
+    {	int result;
+
+	foreach (Value key, inout Property p; table)
+	{
+	    result = dg(key, p);
+	    if (result)
+		break;
+	}
+	return result;
+    }
+
+    /*******************************
+     * Look up name and get its corresponding Property.
+     * Return null if not found.
+     */
+
+    Property *getProperty(d_string name)
+    {
+	Value* v;
+	Property *p;
+
+	v = get(name, Value.calcHash(name));
+	if (!v)
+	    return null;
+
+	// Work backwards from &p->value to p
+	p = cast(Property *)(cast(char *)v - uint.sizeof /*Property.value.offsetof*/);
+
+	return p;
+    }
+
+    Value* get(Value* key, hash_t hash)
+    {
+	uint i;
+	Property *p;
+	PropTable *t;
+
+	//writefln("get(key = '%s', hash = x%x)", key.toString(), hash);
+	assert(key.toHash() == hash);
+	t = this;
+	do
+	{
+	    //writefln("\tt = %x", cast(uint)t);
+//	    p = *key in t.table;
+	    p = _aaInY(hash, t.table, key);
+
+	    if (p)
+	    {	//writefln("\tfound");
+		//p.value.dump();
+		assert(&t.table[*key] == p);
+		//p.value.dump();
+		return &p.value;
+	    }
+	    t = t.previous;
+	} while (t);
+	//writefln("\tnot found");
+	return null;			// not found
+    }
+
+    Value* get(d_uint32 index)
+    {
+	//writefln("get(index = %d)", index);
+	Value key;
+
+	key.putVnumber(index);
+	return get(&key, Value.calcHash(index));
+    }
+
+    Value* get(Identifier* id)
+    {
+	//writefln("get('%s', hash = x%x)", name, hash);
+	return get(&id.value, id.value.hash);
+	//return get(id.value.string, id.value.hash);
+    }
+
+    Value* get(d_string name, hash_t hash)
+    {
+	//writefln("get('%s', hash = x%x)", name, hash);
+	Value key;
+
+	key.putVstring(name);
+	return get(&key, hash);
+    }
+
+    /*******************************
+     * Determine if property exists for this object.
+     * The enumerable flag means the DontEnum attribute cannot be set.
+     */
+
+    int hasownproperty(Value* key, int enumerable)
+    {
+	Property* p;
+
+	p = *key in table;
+	return p && (!enumerable || !(p.attributes & DontEnum));
+    }
+
+    int hasproperty(Value* key)
+    {
+	return (*key in table) != null;
+    }
+
+    int hasproperty(d_string name)
+    {
+	Value v;
+
+	v.putVstring(name);
+	return hasproperty(&v);
+    }
+
+    Value* put(Value* key, hash_t hash, Value* value, uint attributes)
+    {
+	Property* p;
+
+	//writefln("put(key = %s, hash = x%x, value = %s, attributes = x%x)", key.toString(), hash, value.toString(), attributes);
+	//writefln("put(key = %s)", key.toString());
+//	p = &table[*key];
+	p = _aaGetY(hash, &table, key);
+/+
+    {
+	size_t i;
+	aaA *e;
+	aaA **pe;
+	aaA*[]* aa = cast(aaA*[]*)&table;
+	size_t aalen;
+
+	aalen = (*aa).length;
+	if (!aalen)
+	{
+	    alias aaA *pa;
+
+	    aalen = 97 + 1;
+	    *aa = new pa[aalen];
+	    (*aa)[0] = cast(aaA *) cast(void*) new void[aaA.sizeof];
+	}
+
+	//printf("hash = %d\n", hash);
+	i = (hash % (aalen - 1)) + 1;
+	pe = &(*aa)[i];
+	while ((e = *pe) != null)
+	{
+	    if (hash == e.hash)
+	    {
+		Value* v = cast(Value*)(e + 1);
+		if (key.vtype == V_NUMBER)
+		{   if (v.vtype == V_NUMBER && key.number == v.number)
+			goto Lfound;
+		}
+		else if (key.vtype == V_STRING)
+		{   if (v.vtype == V_STRING && key.string is v.string)
+			goto Lfound;
+		}
+		auto c = key.opCmp(v);
+		if (c == 0)
+		{
+		Lfound:
+		    p = cast(Property*)(v + 1);
+		    goto Lx;
+		}
+		pe = (c < 0) ? &e.left : &e.right;
+	    }
+	    else
+		pe = (hash < e.hash) ? &e.left : &e.right;
+	}
+
+	// Not found, create new elem
+	//printf("\tcreate new one\n");
+	e = cast(aaA *) cast(void*) new void[aaA.sizeof + Value.sizeof + Property.sizeof];
+	memcpy(e + 1, key, Value.sizeof);
+	e.hash = hash;
+	*pe = e;
+
+	uint nodes = ++(*aa)[0].nodes;
+	//printf("length = %d, nodes = %d\n", (*aa).length, nodes);
+	if (nodes > aalen * 4)
+	{
+	    _aaRehash(aa, typeid(Value));
+	}
+
+	p = cast(Property*)(cast(void *)(e + 1) + Value.sizeof);
+    }
++/
+	if (p.value.vtype != V_NONE)
+	{
+    Lx:
+	    if (attributes & DontOverride ||
+		p.attributes & ReadOnly)
+	    {
+		if (p.attributes & KeyWord)
+		    return null;
+		return &vundefined;
+	    }
+
+	    PropTable* t = previous;
+	    if (t)
+	    {
+		do
+		{   Property* q;
+	//	    q = *key in t.table;
+		    q = _aaInY(hash, t.table, key);
+		    if (q)
+		    {
+			if (q.attributes & ReadOnly)
+			{   p.attributes |= ReadOnly;
+			    return &vundefined;
+			}
+			break;
+		    }
+		    t = t.previous;
+		} while (t);
+	    }
+
+	    // Overwrite property with new value
+	    Value.copy(&p.value, value);
+	    p.attributes = (attributes & ~DontOverride) | (p.attributes & (DontDelete | DontEnum));
+	    return null;
+	}
+
+	// Not in table; create new entry
+
+	p.attributes = attributes & ~DontOverride;
+	Value.copy(&p.value, value);
+	assert(p.value == value);
+
+	return null;			// success
+    }
+
+    Value* put(d_string name, Value* value, uint attributes)
+    {
+	Value key;
+
+	key.putVstring(name);
+
+	//writef("PropTable::put(%p, '%ls', hash = x%x)\n", this, d_string_ptr(name), key.toHash());
+	return put(&key, Value.calcHash(name), value, attributes);
+    }
+
+    Value* put(d_uint32 index, Value* value, uint attributes)
+    {
+	Value key;
+
+	key.putVnumber(index);
+
+	//writef("PropTable::put(%d)\n", index);
+	return put(&key, Value.calcHash(index), value, attributes);
+    }
+
+    Value* put(d_uint32 index, d_string string, uint attributes)
+    {
+	Value key;
+	Value value;
+
+	key.putVnumber(index);
+	value.putVstring(string);
+
+	return put(&key, Value.calcHash(index), &value, attributes);
+    }
+
+    int canput(Value* key, hash_t hash)
+    {
+	Property *p;
+	PropTable *t;
+
+	t = this;
+	do
+	{
+//	    p = *key in t.table;
+	    p = _aaInY(hash, t.table, key);
+	    if (p)
+	    {	return (p.attributes & ReadOnly)
+			? false : true;
+	    }
+	    t = t.previous;
+	} while (t);
+	return true;			// success
+    }
+
+    int canput(d_string name)
+    {
+	Value v;
+
+	v.putVstring(name);
+
+	return canput(&v, v.toHash());
+    }
+
+    int del(Value* key)
+    {
+	Property *p;
+
+	//writef("PropTable::del('%ls')\n", d_string_ptr(key.toString()));
+	p = *key in table;
+	if (p)
+	{
+	    if (p.attributes & DontDelete)
+		return false;
+	    table.remove(*key);
+	}
+	return true;			// not found
+    }
+
+    int del(d_string name)
+    {
+	Value v;
+
+	v.putVstring(name);
+
+	//writef("PropTable::del('%ls')\n", d_string_ptr(name));
+	return del(&v);
+    }
+
+    int del(d_uint32 index)
+    {
+	Value v;
+
+	v.putVnumber(index);
+
+	//writef("PropTable::del(%d)\n", index);
+	return del(&v);
+    }
+}
+
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/dmdscript_tango/protoerror.d	Sun Jan 24 12:34:47 2010 +0200
@@ -0,0 +1,184 @@
+
+/* Digital Mars DMDScript source code.
+ * Copyright (c) 2000-2002 by Chromium Communications
+ * D version Copyright (c) 2004-2006 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.protoerror;
+
+import dmdscript.script;
+import dmdscript.dobject;
+import dmdscript.value;
+import dmdscript.threadcontext;
+import dmdscript.text;
+import dmdscript.dfunction;
+import dmdscript.property;
+
+int foo;	// cause this module to be linked in
+
+/* ===================== D0_constructor ==================== */
+
+class D0_constructor : Dfunction
+{
+    d_string text_d1;
+    Dobject function(d_string) newD0;
+
+    this(ThreadContext *tc, d_string text_d1, Dobject function(d_string) newD0)
+    {
+	super(1, tc.Dfunction_prototype);
+	this.text_d1 = text_d1;
+	this.newD0 = newD0;
+    }
+
+    void *Construct(CallContext *cc, Value *ret, Value[] arglist)
+    {
+	// ECMA 15.11.7.2
+	Value* m;
+	Dobject o;
+	tchar[] s;
+
+	m = (arglist.length) ? &arglist[0] : &vundefined;
+	// ECMA doesn't say what we do if m is undefined
+	if (m.isUndefined())
+	    s = text_d1;
+	else
+	    s = m.toString();
+	o = (*newD0)(s);
+	ret.putVobject(o);
+	return null;
+    }
+
+    void *Call(CallContext *cc, Dobject othis, Value* ret, Value[] arglist)
+    {
+	// ECMA v3 15.11.7.1
+	return Construct(cc, ret, arglist);
+    }
+}
+
+
+template proto(alias TEXT_D1)
+{
+
+    /* ===================== D0_prototype ==================== */
+
+    class D0_prototype : D0
+    {
+	this(ThreadContext *tc)
+	{
+	    super(tc.Derror_prototype);
+
+	    tchar[] s;
+
+	    Put(TEXT_constructor, tc.ctorTable[TEXT_D1], DontEnum);
+	    Put(TEXT_name, TEXT_D1, 0);
+	    s = TEXT_D1 ~ ".prototype.message";
+	    Put(TEXT_message, s, 0);
+	    Put(TEXT_description, s, 0);
+	    Put(TEXT_number, cast(d_number)0, 0);
+	}
+    }
+
+    /* ===================== D0 ==================== */
+
+    class D0 : Dobject
+    {
+	ErrInfo errinfo;
+
+	this(Dobject prototype)
+	{
+	    super(prototype);
+	    classname = TEXT_Error;
+	}
+
+	this(tchar[] m)
+	{
+	    this(D0.getPrototype());
+	    Put(TEXT_message, m, 0);
+	    Put(TEXT_description, m, 0);
+	    Put(TEXT_number, cast(d_number)0, 0);
+	    errinfo.message = m;
+	}
+
+	this(ErrInfo *perrinfo)
+	{
+	    this(perrinfo.message);
+	    errinfo = *perrinfo;
+	    Put(TEXT_number, cast(d_number)perrinfo.code, 0);
+	}
+
+	void getErrInfo(ErrInfo *perrinfo, int linnum)
+	{
+	    if (linnum && errinfo.linnum == 0)
+		errinfo.linnum = linnum;
+	    if (perrinfo)
+		*perrinfo = errinfo;
+	    //writefln("getErrInfo(linnum = %d), errinfo.linnum = %d", linnum, errinfo.linnum);
+	}
+
+	static Dfunction getConstructor()
+	{
+	    ThreadContext *tc = ThreadContext.getThreadContext();
+	    assert(tc);
+	    return tc.ctorTable[TEXT_D1];
+	}
+
+	static Dobject getPrototype()
+	{
+	    ThreadContext *tc = ThreadContext.getThreadContext();
+	    assert(tc);
+	    return tc.protoTable[TEXT_D1];
+	}
+
+	static Dobject newD0(d_string s)
+	{
+	    return new D0(s);
+	}
+
+	static void init(ThreadContext *tc)
+	{
+	    Dfunction constructor = new D0_constructor(tc, TEXT_D1, &newD0);
+	    tc.ctorTable[TEXT_D1] = constructor;
+
+	    Dobject prototype = new D0_prototype(tc);
+	    tc.protoTable[TEXT_D1] = prototype;
+
+	    constructor.Put(TEXT_prototype, prototype, DontEnum | DontDelete | ReadOnly);
+	}
+    }
+}
+
+alias proto!(TEXT_SyntaxError) syntaxerror;
+alias proto!(TEXT_EvalError) evalerror;
+alias proto!(TEXT_ReferenceError) referenceerror;
+alias proto!(TEXT_RangeError) rangeerror;
+alias proto!(TEXT_TypeError) typeerror;
+alias proto!(TEXT_URIError) urierror;
+
+/**********************************
+ * Register initializer for each class.
+ */
+
+static this()
+{
+    ThreadContext.initTable ~= &syntaxerror.D0.init;
+    ThreadContext.initTable ~= &evalerror.D0.init;
+    ThreadContext.initTable ~= &referenceerror.D0.init;
+    ThreadContext.initTable ~= &rangeerror.D0.init;
+    ThreadContext.initTable ~= &typeerror.D0.init;
+    ThreadContext.initTable ~= &urierror.D0.init;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/dmdscript_tango/scopex.d	Sun Jan 24 12:34:47 2010 +0200
@@ -0,0 +1,193 @@
+
+/* 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.scopex;
+
+import dmdscript.script;
+import dmdscript.program;
+import dmdscript.symbol;
+import dmdscript.functiondefinition;
+import dmdscript.identifier;
+import dmdscript.statement;
+
+struct Scope
+{
+    Scope* enclosing;		// enclosing Scope
+
+    char[] src;			// source text
+    Program program;		// Root module
+    ScopeSymbol *scopesym;	// current symbol
+    FunctionDefinition funcdef; // what function we're in
+    SymbolTable **plabtab;	// pointer to label symbol table
+    uint nestDepth;		// static nesting level
+
+    ScopeStatement scopeContext;	// nesting of scope statements
+    Statement continueTarget;
+    Statement breakTarget;
+    SwitchStatement switchTarget;
+
+    ErrInfo errinfo;		// semantic() puts error messages here
+
+    void zero()
+    {
+	enclosing = null;
+
+	src = null;
+	program = null;
+	scopesym = null;
+	funcdef = null;
+	plabtab = null;
+	nestDepth = 0;
+
+	scopeContext = null;
+	continueTarget = null;
+	breakTarget = null;
+	switchTarget = null;
+    }
+
+    void ctor(Scope* enclosing)
+    {
+	zero();
+	this.program = enclosing.program;
+	this.funcdef = enclosing.funcdef;
+	this.plabtab = enclosing.plabtab;
+	this.nestDepth = enclosing.nestDepth;
+	this.enclosing = enclosing;
+    }
+
+    void ctor(Program program, FunctionDefinition fd)
+    {   // Create root scope
+
+	zero();
+	this.program = program;
+	this.funcdef = fd;
+	this.plabtab = &fd.labtab;
+    }
+
+    void ctor(FunctionDefinition fd)
+    {   // Create scope for anonymous function fd
+
+	zero();
+	this.funcdef = fd;
+	this.plabtab = &fd.labtab;
+    }
+
+    void dtor()
+    {
+	// Help garbage collector
+	zero();
+    }
+
+    Scope* push()
+    {   Scope* s;
+
+	s = new Scope;
+	s.ctor(this);
+	return s;
+    }
+
+    Scope* push(FunctionDefinition fd)
+    {   Scope* s;
+
+	s = push();
+	s.funcdef = fd;
+	s.plabtab = &fd.labtab;
+	return s;
+    }
+
+    void pop()
+    {
+	if (enclosing && !enclosing.errinfo.message)
+	    enclosing.errinfo = errinfo;
+	zero();			// aid GC
+    }
+
+
+    Symbol search(Identifier *ident)
+    {   Symbol s;
+	Scope* sc;
+
+	//writef("Scope.search(%p, '%s')\n", this, ident.toString());
+	for (sc = this; sc; sc = sc.enclosing)
+	{
+	    s = sc.scopesym.search(ident);
+	    if (s)
+		return s;
+	}
+
+	assert(0);
+	//error("Symbol '%s' is not defined", ident.toString());
+	return null;
+    }
+
+    Symbol insert(Symbol s)
+    {
+	if (!scopesym.symtab)
+	    scopesym.symtab = new SymbolTable();
+	return scopesym.symtab.insert(s);
+    }
+
+    LabelSymbol searchLabel(Identifier *ident)
+    {
+	SymbolTable *st;
+	LabelSymbol ls;
+
+	//writef("Scope::searchLabel('%ls')\n", ident.toDchars());
+	assert(plabtab);
+	st = *plabtab;
+	if (!st)
+	{
+	    st = new SymbolTable();
+	    *plabtab = st;
+	}
+	ls = cast(LabelSymbol )st.lookup(ident);
+	return ls;
+    }
+
+    LabelSymbol insertLabel(LabelSymbol ls)
+    {
+	SymbolTable *st;
+
+	//writef("Scope::insertLabel('%s')\n", ls.toString());
+	assert(plabtab);
+	st = *plabtab;
+	if (!st)
+	{
+	    st = new SymbolTable();
+	    *plabtab = st;
+	}
+	ls = cast(LabelSymbol )st.insert(ls);
+	return ls;
+    }
+
+    tchar[] getSource()
+    {   Scope* sc;
+
+	for (sc = this; sc; sc = sc.enclosing)
+	{
+	    if (sc.src)
+		return sc.src;
+	}
+
+	return null;
+    }
+}
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/dmdscript_tango/script.d	Sun Jan 24 12:34:47 2010 +0200
@@ -0,0 +1,319 @@
+
+/* Digital Mars DMDScript source code.
+ * Copyright (c) 2000-2002 by Chromium Communications
+ * D version Copyright (c) 2004-2006 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.script;
+
+import std.ctype;
+import std.string;
+import std.c.stdlib;
+import std.c.stdarg;
+
+/* =================== Configuration ======================= */
+
+const uint MAJOR_VERSION = 5;	// ScriptEngineMajorVersion
+const uint MINOR_VERSION = 5;	// ScriptEngineMinorVersion
+
+const uint BUILD_VERSION = 1;	// ScriptEngineBuildVersion
+
+const uint JSCRIPT_CATCH_BUG = 1;	// emulate Jscript's bug in scoping of
+					// catch objects in violation of ECMA
+const uint JSCRIPT_ESCAPEV_BUG = 0;	// emulate Jscript's bug where \v is
+					// not recognized as vertical tab
+
+//=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
+
+alias char tchar;
+
+alias ulong number_t;
+alias double real_t;
+
+alias uint Loc;			// file location (line number)
+
+struct ErrInfo
+{
+    tchar[] message;		// error message (null if no error)
+    tchar[] srcline;		// string of source line (null if not known)
+    uint linnum;		// source line number (1 based, 0 if not available)
+    int charpos;		// character position (1 based, 0 if not available)
+    int code;			// error code (0 if not known)
+}
+
+class ScriptException : Exception
+{
+    ErrInfo ei;
+
+    this(tchar[] msg)
+    {	ei.message = msg;
+	super(msg);
+    }
+
+    this(ErrInfo* pei)
+    {
+	ei = *pei;
+	super(ei.message);
+    }
+}
+
+int logflag;	// used for debugging
+
+
+// Aliases for script primitive types
+alias uint	d_boolean;
+alias double	d_number;
+alias int	d_int32;
+alias uint	d_uint32;
+alias ushort	d_uint16;
+alias tchar[]	d_string;
+
+import dmdscript.value;
+import dmdscript.dobject;
+import dmdscript.program;
+import dmdscript.text;
+import dmdscript.functiondefinition;
+
+struct CallContext
+{
+    Dobject[] scopex;	// current scope chain
+    Dobject variable;	// object for variable instantiation
+    Dobject global;	// global object
+    uint scoperoot;	// number of entries in scope[] starting from 0
+			// to copy onto new scopes
+    uint globalroot;	// number of entries in scope[] starting from 0
+			// that are in the "global" context. Always <= scoperoot
+    void* lastnamedfunc;  // points to the last named function added as an event
+    Program prog;
+    Dobject callerothis;	// caller's othis
+    Dobject caller;		// caller function object
+    FunctionDefinition callerf;
+
+    char[16] value;	// place to store exception; must be same size as Value
+    uint linnum;	// source line number of exception (1 based, 0 if not available)
+
+    int finallyret;	// !=0 if IRfinallyret was executed
+    int Interrupt;	// !=0 if cancelled due to interrupt
+}
+
+struct Global
+{
+    tchar[] copyright = "Copyright (c) 1999-2009 by Digital Mars";
+    tchar[] written = "written by Walter Bright";
+}
+
+Global global;
+
+tchar[] banner()
+{
+    return std.string.format(
+	"Digital Mars DMDScript 1.15\n",
+	"http://www.digitalmars.com\n",
+	"Compiled by Digital Mars DMD D compiler\n",
+	global.copyright, "\n",
+	global.written);
+}
+
+int isStrWhiteSpaceChar(dchar c)
+{
+    switch (c)
+    {
+	case ' ':
+	case '\t':
+	case 0xA0:	// <NBSP>
+	case '\f':
+	case '\v':
+	case '\r':
+	case '\n':
+	case 0x2028:	// <LS>
+	case 0x2029:	// <PS>
+	case 0x2001:	// <USP>
+	case 0x2000:	// should we do this one?
+	    return 1;
+
+	default:
+	    break;
+    }
+    return 0;
+}
+
+
+/************************
+ * Convert d_string to an index, if it is one.
+ * Returns:
+ *	true	it's an index, and *index is set
+ *	false	it's not an index
+ */
+
+int StringToIndex(d_string name, out d_uint32 index)
+{
+    if (name.length)
+    {
+	d_uint32 i = 0;
+
+	for (uint j = 0; j < name.length; j++)
+	{   tchar c = name[j];
+
+	    switch (c)
+	    {
+		case '0':
+		case '1':
+		case '2':
+		case '3':
+		case '4':
+		case '5':
+		case '6':
+		case '7':
+		case '8':
+		case '9':
+		    if ((i == 0 && j) ||		// if leading zeros
+			i >= 0xFFFFFFFF / 10)	// or overflow
+			goto Lnotindex;
+		    i = i * 10 + c - '0';
+		    break;
+
+		default:
+		    goto Lnotindex;
+	    }
+	}
+	index = i;
+	return true;
+    }
+
+  Lnotindex:
+    return false;
+}
+
+
+/********************************
+ * Parse string numeric literal into a number.
+ * Input:
+ *	parsefloat	0: convert per ECMA 9.3.1
+ *			1: convert per ECMA 15.1.2.3 (global.parseFloat())
+ */
+
+d_number StringNumericLiteral(d_string string, out size_t endidx, int parsefloat)
+{
+    // Convert StringNumericLiteral using ECMA 9.3.1
+    d_number number;
+    int sign = 0;
+    size_t i;
+    size_t len;
+    size_t eoff;
+
+    // Skip leading whitespace
+    eoff = string.length;
+    foreach (size_t j, dchar c; string)
+    {
+	if (!isStrWhiteSpaceChar(c))
+	{
+	    eoff = j;
+	    break;
+	}
+    }
+    string = string[eoff .. length];
+    len = string.length;
+
+    // Check for [+|-]
+    i = 0;
+    if (len)
+    {
+	switch (string[0])
+	{   case '+':
+		sign = 0;
+		i++;
+		break;
+
+	    case '-':
+		sign = 1;
+		i++;
+		break;
+
+	    default:
+		sign = 0;
+		break;
+	}
+    }
+
+    size_t inflen = TEXT_Infinity.length;
+    if (len - i >= inflen &&
+	string[i .. i + inflen] == TEXT_Infinity)
+    {
+	number = sign ? -d_number.infinity : d_number.infinity;
+	endidx = eoff + i + inflen;
+    }
+    else if (len - i >= 2 &&
+	     string[i] == '0' && (string[i + 1] == 'x' || string[i + 1] == 'X'))
+    {
+	// Check for 0[x|X]HexDigit...
+	number = 0;
+	if (parsefloat)
+	{   // Do not recognize the 0x, treat it as if it's just a '0'
+	    i += 1;
+	}
+	else
+	{
+	    i += 2;
+	    for (; i < len; i++)
+	    {   tchar c;
+
+		c = string[i];		// don't need to decode UTF here
+		if ('0' <= c && c <= '9')
+		    number = number * 16 + (c - '0');
+		else if ('a' <= c && c <= 'f')
+		    number = number * 16 + (c - 'a' + 10);
+		else if ('A' <= c && c <= 'F')
+		    number = number * 16 + (c - 'A' + 10);
+		else
+		    break;
+	    }
+	}
+	if (sign)
+	    number = -number;
+	endidx = eoff + i;
+    }
+    else
+    {	char* endptr;
+	char* s = std.string.toStringz(string[i .. len]);
+
+	endptr = s;
+	number = std.c.stdlib.strtod(s, &endptr);
+	endidx = (endptr - s) + i;
+
+	//printf("s = '%s', endidx = %d, eoff = %d, number = %g\n", s, endidx, eoff, number);
+
+	// Correctly produce a -0 for the
+	// string "-1e-2000"
+	if (sign)
+	    number = -number;
+	if (endidx == i && (parsefloat || i != 0))
+	    number = d_number.nan;
+	endidx += eoff;
+    }
+
+    return number;
+}
+
+
+
+
+int localeCompare(CallContext *cc, d_string s1, d_string s2)
+{   // no locale support here
+    return std.string.cmp(s1, s2);
+}
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/dmdscript_tango/statement.d	Sun Jan 24 12:34:47 2010 +0200
@@ -0,0 +1,1833 @@
+
+/* 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.statement;
+
+import std.stdio;
+import std.string;
+import std.math;
+
+import dmdscript.script;
+import dmdscript.value;
+import dmdscript.scopex;
+import dmdscript.expression;
+import dmdscript.irstate;
+import dmdscript.symbol;
+import dmdscript.identifier;
+import dmdscript.ir;
+import dmdscript.lexer;
+import dmdscript.errmsgs;
+import dmdscript.functiondefinition;
+import dmdscript.opcodes;
+
+enum
+{
+    TOPSTATEMENT,
+    FUNCTIONDEFINITION,
+    EXPSTATEMENT,
+    VARSTATEMENT,
+}
+
+
+/******************************** TopStatement ***************************/
+
+class TopStatement
+{
+    const uint TOPSTATEMENT_SIGNATURE = 0xBA3FE1F3;
+    uint signature = TOPSTATEMENT_SIGNATURE;
+
+    Loc loc;
+    int done;		// 0: parsed
+			// 1: semantic
+			// 2: toIR
+    int st;
+
+    this(Loc loc)
+    {
+	this.loc = loc;
+	this.done = 0;
+	this.st = TOPSTATEMENT;
+    }
+
+    invariant
+    {
+	assert(signature == TOPSTATEMENT_SIGNATURE);
+    }
+
+    void toBuffer(inout tchar[] buf)
+    {
+	buf ~= "TopStatement.toBuffer()\n";
+    }
+
+    Statement semantic(Scope *sc)
+    {
+	writefln("TopStatement.semantic(%p)", this);
+	return null;
+    }
+
+    void toIR(IRstate *irs)
+    {
+	writefln("TopStatement.toIR(%p)", this);
+    }
+
+    void error(Scope *sc, int msgnum)
+    {
+	error(sc, errmsgtbl[msgnum]);
+    }
+
+    void error(Scope *sc, ...)
+    {
+	tchar[] buf;
+	tchar[] sourcename;
+
+	if (sc.funcdef)
+	{   if (sc.funcdef.isanonymous)
+		sourcename = "anonymous";
+	    else if (sc.funcdef.name)
+		sourcename ~= sc.funcdef.name.toString();
+	}
+	buf = std.string.format("%s(%d) : Error: ", sourcename, loc);
+
+	void putc(dchar c)
+	{
+	    std.utf.encode(buf, c);
+	}
+
+	std.format.doFormat(&putc, _arguments, _argptr);
+
+
+	if (!sc.errinfo.message)
+	{
+	    sc.errinfo.message = buf;
+	    sc.errinfo.linnum = loc;
+	    sc.errinfo.srcline = Lexer.locToSrcline(sc.getSource().ptr, loc);
+	}
+    }
+
+    TopStatement ImpliedReturn()
+    {
+	return this;
+    }
+}
+
+/******************************** Statement ***************************/
+
+class Statement : TopStatement
+{
+    LabelSymbol *label;
+
+    this(Loc loc)
+    {
+	super(loc);
+	this.loc = loc;
+    }
+
+    void toBuffer(inout tchar[] buf)
+    {
+	buf ~= "Statement.toBuffer()\n";
+    }
+
+    Statement semantic(Scope *sc)
+    {
+	writef("Statement.semantic(%p)\n", this);
+	return this;
+    }
+
+    void toIR(IRstate *irs)
+    {
+	writef("Statement.toIR(%p)\n", this);
+    }
+
+    uint getBreak()
+    {
+	assert(0);
+	return 0;
+    }
+
+    uint getContinue()
+    {
+	assert(0);
+	return 0;
+    }
+
+    uint getGoto()
+    {
+	assert(0);
+	return 0;
+    }
+
+    uint getTarget()
+    {
+	assert(0);
+	return 0;
+    }
+
+    ScopeStatement getScope()
+    {
+	return null;
+    }
+}
+
+/******************************** EmptyStatement ***************************/
+
+class EmptyStatement : Statement
+{
+    this(Loc loc)
+    {
+	super(loc);
+	this.loc = loc;
+    }
+
+    void toBuffer(inout tchar[] buf)
+    {
+	buf ~= ";\n";
+    }
+
+    Statement semantic(Scope *sc)
+    {
+	//writef("EmptyStatement.semantic(%p)\n", this);
+	return this;
+    }
+
+    void toIR(IRstate *irs)
+    {
+    }
+}
+
+/******************************** ExpStatement ***************************/
+
+class ExpStatement : Statement
+{
+    Expression exp;
+
+    this(Loc loc, Expression exp)
+    {
+	//writef("ExpStatement.ExpStatement(this = %x, exp = %x)\n", this, exp);
+	super(loc);
+	st = EXPSTATEMENT;
+	this.exp = exp;
+    }
+
+    void toBuffer(inout tchar[] buf)
+    {
+	if (exp)
+	    exp.toBuffer(buf);
+	buf ~= ";\n";
+    }
+
+    Statement semantic(Scope *sc)
+    {
+	//writef("exp = '%s'\n", exp.toString());
+	//writef("ExpStatement.semantic(this = %x, exp = %x, exp.vptr = %x, %x, %x)\n", this, exp, ((uint *)exp)[0], /*(*(uint **)exp)[12],*/ *(uint *)(*(uint **)exp)[12]);
+	if (exp)
+	    exp = exp.semantic(sc);
+	//writef("-semantic()\n");
+	return this;
+    }
+
+    TopStatement ImpliedReturn()
+    {
+	return new ImpliedReturnStatement(loc, exp);
+    }
+
+    void toIR(IRstate *irs)
+    {
+	//writef("ExpStatement.toIR(%p)\n", exp);
+	if (exp)
+	{   uint marksave = irs.mark();
+
+	    assert(exp);
+	    exp.toIR(irs, 0);
+	    irs.release(marksave);
+
+	    exp = null;		// release to garbage collector
+	}
+    }
+}
+
+/****************************** VarDeclaration ******************************/
+
+class VarDeclaration
+{
+    Loc loc;
+    Identifier *name;
+    Expression init;
+
+    this(Loc loc, Identifier *name, Expression init)
+    {
+	this.loc = loc;
+	this.init = init;
+	this.name = name;
+    }
+}
+
+/******************************** VarStatement ***************************/
+
+class VarStatement : Statement
+{
+    VarDeclaration[] vardecls;
+
+    this(Loc loc)
+    {
+	super(loc);
+	st = VARSTATEMENT;
+    }
+
+    Statement semantic(Scope *sc)
+    {   FunctionDefinition fd;
+	uint i;
+
+	// Collect all the Var statements in order in the function
+	// declaration, this is so it is easy to instantiate them
+	fd = sc.funcdef;
+	//fd.varnames.reserve(vardecls.length);
+
+	for (i = 0; i < vardecls.length; i++)
+	{
+	    VarDeclaration vd;
+
+	    vd = vardecls[i];
+	    if (vd.init)
+		vd.init = vd.init.semantic(sc);
+	    fd.varnames ~= vd.name;
+	}
+
+	return this;
+    }
+
+    void toBuffer(inout tchar[] buf)
+    {
+	uint i;
+
+	if (vardecls.length)
+	{
+	    buf ~= "var ";
+
+	    for (i = 0; i < vardecls.length; i++)
+	    {
+		VarDeclaration vd;
+
+		vd = vardecls[i];
+		buf ~= vd.name.toString();
+		if (vd.init)
+		{   buf ~= " = ";
+		    vd.init.toBuffer(buf);
+		}
+	    }
+	    buf ~= ";\n";
+	}
+    }
+
+    void toIR(IRstate *irs)
+    {
+	uint i;
+	uint ret;
+
+	if (vardecls.length)
+	{   uint marksave;
+
+	    marksave = irs.mark();
+	    ret = irs.alloc(1);
+
+	    for (i = 0; i < vardecls.length; i++)
+	    {
+		VarDeclaration vd;
+
+		vd = vardecls[i];
+
+		// This works like assignment statements:
+		//	name = init;
+		IR property;
+
+		if (vd.init)
+		{
+		    vd.init.toIR(irs, ret);
+		    property.id = Identifier.build(vd.name.toString());
+		    irs.gen2(loc, IRputthis, ret, property.index);
+		}
+	    }
+	    irs.release(marksave);
+	    vardecls[] = null;		// help gc
+	}
+    }
+}
+
+/******************************** BlockStatement ***************************/
+
+class BlockStatement : Statement
+{
+    Statement[] statements;
+
+    this(Loc loc)
+    {
+	super(loc);
+    }
+
+    Statement semantic(Scope *sc)
+    {   uint i;
+
+	//writefln("BlockStatement.semantic()");
+	for (i = 0; i < statements.length; i++)
+	{   Statement s;
+
+	    s = statements[i];
+	    assert(s);
+	    statements[i] = s.semantic(sc);
+	}
+
+	return this;
+    }
+
+    TopStatement ImpliedReturn()
+    {
+	uint i = statements.length;
+
+	if (i)
+	{
+	    TopStatement ts = statements[i - 1];
+	    ts = ts.ImpliedReturn();
+	    statements[i - 1] = cast(Statement)ts;
+	}
+	return this;
+    }
+
+
+    void toBuffer(inout tchar[] buf)
+    {
+	buf ~= "{\n";
+
+	foreach (Statement s; statements)
+	{
+	    s.toBuffer(buf);
+	}
+
+	buf ~= "}\n";
+    }
+
+    void toIR(IRstate *irs)
+    {
+	foreach (Statement s; statements)
+	{
+	    s.toIR(irs);
+	}
+
+	// Release to garbage collector
+	statements[] = null;
+	statements = null;
+    }
+}
+
+/******************************** LabelStatement ***************************/
+
+class LabelStatement : Statement
+{
+    Identifier* ident;
+    Statement statement;
+    uint gotoIP;
+    uint breakIP;
+    ScopeStatement scopeContext;
+
+    this(Loc loc, Identifier *ident, Statement statement)
+    {
+	//writef("LabelStatement.LabelStatement(%p, '%s', %p)\n", this, ident.toChars(), statement);
+	super(loc);
+	this.ident = ident;
+	this.statement = statement;
+	gotoIP = ~0u;
+	breakIP = ~0u;
+	scopeContext = null;
+    }
+
+    Statement semantic(Scope *sc)
+    {
+	LabelSymbol ls;
+
+	//writef("LabelStatement.semantic('%ls')\n", ident.toString());
+	scopeContext = sc.scopeContext;
+	ls = sc.searchLabel(ident);
+	if (ls)
+	{
+	    // Ignore multiple definition errors
+	    //if (ls.statement)
+		//error(sc, "label '%s' is already defined", ident.toString());
+	    ls.statement = this;
+	}
+	else
+	{
+	    ls = new LabelSymbol(loc, ident, this);
+	    sc.insertLabel(ls);
+	}
+	if (statement)
+	    statement = statement.semantic(sc);
+	return this;
+    }
+
+    TopStatement ImpliedReturn()
+    {
+	if (statement)
+	    statement = cast(Statement)statement.ImpliedReturn();
+	return this;
+    }
+
+    void toBuffer(inout tchar[] buf)
+    {
+	buf ~= ident.toString();
+	buf ~= ": ";
+	if (statement)
+	    statement.toBuffer(buf);
+	else
+	    buf ~= '\n';
+    }
+
+    void toIR(IRstate *irs)
+    {
+	gotoIP = irs.getIP();
+	statement.toIR(irs);
+	breakIP = irs.getIP();
+    }
+
+    uint getGoto()
+    {
+	return gotoIP;
+    }
+
+    uint getBreak()
+    {
+	return breakIP;
+    }
+
+    uint getContinue()
+    {
+	return statement.getContinue();
+    }
+
+    ScopeStatement getScope()
+    {
+	return scopeContext;
+    }
+}
+
+/******************************** IfStatement ***************************/
+
+class IfStatement : Statement
+{
+    Expression condition;
+    Statement ifbody;
+    Statement elsebody;
+
+    this(Loc loc, Expression condition, Statement ifbody, Statement elsebody)
+    {
+	super(loc);
+	this.condition = condition;
+	this.ifbody = ifbody;
+	this.elsebody = elsebody;
+    }
+
+    Statement semantic(Scope *sc)
+    {
+	//writef("IfStatement.semantic(%p)\n", sc);
+	assert(condition);
+	condition = condition.semantic(sc);
+	ifbody = ifbody.semantic(sc);
+	if (elsebody)
+	    elsebody = elsebody.semantic(sc);
+
+	return this;
+    }
+
+    TopStatement ImpliedReturn()
+    {
+	assert(condition);
+	ifbody = cast(Statement)ifbody.ImpliedReturn();
+	if (elsebody)
+	    elsebody = cast(Statement)elsebody.ImpliedReturn();
+	return this;
+    }
+
+
+
+    void toIR(IRstate *irs)
+    {
+	uint c;
+	uint u1;
+	uint u2;
+
+	assert(condition);
+	c = irs.alloc(1);
+	condition.toIR(irs, c);
+	u1 = irs.getIP();
+	irs.gen2(loc, (condition.isBooleanResult() ? IRjfb : IRjf), 0, c);
+	irs.release(c, 1);
+	ifbody.toIR(irs);
+	if (elsebody)
+	{
+	    u2 = irs.getIP();
+	    irs.gen1(loc, IRjmp, 0);
+	    irs.patchJmp(u1, irs.getIP());
+	    elsebody.toIR(irs);
+	    irs.patchJmp(u2, irs.getIP());
+	}
+	else
+	{
+	    irs.patchJmp(u1, irs.getIP());
+	}
+
+	// Help GC
+	condition = null;
+	ifbody = null;
+	elsebody = null;
+    }
+}
+
+/******************************** SwitchStatement ***************************/
+
+class SwitchStatement : Statement
+{
+    Expression condition;
+    Statement bdy;
+    uint breakIP;
+    ScopeStatement scopeContext;
+
+    DefaultStatement swdefault;
+    CaseStatement[] cases;
+
+    this(Loc loc, Expression c, Statement b)
+    {
+	super(loc);
+	condition = c;
+	bdy = b;
+	breakIP = ~0u;
+	scopeContext = null;
+
+	swdefault = null;
+	cases = null;
+    }
+
+    Statement semantic(Scope *sc)
+    {
+	condition = condition.semantic(sc);
+
+	SwitchStatement switchSave = sc.switchTarget;
+	Statement breakSave = sc.breakTarget;
+
+	scopeContext = sc.scopeContext;
+	sc.switchTarget = this;
+	sc.breakTarget = this;
+
+	bdy = bdy.semantic(sc);
+
+	sc.switchTarget = switchSave;
+	sc.breakTarget = breakSave;
+
+	return this;
+    }
+
+    void toIR(IRstate *irs)
+    {   uint c;
+	uint udefault;
+	uint marksave;
+
+	//writef("SwitchStatement.toIR()\n");
+	marksave = irs.mark();
+	c = irs.alloc(1);
+	condition.toIR(irs, c);
+
+	// Generate a sequence of cmp-jt
+	// Not the most efficient, but we await a more formal
+	// specification of switch before we attempt to optimize
+
+	if (cases.length)
+	{   uint x;
+
+	    x = irs.alloc(1);
+	    for (uint i = 0; i < cases.length; i++)
+	    {
+		CaseStatement cs;
+
+		x = irs.alloc(1);
+		cs = cases[i];
+		cs.exp.toIR(irs, x);
+		irs.gen3(loc, IRcid, x, c, x);
+		cs.patchIP = irs.getIP();
+		irs.gen2(loc, IRjt, 0, x);
+	    }
+	}
+	udefault = irs.getIP();
+	irs.gen1(loc, IRjmp, 0);
+
+	Statement breakSave = irs.breakTarget;
+	irs.breakTarget = this;
+	bdy.toIR(irs);
+
+	irs.breakTarget = breakSave;
+	breakIP = irs.getIP();
+
+	// Patch jump addresses
+	if (cases.length)
+	{
+	    for (uint i = 0; i < cases.length; i++)
+	    {   CaseStatement cs;
+
+		cs = cases[i];
+		irs.patchJmp(cs.patchIP, cs.caseIP);
+	    }
+	}
+	if (swdefault)
+	    irs.patchJmp(udefault, swdefault.defaultIP);
+	else
+	    irs.patchJmp(udefault, breakIP);
+	irs.release(marksave);
+
+	// Help gc
+	condition = null;
+	bdy = null;
+    }
+
+    uint getBreak()
+    {
+	return breakIP;
+    }
+
+    ScopeStatement getScope()
+    {
+	return scopeContext;
+    }
+}
+
+
+/******************************** CaseStatement ***************************/
+
+class CaseStatement : Statement
+{
+    Expression exp;
+    uint caseIP;
+    uint patchIP;
+
+    this(Loc loc, Expression exp)
+    {
+	super(loc);
+	this.exp = exp;
+	caseIP = ~0u;
+	patchIP = ~0u;
+    }
+
+    Statement semantic(Scope *sc)
+    {
+	//writef("CaseStatement.semantic(%p)\n", sc);
+	exp = exp.semantic(sc);
+	if (sc.switchTarget)
+	{
+	    SwitchStatement sw = sc.switchTarget;
+	    uint i;
+
+	    // Look for duplicate
+	    for (i = 0; i < sw.cases.length; i++)
+	    {
+		CaseStatement cs = sw.cases[i];
+
+		if (exp == cs.exp)
+		{
+		    error(sc, errmsgtbl[ERR_SWITCH_REDUNDANT_CASE], exp.toString());
+		    return null;
+		}
+	    }
+	    sw.cases ~= this;
+	}
+	else
+	{   error(sc, errmsgtbl[ERR_MISPLACED_SWITCH_CASE], exp.toString());
+	    return null;
+	}
+	return this;
+    }
+
+    void toIR(IRstate *irs)
+    {
+	caseIP = irs.getIP();
+    }
+}
+
+/******************************** DefaultStatement ***************************/
+
+class DefaultStatement : Statement
+{
+    uint defaultIP;
+
+    this(Loc loc)
+    {
+	super(loc);
+	defaultIP = ~0u;
+    }
+
+    Statement semantic(Scope *sc)
+    {
+	if (sc.switchTarget)
+	{
+	    SwitchStatement sw = sc.switchTarget;
+
+	    if (sw.swdefault)
+	    {
+		error(sc, ERR_SWITCH_REDUNDANT_DEFAULT);
+		return null;
+	    }
+	    sw.swdefault = this;
+	}
+	else
+	{   error(sc, ERR_MISPLACED_SWITCH_DEFAULT);
+	    return null;
+	}
+	return this;
+    }
+
+    void toIR(IRstate *irs)
+    {
+	defaultIP = irs.getIP();
+    }
+}
+
+/******************************** DoStatement ***************************/
+
+class DoStatement : Statement
+{
+    Statement bdy;
+    Expression condition;
+    uint breakIP;
+    uint continueIP;
+    ScopeStatement scopeContext;
+
+    this(Loc loc, Statement b, Expression c)
+    {
+	super(loc);
+	bdy = b;
+	condition = c;
+	breakIP = ~0u;
+	continueIP = ~0u;
+	scopeContext = null;
+    }
+
+    Statement semantic(Scope *sc)
+    {
+	Statement continueSave = sc.continueTarget;
+	Statement breakSave = sc.breakTarget;
+
+	scopeContext = sc.scopeContext;
+	sc.continueTarget = this;
+	sc.breakTarget = this;
+
+	bdy = bdy.semantic(sc);
+	condition = condition.semantic(sc);
+
+	sc.continueTarget = continueSave;
+	sc.breakTarget = breakSave;
+
+	return this;
+    }
+
+    TopStatement ImpliedReturn()
+    {
+	if (bdy)
+	    bdy = cast(Statement)bdy.ImpliedReturn();
+	return this;
+    }
+
+    void toIR(IRstate *irs)
+    {   uint c;
+	uint u1;
+	Statement continueSave = irs.continueTarget;
+	Statement breakSave = irs.breakTarget;
+	uint marksave;
+
+	irs.continueTarget = this;
+	irs.breakTarget = this;
+
+	marksave = irs.mark();
+	u1 = irs.getIP();
+	bdy.toIR(irs);
+	c = irs.alloc(1);
+	continueIP = irs.getIP();
+	condition.toIR(irs, c);
+	irs.gen2(loc, (condition.isBooleanResult() ? IRjtb : IRjt), u1 - irs.getIP(), c);
+	breakIP = irs.getIP();
+	irs.release(marksave);
+
+	irs.continueTarget = continueSave;
+	irs.breakTarget = breakSave;
+
+	// Help GC
+	condition = null;
+	bdy = null;
+    }
+
+    uint getBreak()
+    {
+	return breakIP;
+    }
+
+    uint getContinue()
+    {
+	return continueIP;
+    }
+
+    ScopeStatement getScope()
+    {
+	return scopeContext;
+    }
+}
+
+/******************************** WhileStatement ***************************/
+
+class WhileStatement : Statement
+{
+    Expression condition;
+    Statement bdy;
+    uint breakIP;
+    uint continueIP;
+    ScopeStatement scopeContext;
+
+    this(Loc loc, Expression c, Statement b)
+    {
+	super(loc);
+	condition = c;
+	bdy = b;
+	breakIP = ~0u;
+	continueIP = ~0u;
+	scopeContext = null;
+    }
+
+    Statement semantic(Scope *sc)
+    {
+	Statement continueSave = sc.continueTarget;
+	Statement breakSave = sc.breakTarget;
+
+	scopeContext = sc.scopeContext;
+	sc.continueTarget = this;
+	sc.breakTarget = this;
+
+	condition = condition.semantic(sc);
+	bdy = bdy.semantic(sc);
+
+	sc.continueTarget = continueSave;
+	sc.breakTarget = breakSave;
+
+	return this;
+    }
+
+    TopStatement ImpliedReturn()
+    {
+	if (bdy)
+	    bdy = cast(Statement)bdy.ImpliedReturn();
+	return this;
+    }
+
+    void toIR(IRstate *irs)
+    {   uint c;
+	uint u1;
+	uint u2;
+
+	Statement continueSave = irs.continueTarget;
+	Statement breakSave = irs.breakTarget;
+	uint marksave = irs.mark();
+
+	irs.continueTarget = this;
+	irs.breakTarget = this;
+
+	u1 = irs.getIP();
+	continueIP = u1;
+	c = irs.alloc(1);
+	condition.toIR(irs, c);
+	u2 = irs.getIP();
+	irs.gen2(loc, (condition.isBooleanResult() ? IRjfb : IRjf), 0, c);
+	bdy.toIR(irs);
+	irs.gen1(loc, IRjmp, u1 - irs.getIP());
+	irs.patchJmp(u2, irs.getIP());
+	breakIP = irs.getIP();
+
+	irs.release(marksave);
+	irs.continueTarget = continueSave;
+	irs.breakTarget = breakSave;
+
+	// Help GC
+	condition = null;
+	bdy = null;
+    }
+
+    uint getBreak()
+    {
+	return breakIP;
+    }
+
+    uint getContinue()
+    {
+	return continueIP;
+    }
+
+    ScopeStatement getScope()
+    {
+	return scopeContext;
+    }
+}
+
+/******************************** ForStatement ***************************/
+
+class ForStatement : Statement
+{
+    Statement init;
+    Expression condition;
+    Expression increment;
+    Statement bdy;
+    uint breakIP;
+    uint continueIP;
+    ScopeStatement scopeContext;
+
+    this(Loc loc, Statement init, Expression condition, Expression increment, Statement bdy)
+    {
+	super(loc);
+	this.init = init;
+	this.condition = condition;
+	this.increment = increment;
+	this.bdy = bdy;
+	breakIP = ~0u;
+	continueIP = ~0u;
+	scopeContext = null;
+    }
+
+    Statement semantic(Scope *sc)
+    {
+	Statement continueSave = sc.continueTarget;
+	Statement breakSave = sc.breakTarget;
+
+	if (init)
+	    init = init.semantic(sc);
+	if (condition)
+	    condition = condition.semantic(sc);
+	if (increment)
+	    increment = increment.semantic(sc);
+
+	scopeContext = sc.scopeContext;
+	sc.continueTarget = this;
+	sc.breakTarget = this;
+
+	bdy = bdy.semantic(sc);
+
+	sc.continueTarget = continueSave;
+	sc.breakTarget = breakSave;
+
+	return this;
+    }
+
+    TopStatement ImpliedReturn()
+    {
+	if (bdy)
+	    bdy = cast(Statement)bdy.ImpliedReturn();
+	return this;
+    }
+
+    void toIR(IRstate *irs)
+    {
+	uint u1;
+	uint u2 = 0;	// unneeded initialization keeps lint happy
+
+	Statement continueSave = irs.continueTarget;
+	Statement breakSave = irs.breakTarget;
+	uint marksave = irs.mark();
+
+	irs.continueTarget = this;
+	irs.breakTarget = this;
+
+	if (init)
+	    init.toIR(irs);
+	u1 = irs.getIP();
+	if (condition)
+	{
+	    if (condition.op == TOKless || condition.op == TOKlessequal)
+	    {
+		BinExp be = cast(BinExp)condition;
+		RealExpression re;
+		uint b;
+		uint c;
+
+		b = irs.alloc(1);
+		be.e1.toIR(irs, b);
+		re = cast(RealExpression )be.e2;
+		if (be.e2.op == TOKreal && !isnan(re.value))
+		{
+		    u2 = irs.getIP();
+		    irs.gen(loc, (condition.op == TOKless) ? IRjltc : IRjlec, 4, 0, b, re.value);
+		}
+		else
+		{
+		    c = irs.alloc(1);
+		    be.e2.toIR(irs, c);
+		    u2 = irs.getIP();
+		    irs.gen3(loc, (condition.op == TOKless) ? IRjlt : IRjle, 0, b, c);
+		}
+	    }
+	    else
+	    {   uint c;
+
+		c = irs.alloc(1);
+		condition.toIR(irs, c);
+		u2 = irs.getIP();
+		irs.gen2(loc, (condition.isBooleanResult() ? IRjfb : IRjf), 0, c);
+	    }
+	}
+	bdy.toIR(irs);
+	continueIP = irs.getIP();
+	if (increment)
+	    increment.toIR(irs, 0);
+	irs.gen1(loc, IRjmp, u1 - irs.getIP());
+	if (condition)
+	    irs.patchJmp(u2, irs.getIP());
+
+	breakIP = irs.getIP();
+
+	irs.release(marksave);
+	irs.continueTarget = continueSave;
+	irs.breakTarget = breakSave;
+
+	// Help GC
+	init = null;
+	condition = null;
+	bdy = null;
+	increment = null;
+    }
+
+    uint getBreak()
+    {
+	return breakIP;
+    }
+
+    uint getContinue()
+    {
+	return continueIP;
+    }
+
+    ScopeStatement getScope()
+    {
+	return scopeContext;
+    }
+}
+
+/******************************** ForInStatement ***************************/
+
+class ForInStatement : Statement
+{
+    Statement init;
+    Expression inexp;
+    Statement bdy;
+    uint breakIP;
+    uint continueIP;
+    ScopeStatement scopeContext;
+
+    this(Loc loc, Statement init, Expression inexp, Statement bdy)
+    {
+	super(loc);
+	this.init = init;
+	this.inexp = inexp;
+	this.bdy = bdy;
+	breakIP = ~0u;
+	continueIP = ~0u;
+	scopeContext = null;
+    }
+
+    Statement semantic(Scope *sc)
+    {
+	Statement continueSave = sc.continueTarget;
+	Statement breakSave = sc.breakTarget;
+
+	init = init.semantic(sc);
+
+	if (init.st == EXPSTATEMENT)
+	{   ExpStatement es;
+
+	    es = cast(ExpStatement)(init);
+	    es.exp.checkLvalue(sc);
+	}
+	else if (init.st == VARSTATEMENT)
+	{
+	}
+	else
+	{
+	    error(sc, ERR_INIT_NOT_EXPRESSION);
+	    return null;
+	}
+
+	inexp = inexp.semantic(sc);
+
+	scopeContext = sc.scopeContext;
+	sc.continueTarget = this;
+	sc.breakTarget = this;
+
+	bdy = bdy.semantic(sc);
+
+	sc.continueTarget = continueSave;
+	sc.breakTarget = breakSave;
+
+	return this;
+    }
+
+    TopStatement ImpliedReturn()
+    {
+	bdy = cast(Statement)bdy.ImpliedReturn();
+	return this;
+    }
+
+    void toIR(IRstate *irs)
+    {
+	uint e;
+	uint iter;
+	ExpStatement es;
+	VarStatement vs;
+	uint base;
+	IR property;
+	int opoff;
+	uint marksave = irs.mark();
+
+	e = irs.alloc(1);
+	inexp.toIR(irs, e);
+	iter = irs.alloc(1);
+	irs.gen2(loc, IRiter, iter, e);
+
+	Statement continueSave = irs.continueTarget;
+	Statement breakSave = irs.breakTarget;
+
+	irs.continueTarget = this;
+	irs.breakTarget = this;
+
+	if (init.st == EXPSTATEMENT)
+	{
+	    es = cast(ExpStatement)(init);
+	    es.exp.toLvalue(irs, base, &property, opoff);
+	}
+	else if (init.st == VARSTATEMENT)
+	{
+	    VarDeclaration vd;
+
+	    vs = cast(VarStatement)(init);
+	    assert(vs.vardecls.length == 1);
+	    vd = vs.vardecls[0];
+
+	    property.id = Identifier.build(vd.name.toString());
+	    opoff = 2;
+	    base = ~0u;
+	}
+	else
+	{   // Error already reported by semantic()
+	    return;
+	}
+
+	continueIP = irs.getIP();
+	if (opoff == 2)
+	    irs.gen3(loc, IRnextscope, 0, property.index, iter);
+	else
+	    irs.gen(loc, IRnext + opoff, 4, 0, base, property.index, iter);
+	bdy.toIR(irs);
+	irs.gen1(loc, IRjmp, continueIP - irs.getIP());
+	irs.patchJmp(continueIP, irs.getIP());
+
+	breakIP = irs.getIP();
+
+	irs.continueTarget = continueSave;
+	irs.breakTarget = breakSave;
+	irs.release(marksave);
+
+	// Help GC
+	init = null;
+	inexp = null;
+	bdy = null;
+    }
+
+    uint getBreak()
+    {
+	return breakIP;
+    }
+
+    uint getContinue()
+    {
+	return continueIP;
+    }
+
+    ScopeStatement getScope()
+    {
+	return scopeContext;
+    }
+}
+
+/******************************** ScopeStatement ***************************/
+
+class ScopeStatement : Statement
+{
+    ScopeStatement enclosingScope;
+    int depth;			// syntactical nesting level of ScopeStatement's
+    int npops;			// how many items added to scope chain
+
+    this(Loc loc)
+    {
+	super(loc);
+	enclosingScope = null;
+	depth = 1;
+	npops = 1;
+    }
+}
+
+/******************************** WithStatement ***************************/
+
+class WithStatement : ScopeStatement
+{
+    Expression exp;
+    Statement bdy;
+
+    this(Loc loc, Expression exp, Statement bdy)
+    {
+	super(loc);
+	this.exp = exp;
+	this.bdy = bdy;
+    }
+
+    Statement semantic(Scope *sc)
+    {
+	exp = exp.semantic(sc);
+
+	enclosingScope = sc.scopeContext;
+	sc.scopeContext = this;
+
+	// So enclosing FunctionDeclaration knows how deep the With's
+	// can nest
+	if (enclosingScope)
+	    depth = enclosingScope.depth + 1;
+	if (depth > sc.funcdef.withdepth)
+	    sc.funcdef.withdepth = depth;
+
+	sc.nestDepth++;
+	bdy = bdy.semantic(sc);
+	sc.nestDepth--;
+
+	sc.scopeContext = enclosingScope;
+	return this;
+    }
+
+    TopStatement ImpliedReturn()
+    {
+	bdy = cast(Statement)bdy.ImpliedReturn();
+	return this;
+    }
+
+
+
+    void toIR(IRstate *irs)
+    {
+	uint c;
+	uint marksave = irs.mark();
+
+	irs.scopeContext = this;
+
+	c = irs.alloc(1);
+	exp.toIR(irs, c);
+	irs.gen1(loc, IRpush, c);
+	bdy.toIR(irs);
+	irs.gen0(loc, IRpop);
+
+	irs.scopeContext = enclosingScope;
+	irs.release(marksave);
+
+	// Help GC
+	exp = null;
+	bdy = null;
+    }
+}
+
+/******************************** ContinueStatement ***************************/
+
+class ContinueStatement : Statement
+{
+    Identifier *ident;
+    Statement target;
+
+    this(Loc loc, Identifier *ident)
+    {
+	super(loc);
+	this.ident = ident;
+	target = null;
+    }
+
+    Statement semantic(Scope *sc)
+    {
+	if (ident == null)
+	{
+	    target = sc.continueTarget;
+	    if (!target)
+	    {
+		error(sc, ERR_MISPLACED_CONTINUE);
+		return null;
+	    }
+	}
+	else
+	{   LabelSymbol ls;
+
+	    ls = sc.searchLabel(ident);
+	    if (!ls || !ls.statement)
+	    {   error(sc, errmsgtbl[ERR_UNDEFINED_STATEMENT_LABEL], ident.toString());
+		return null;
+	    }
+	    else
+		target = ls.statement;
+	}
+	return this;
+    }
+
+    void toIR(IRstate *irs)
+    {   ScopeStatement w;
+	ScopeStatement tw;
+
+	tw = target.getScope();
+	for (w = irs.scopeContext; !(w is tw); w = w.enclosingScope)
+	{
+	    assert(w);
+	    irs.pops(w.npops);
+	}
+	irs.addFixup(irs.getIP());
+	irs.gen1(loc, IRjmp, cast(uint)cast(void*)this);
+    }
+
+    uint getTarget()
+    {
+	assert(target);
+	return target.getContinue();
+    }
+}
+
+/******************************** BreakStatement ***************************/
+
+class BreakStatement : Statement
+{
+    Identifier *ident;
+    Statement target;
+
+    this(Loc loc, Identifier *ident)
+    {
+	super(loc);
+	this.ident = ident;
+	target = null;
+    }
+
+    Statement semantic(Scope *sc)
+    {
+	//writef("BreakStatement.semantic(%p)\n", sc);
+	if (ident == null)
+	{
+	    target = sc.breakTarget;
+	    if (!target)
+	    {
+		error(sc, ERR_MISPLACED_BREAK);
+		return null;
+	    }
+	}
+	else
+	{   LabelSymbol ls;
+
+	    ls = sc.searchLabel(ident);
+	    if (!ls || !ls.statement)
+	    {   error(sc, errmsgtbl[ERR_UNDEFINED_STATEMENT_LABEL], ident.toString());
+		return null;
+	    }
+	    else
+		target = ls.statement;
+	}
+	return this;
+    }
+
+    void toIR(IRstate *irs)
+    {   ScopeStatement w;
+	ScopeStatement tw;
+
+	assert(target);
+	tw = target.getScope();
+	for (w = irs.scopeContext; !(w is tw); w = w.enclosingScope)
+	{
+	    assert(w);
+	    irs.pops(w.npops);
+	}
+
+	irs.addFixup(irs.getIP());
+	irs.gen1(loc, IRjmp, cast(uint)cast(void*)this);
+    }
+
+    uint getTarget()
+    {
+	assert(target);
+	return target.getBreak();
+    }
+}
+
+/******************************** GotoStatement ***************************/
+
+class GotoStatement : Statement
+{
+    Identifier *ident;
+    LabelSymbol label;
+
+    this(Loc loc, Identifier *ident)
+    {
+	super(loc);
+	this.ident = ident;
+	label = null;
+    }
+
+    Statement semantic(Scope *sc)
+    {
+	LabelSymbol ls;
+
+	ls = sc.searchLabel(ident);
+	if (!ls)
+	{
+	    ls = new LabelSymbol(loc, ident, null);
+	    sc.insertLabel(ls);
+	}
+	label = ls;
+	return this;
+    }
+
+    void toIR(IRstate *irs)
+    {
+	assert(label);
+
+	// Determine how many with pops we need to do
+	for (ScopeStatement w = irs.scopeContext; ; w = w.enclosingScope)
+	{
+	    if (!w)
+	    {
+		if (label.statement.scopeContext)
+		{
+		    assert(0); // BUG: should do next statement instead
+		    //script.error(errmsgtbl[ERR_GOTO_INTO_WITH]);
+		}
+		break;
+	    }
+	    if (w is label.statement.scopeContext)
+		break;
+	    irs.pops(w.npops);
+	}
+
+	irs.addFixup(irs.getIP());
+	irs.gen1(loc, IRjmp, cast(uint)cast(void*)this);
+    }
+
+    uint getTarget()
+    {
+	return label.statement.getGoto();
+    }
+}
+
+/******************************** ReturnStatement ***************************/
+
+class ReturnStatement : Statement
+{
+    Expression exp;
+
+    this(Loc loc, Expression exp)
+    {
+	super(loc);
+	this.exp = exp;
+    }
+
+    Statement semantic(Scope *sc)
+    {
+	if (exp)
+	    exp = exp.semantic(sc);
+
+	// Don't allow return from eval functions or global function
+	if (sc.funcdef.iseval || sc.funcdef.isglobal)
+	    error(sc, ERR_MISPLACED_RETURN);
+
+	return this;
+    }
+
+    void toBuffer(inout tchar[] buf)
+    {
+	//writef("ReturnStatement.toBuffer()\n");
+	buf ~= "return ";
+	if (exp)
+	    exp.toBuffer(buf);
+	buf ~= ";\n";
+    }
+
+    void toIR(IRstate *irs)
+    {   ScopeStatement w;
+	int npops;
+
+	npops = 0;
+	for (w = irs.scopeContext; w; w = w.enclosingScope)
+	    npops += w.npops;
+
+	if (exp)
+	{   uint e;
+
+	    e = irs.alloc(1);
+	    exp.toIR(irs, e);
+	    if (npops)
+	    {
+		irs.gen1(loc, IRimpret, e);
+		irs.pops(npops);
+		irs.gen0(loc, IRret);
+	    }
+	    else
+		irs.gen1(loc, IRretexp, e);
+	    irs.release(e, 1);
+	}
+	else
+	{
+	    if (npops)
+		irs.pops(npops);
+	    irs.gen0(loc, IRret);
+	}
+
+	// Help GC
+	exp = null;
+    }
+}
+
+/******************************** ImpliedReturnStatement ***************************/
+
+// Same as ReturnStatement, except that the return value is set but the
+// function does not actually return. Useful for setting the return
+// value for loop bodies.
+
+class ImpliedReturnStatement : Statement
+{
+    Expression exp;
+
+    this(Loc loc, Expression exp)
+    {
+	super(loc);
+	this.exp = exp;
+    }
+
+    Statement semantic(Scope *sc)
+    {
+	if (exp)
+	    exp = exp.semantic(sc);
+	return this;
+    }
+
+    void toBuffer(inout tchar[] buf)
+    {
+	if (exp)
+	    exp.toBuffer(buf);
+	buf ~= ";\n";
+    }
+
+    void toIR(IRstate *irs)
+    {
+	if (exp)
+	{   uint e;
+
+	    e = irs.alloc(1);
+	    exp.toIR(irs, e);
+	    irs.gen1(loc, IRimpret, e);
+	    irs.release(e, 1);
+
+	    // Help GC
+	    exp = null;
+	}
+    }
+}
+
+/******************************** ThrowStatement ***************************/
+
+class ThrowStatement : Statement
+{
+    Expression exp;
+
+    this(Loc loc, Expression exp)
+    {
+	super(loc);
+	this.exp = exp;
+    }
+
+    Statement semantic(Scope *sc)
+    {
+	if (exp)
+	    exp = exp.semantic(sc);
+	else
+	{
+	    error(sc, ERR_NO_THROW_EXPRESSION);
+	    return new EmptyStatement(loc);
+	}
+	return this;
+    }
+
+    void toBuffer(inout tchar[] buf)
+    {
+	buf ~= "throw ";
+	if (exp)
+	    exp.toBuffer(buf);
+	buf ~= ";\n";
+    }
+
+    void toIR(IRstate *irs)
+    {
+	uint e;
+
+	assert(exp);
+	e = irs.alloc(1);
+	exp.toIR(irs, e);
+	irs.gen1(loc, IRthrow, e);
+	irs.release(e, 1);
+
+	// Help GC
+	exp = null;
+    }
+}
+
+/******************************** TryStatement ***************************/
+
+class TryStatement : ScopeStatement
+{
+    Statement bdy;
+    Identifier* catchident;
+    Statement catchbdy;
+    Statement finalbdy;
+
+    this(Loc loc, Statement bdy,
+	    Identifier *catchident, Statement catchbdy,
+	    Statement finalbdy)
+    {
+	super(loc);
+	this.bdy = bdy;
+	this.catchident = catchident;
+	this.catchbdy = catchbdy;
+	this.finalbdy = finalbdy;
+	if (catchbdy && finalbdy)
+	    npops = 2;		// 2 items in scope chain
+    }
+
+    Statement semantic(Scope *sc)
+    {
+	enclosingScope = sc.scopeContext;
+	sc.scopeContext = this;
+
+	// So enclosing FunctionDeclaration knows how deep the With's
+	// can nest
+	if (enclosingScope)
+	    depth = enclosingScope.depth + 1;
+	if (depth > sc.funcdef.withdepth)
+	    sc.funcdef.withdepth = depth;
+
+	bdy.semantic(sc);
+	if (catchbdy)
+	    catchbdy.semantic(sc);
+	if (finalbdy)
+	    finalbdy.semantic(sc);
+
+	sc.scopeContext = enclosingScope;
+	return this;
+    }
+
+    void toBuffer(inout tchar[] buf)
+    {
+	buf ~= "try\n";
+	bdy.toBuffer(buf);
+	if (catchident)
+	{
+	    buf ~= "catch (" ~
+		   catchident.toString() ~
+		   ")\n";
+	}
+	if (catchbdy)
+	    catchbdy.toBuffer(buf);
+	if (finalbdy)
+	{
+	    buf ~= "finally\n";
+	    finalbdy.toBuffer(buf);
+	}
+    }
+
+    void toIR(IRstate *irs)
+    {   uint f;
+	uint c;
+	uint e;
+	uint e2;
+	uint marksave = irs.mark();
+
+	irs.scopeContext = this;
+	if (finalbdy)
+	{
+	    f = irs.getIP();
+	    irs.gen1(loc, IRtryfinally, 0);
+	    if (catchbdy)
+	    {
+		c = irs.getIP();
+		irs.gen2(loc, IRtrycatch, 0, cast(uint)Identifier.build(catchident.toString()));
+		bdy.toIR(irs);
+		irs.gen0(loc, IRpop);		// remove catch clause
+		irs.gen0(loc, IRpop);		// call finalbdy
+
+		e = irs.getIP();
+		irs.gen1(loc, IRjmp, 0);
+		irs.patchJmp(c, irs.getIP());
+		catchbdy.toIR(irs);
+		irs.gen0(loc, IRpop);		// remove catch object
+		irs.gen0(loc, IRpop);		// call finalbdy code
+		e2 = irs.getIP();
+		irs.gen1(loc, IRjmp, 0);	// jmp past finalbdy
+
+		irs.patchJmp(f, irs.getIP());
+		irs.scopeContext = enclosingScope;
+		finalbdy.toIR(irs);
+		irs.gen0(loc, IRfinallyret);
+		irs.patchJmp(e, irs.getIP());
+		irs.patchJmp(e2, irs.getIP());
+	    }
+	    else // finalbdy only
+	    {
+		bdy.toIR(irs);
+		irs.gen0(loc, IRpop);
+		e = irs.getIP();
+		irs.gen1(loc, IRjmp, 0);
+		irs.patchJmp(f, irs.getIP());
+		irs.scopeContext = enclosingScope;
+		finalbdy.toIR(irs);
+		irs.gen0(loc, IRfinallyret);
+		irs.patchJmp(e, irs.getIP());
+	    }
+	}
+	else // catchbdy only
+	{
+	    c = irs.getIP();
+	    irs.gen2(loc, IRtrycatch, 0, cast(uint)Identifier.build(catchident.toString()));
+	    bdy.toIR(irs);
+	    irs.gen0(loc, IRpop);
+	    e = irs.getIP();
+	    irs.gen1(loc, IRjmp, 0);
+	    irs.patchJmp(c, irs.getIP());
+	    catchbdy.toIR(irs);
+	    irs.gen0(loc, IRpop);
+	    irs.patchJmp(e, irs.getIP());
+	}
+	irs.scopeContext = enclosingScope;
+	irs.release(marksave);
+
+	// Help GC
+	bdy = null;
+	catchident = null;
+	catchbdy = null;
+	finalbdy = null;
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/dmdscript_tango/symbol.d	Sun Jan 24 12:34:47 2010 +0200
@@ -0,0 +1,200 @@
+
+/* 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.symbol;
+
+import std.stdio;
+
+import dmdscript.script;
+import dmdscript.identifier;
+import dmdscript.scopex;
+import dmdscript.statement;
+import dmdscript.irstate;
+import dmdscript.opcodes;
+import dmdscript.errmsgs;
+
+/****************************** Symbol ******************************/
+
+class Symbol
+{
+    Identifier *ident;
+
+    this()
+    {
+    }
+
+    this(Identifier *ident)
+    {
+	this.ident = ident;
+    }
+
+    int opEquals(Object o)
+    {   Symbol s;
+
+	if (this == o)
+	    return true;
+	s = cast(Symbol)o;
+	if (s && ident == s.ident)
+	    return true;
+	return false;
+    }
+
+    tchar[] toString()
+    {
+	return ident ? "__ident" : "__anonymous";
+    }
+
+    void semantic(Scope *sc)
+    {
+	assert(0);
+    }
+
+    Symbol search(Identifier *ident)
+    {
+	assert(0);
+	//error(DTEXT("%s.%s is undefined"),toString(), ident.toString());
+	return this;
+    }
+
+    void toBuffer(inout tchar[] buf)
+    {
+	buf ~= toString();
+    }
+}
+
+
+/********************************* ScopeSymbol ****************************/
+
+// Symbol that generates a scope
+
+class ScopeSymbol : Symbol
+{
+    Symbol[] members;		// all Symbol's in this scope
+    SymbolTable *symtab;	// member[] sorted into table
+
+    this()
+    {
+	super();
+    }
+
+    this(Identifier *id)
+    {
+	super(id);
+    }
+
+    Symbol search(Identifier *ident)
+    {   Symbol s;
+
+	//writef("ScopeSymbol::search(%s, '%s')\n", toString(), ident.toString());
+	// Look in symbols declared in this module
+	s = symtab ? symtab.lookup(ident) : null;
+	if (s)
+	    writef("\ts = '%s.%s'\n",toString(),s.toString());
+	return s;
+    }
+}
+
+
+/****************************** SymbolTable ******************************/
+
+// Table of Symbol's
+
+struct SymbolTable
+{
+    Symbol[Identifier*] members;
+
+    // Look up Identifier. Return Symbol if found, NULL if not.
+    Symbol lookup(Identifier *ident)
+    {
+	Symbol *ps;
+
+	ps = ident in members;
+	if (ps)
+	    return *ps;
+	return null;
+    }
+
+    // Insert Symbol in table. Return NULL if already there.
+    Symbol insert(Symbol s)
+    {
+	Symbol *ps;
+
+	ps = s.ident in members;
+	if (ps)
+	    return null;	// already in table
+	members[s.ident] = s;
+	return s;
+    }
+
+    // Look for Symbol in table. If there, return it.
+    // If not, insert s and return that.
+    Symbol update(Symbol s)
+    {
+	members[s.ident] = s;
+	return s;
+    }
+}
+
+
+/****************************** FunctionSymbol ******************************/
+
+class FunctionSymbol : ScopeSymbol
+{
+    Loc loc;
+
+    Identifier*[] parameters;		// array of Identifier's
+    TopStatement[] topstatements;	// array of TopStatement's
+
+    SymbolTable labtab;		// symbol table for LabelSymbol's
+
+    IR *code;
+    uint nlocals;
+
+    this(Loc loc, Identifier* ident, Identifier*[] parameters,
+	TopStatement[] topstatements)
+    {
+	super(ident);
+	this.loc = loc;
+	this.parameters = parameters;
+	this.topstatements = topstatements;
+    }
+
+    void semantic(Scope *sc)
+    {
+    }
+}
+
+
+/****************************** LabelSymbol ******************************/
+
+class LabelSymbol : Symbol
+{   Loc loc;
+    LabelStatement statement;
+
+    this(Loc loc, Identifier* ident, LabelStatement statement)
+    {
+	super(ident);
+	this.loc = loc;
+	this.statement = statement;
+    }
+}
+
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/dmdscript_tango/test/testscript.d	Sun Jan 24 12:34:47 2010 +0200
@@ -0,0 +1,231 @@
+
+/* 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 testscript;
+
+import std.path;
+import std.file;
+import std.stdio;
+import std.c.stdlib;
+import std.gc;
+
+import dmdscript.script;
+import dmdscript.program;
+import dmdscript.errmsgs;
+
+enum
+{
+	EXITCODE_INIT_ERROR = 1,
+	EXITCODE_INVALID_ARGS = 2,
+	EXITCODE_RUNTIME_ERROR = 3,
+}
+
+version (Windows)
+{
+    pragma(lib, "dmdscript");
+}
+
+
+
+/**************************************************
+	Usage:
+
+	    ds
+		will run test.ds
+
+	    ds foo
+		will run foo.ds
+
+	    ds foo.js
+		will run foo.js
+
+	    ds foo1 foo2 foo.bar
+		will run foo1.ds, foo2.ds, foo.bar
+
+	The -iinc flag will prefix the source files with the contents of file inc.
+	There can be multiple -i's. The include list is reset to empty any time
+	a new -i is encountered that is not preceded by a -i.
+
+	    ds -iinc foo
+		will prefix foo.ds with inc
+
+	    ds -iinc1 -iinc2 foo bar
+		will prefix foo.ds with inc1+inc2, and will prefix bar.ds
+		with inc1+inc2
+
+	    ds -iinc1 -iinc2 foo -iinc3 bar
+		will prefix foo.ds with inc1+inc2, and will prefix bar.ds
+		with inc3
+
+	    ds -iinc1 -iinc2 foo -i bar
+		will prefix foo.ds with inc1+inc2, and will prefix bar.ds
+		with nothing
+
+ */
+
+int main(char[][] args)
+{
+    uint errors = 0;
+    char[][] includes;
+    SrcFile[] srcfiles;
+    int result;
+    bool verbose;
+    ErrInfo errinfo;
+
+    fwritefln(stderr, dmdscript.script.banner());
+
+    for (size_t i = 1; i < args.length; i++)
+    {	char[] p = args[i];
+
+	if (p[0] == '-')
+	{
+	    switch (p[1])
+	    {
+		case 'i':
+		    if (p[2])
+			includes ~= p[2 .. length];
+		    break;
+
+		case 'v':
+		    verbose = 1;
+		    break;
+
+		default:
+		    writefln(errmsgtbl[ERR_BAD_SWITCH],p);
+		    errors++;
+		    break;
+	    }
+	}
+	else
+	{
+	    srcfiles ~= new SrcFile(p, includes);
+	    includes = null;
+	}
+    }
+    if (errors)
+	return EXITCODE_INVALID_ARGS;
+
+    if (srcfiles.length == 0)
+    {
+	srcfiles ~= new SrcFile("test", null);
+    }
+
+    fwritefln(stderr, "%d source files", srcfiles.length);
+
+    // Read files, parse them, execute them
+    foreach (SrcFile m; srcfiles)
+    {
+	if (verbose)
+	    writefln("read    %s:", m.srcfile);
+	m.read();
+	if (verbose)
+	    writefln("compile %s:", m.srcfile);
+	m.compile();
+	if (verbose)
+	    writefln("execute %s:", m.srcfile);
+	m.execute();
+    }
+
+    return EXIT_SUCCESS;
+}
+
+
+class SrcFile
+{
+    char[] srcfile;
+    char[][] includes;
+
+    Program program;
+    char[] buffer;
+
+    this(char[] srcfilename, char[][] includes)
+    {
+	/* DMDScript source files default to a '.ds' extension
+	 */
+
+	srcfile = std.path.defaultExt(srcfilename, "ds");
+	this.includes = includes;
+    }
+
+    void read()
+    {
+	/* Read the source file, prepend the include files,
+	 * and put it all in buffer[]. Allocate an extra byte
+	 * to buffer[] and terminate it with a 0x1A.
+	 * (If the 0x1A isn't at the end, the lexer will put
+	 * one there, forcing an extra copy to be made of the
+	 * source text.)
+	 */
+
+	//writef("read file '%s'\n",srcfile);
+
+	// Read the includes[] files
+	size_t i;
+	void[] buf;
+	ulong len;
+
+	len = std.file.getSize(srcfile);
+	foreach (char[] filename; includes)
+	{
+	    len += std.file.getSize(filename);
+	}
+	len++;				// leave room for sentinal
+
+	assert(len < uint.max);
+
+	// Prefix the includes[] files
+
+	int sz = cast(int)len;
+	buffer = new tchar[sz];
+
+	foreach (char[] filename; includes)
+	{
+	    buf = std.file.read(filename);
+	    buffer[i .. i + buf.length] = cast(char[])buf[];
+	    i += buf.length;
+	}
+
+	buf = std.file.read(srcfile);
+	buffer[i .. i + buf.length] = cast(char[])buf[];
+	i += buf.length;
+
+	buffer[i] = 0x1A;		// ending sentinal
+	i++;
+	assert(i == len);
+    }
+
+    void compile()
+    {
+	/* Create a DMDScript program, and compile our text buffer.
+	 */
+
+	program = new Program();
+	program.compile(srcfile, buffer, null);
+    }
+
+    void execute()
+    {
+	/* Execute the resulting program.
+	 */
+
+	program.execute(null);
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/dmdscript_tango/text.d	Sun Jan 24 12:34:47 2010 +0200
@@ -0,0 +1,274 @@
+
+/* 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.text;
+
+
+char[] TEXT_ = "";
+char[] TEXT_source = "source";
+char[] TEXT_global = "global";
+char[] TEXT_ignoreCase = "ignoreCase";
+char[] TEXT_multiline = "multiline";
+char[] TEXT_lastIndex = "lastIndex";
+char[] TEXT_input = "input";
+char[] TEXT_lastMatch = "lastMatch";
+char[] TEXT_lastParen = "lastParen";
+char[] TEXT_leftContext = "leftContext";
+char[] TEXT_rightContext = "rightContext";
+char[] TEXT_prototype = "prototype";
+char[] TEXT_constructor = "constructor";
+char[] TEXT_toString = "toString";
+char[] TEXT_toLocaleString = "toLocaleString";
+char[] TEXT_toSource = "toSource";
+char[] TEXT_valueOf = "valueOf";
+char[] TEXT_message = "message";
+char[] TEXT_description = "description";
+char[] TEXT_Error = "Error";
+char[] TEXT_name = "name";
+char[] TEXT_length = "length";
+char[] TEXT_NaN = "NaN";
+char[] TEXT_Infinity = "Infinity";
+char[] TEXT_negInfinity = "-Infinity";
+char[] TEXT_bobjectb = "[object]";
+char[] TEXT_undefined = "undefined";
+char[] TEXT_null = "null";
+char[] TEXT_true = "true";
+char[] TEXT_false = "false";
+char[] TEXT_object = "object";
+char[] TEXT_string = "string";
+char[] TEXT_number = "number";
+char[] TEXT_boolean = "boolean";
+char[] TEXT_Object = "Object";
+char[] TEXT_String = "String";
+char[] TEXT_Number = "Number";
+char[] TEXT_Boolean = "Boolean";
+char[] TEXT_Date = "Date";
+char[] TEXT_Array = "Array";
+char[] TEXT_RegExp = "RegExp";
+char[] TEXT_arity = "arity";
+char[] TEXT_arguments = "arguments";
+char[] TEXT_callee = "callee";
+char[] TEXT_caller = "caller";			// extension
+char[] TEXT_EvalError = "EvalError";
+char[] TEXT_RangeError = "RangeError";
+char[] TEXT_ReferenceError = "ReferenceError";
+char[] TEXT_SyntaxError = "SyntaxError";
+char[] TEXT_TypeError = "TypeError";
+char[] TEXT_URIError = "URIError";
+char[] TEXT_this = "this";
+char[] TEXT_fromCharCode = "fromCharCode";
+char[] TEXT_charAt = "charAt";
+char[] TEXT_charCodeAt = "charCodeAt";
+char[] TEXT_concat = "concat";
+char[] TEXT_indexOf = "indexOf";
+char[] TEXT_lastIndexOf = "lastIndexOf";
+char[] TEXT_localeCompare = "localeCompare";
+char[] TEXT_match = "match";
+char[] TEXT_replace = "replace";
+char[] TEXT_search = "search";
+char[] TEXT_slice = "slice";
+char[] TEXT_split = "split";
+char[] TEXT_substr = "substr";
+char[] TEXT_substring = "substring";
+char[] TEXT_toLowerCase = "toLowerCase";
+char[] TEXT_toLocaleLowerCase = "toLocaleLowerCase";
+char[] TEXT_toUpperCase = "toUpperCase";
+char[] TEXT_toLocaleUpperCase = "toLocaleUpperCase";
+char[] TEXT_hasOwnProperty = "hasOwnProperty";
+char[] TEXT_isPrototypeOf = "isPrototypeOf";
+char[] TEXT_propertyIsEnumerable = "propertyIsEnumerable";
+char[] TEXT_dollar1 = "$1";
+char[] TEXT_dollar2 = "$2";
+char[] TEXT_dollar3 = "$3";
+char[] TEXT_dollar4 = "$4";
+char[] TEXT_dollar5 = "$5";
+char[] TEXT_dollar6 = "$6";
+char[] TEXT_dollar7 = "$7";
+char[] TEXT_dollar8 = "$8";
+char[] TEXT_dollar9 = "$9";
+char[] TEXT_index = "index";
+char[] TEXT_compile = "compile";
+char[] TEXT_test = "test";
+char[] TEXT_exec = "exec";
+char[] TEXT_MAX_VALUE = "MAX_VALUE";
+char[] TEXT_MIN_VALUE = "MIN_VALUE";
+char[] TEXT_NEGATIVE_INFINITY = "NEGATIVE_INFINITY";
+char[] TEXT_POSITIVE_INFINITY = "POSITIVE_INFINITY";
+char[] TEXT_dash = "-";
+char[] TEXT_toFixed = "toFixed";
+char[] TEXT_toExponential = "toExponential";
+char[] TEXT_toPrecision = "toPrecision";
+char[] TEXT_abs = "abs";
+char[] TEXT_acos = "acos";
+char[] TEXT_asin = "asin";
+char[] TEXT_atan = "atan";
+char[] TEXT_atan2 = "atan2";
+char[] TEXT_ceil = "ceil";
+char[] TEXT_cos = "cos";
+char[] TEXT_exp = "exp";
+char[] TEXT_floor = "floor";
+char[] TEXT_log = "log";
+char[] TEXT_max = "max";
+char[] TEXT_min = "min";
+char[] TEXT_pow = "pow";
+char[] TEXT_random = "random";
+char[] TEXT_round = "round";
+char[] TEXT_sin = "sin";
+char[] TEXT_sqrt = "sqrt";
+char[] TEXT_tan = "tan";
+char[] TEXT_E = "E";
+char[] TEXT_LN10 = "LN10";
+char[] TEXT_LN2 = "LN2";
+char[] TEXT_LOG2E = "LOG2E";
+char[] TEXT_LOG10E = "LOG10E";
+char[] TEXT_PI = "PI";
+char[] TEXT_SQRT1_2 = "SQRT1_2";
+char[] TEXT_SQRT2 = "SQRT2";
+char[] TEXT_parse = "parse";
+char[] TEXT_UTC = "UTC";
+
+char[] TEXT_getTime = "getTime";
+char[] TEXT_getYear = "getYear";
+char[] TEXT_getFullYear = "getFullYear";
+char[] TEXT_getUTCFullYear = "getUTCFullYear";
+char[] TEXT_getDate = "getDate";
+char[] TEXT_getUTCDate = "getUTCDate";
+char[] TEXT_getMonth = "getMonth";
+char[] TEXT_getUTCMonth = "getUTCMonth";
+char[] TEXT_getDay = "getDay";
+char[] TEXT_getUTCDay = "getUTCDay";
+char[] TEXT_getHours = "getHours";
+char[] TEXT_getUTCHours = "getUTCHours";
+char[] TEXT_getMinutes = "getMinutes";
+char[] TEXT_getUTCMinutes = "getUTCMinutes";
+char[] TEXT_getSeconds = "getSeconds";
+char[] TEXT_getUTCSeconds = "getUTCSeconds";
+char[] TEXT_getMilliseconds = "getMilliseconds";
+char[] TEXT_getUTCMilliseconds = "getUTCMilliseconds";
+char[] TEXT_getTimezoneOffset = "getTimezoneOffset";
+char[] TEXT_getVarDate = "getVarDate";
+
+char[] TEXT_setTime = "setTime";
+char[] TEXT_setYear = "setYear";
+char[] TEXT_setFullYear = "setFullYear";
+char[] TEXT_setUTCFullYear = "setUTCFullYear";
+char[] TEXT_setDate = "setDate";
+char[] TEXT_setUTCDate = "setUTCDate";
+char[] TEXT_setMonth = "setMonth";
+char[] TEXT_setUTCMonth = "setUTCMonth";
+char[] TEXT_setDay = "setDay";
+char[] TEXT_setUTCDay = "setUTCDay";
+char[] TEXT_setHours = "setHours";
+char[] TEXT_setUTCHours = "setUTCHours";
+char[] TEXT_setMinutes = "setMinutes";
+char[] TEXT_setUTCMinutes = "setUTCMinutes";
+char[] TEXT_setSeconds = "setSeconds";
+char[] TEXT_setUTCSeconds = "setUTCSeconds";
+char[] TEXT_setMilliseconds = "setMilliseconds";
+char[] TEXT_setUTCMilliseconds = "setUTCMilliseconds";
+
+char[] TEXT_toDateString = "toDateString";
+char[] TEXT_toTimeString = "toTimeString";
+char[] TEXT_toLocaleDateString = "toLocaleDateString";
+char[] TEXT_toLocaleTimeString = "toLocaleTimeString";
+char[] TEXT_toUTCString = "toUTCString";
+char[] TEXT_toGMTString = "toGMTString";
+
+char[] TEXT_comma =  ",";
+char[] TEXT_join = "join";
+char[] TEXT_pop = "pop";
+char[] TEXT_push = "push";
+char[] TEXT_reverse = "reverse";
+char[] TEXT_shift = "shift";
+char[] TEXT_sort = "sort";
+char[] TEXT_splice = "splice";
+char[] TEXT_unshift = "unshift";
+char[] TEXT_apply = "apply";
+char[] TEXT_call = "call";
+char[] TEXT_function = "function";
+
+char[] TEXT_eval = "eval";
+char[] TEXT_parseInt = "parseInt";
+char[] TEXT_parseFloat = "parseFloat";
+char[] TEXT_escape = "escape";
+char[] TEXT_unescape = "unescape";
+char[] TEXT_isNaN = "isNaN";
+char[] TEXT_isFinite = "isFinite";
+char[] TEXT_decodeURI = "decodeURI";
+char[] TEXT_decodeURIComponent = "decodeURIComponent";
+char[] TEXT_encodeURI = "encodeURI";
+char[] TEXT_encodeURIComponent = "encodeURIComponent";
+
+char[] TEXT_print = "print";
+char[] TEXT_println = "println";
+char[] TEXT_readln = "readln";
+char[] TEXT_getenv = "getenv";
+char[] TEXT_assert = "assert";
+
+char[] TEXT_Function = "Function";
+char[] TEXT_Math = "Math";
+
+char[] TEXT_0 = "0";
+char[] TEXT_1 = "1";
+char[] TEXT_2 = "2";
+char[] TEXT_3 = "3";
+char[] TEXT_4 = "4";
+char[] TEXT_5 = "5";
+char[] TEXT_6 = "6";
+char[] TEXT_7 = "7";
+char[] TEXT_8 = "8";
+char[] TEXT_9 = "9";
+
+char[] TEXT_anchor = "anchor";
+char[] TEXT_big = "big";
+char[] TEXT_blink = "blink";
+char[] TEXT_bold = "bold";
+char[] TEXT_fixed = "fixed";
+char[] TEXT_fontcolor = "fontcolor";
+char[] TEXT_fontsize = "fontsize";
+char[] TEXT_italics = "italics";
+char[] TEXT_link = "link";
+char[] TEXT_small = "small";
+char[] TEXT_strike = "strike";
+char[] TEXT_sub = "sub";
+char[] TEXT_sup = "sup";
+
+char[] TEXT_Enumerator = "Enumerator";
+char[] TEXT_item = "item";
+char[] TEXT_atEnd = "atEnd";
+char[] TEXT_moveNext = "moveNext";
+char[] TEXT_moveFirst = "moveFirst";
+
+char[] TEXT_VBArray = "VBArray";
+char[] TEXT_dimensions = "dimensions";
+char[] TEXT_getItem = "getItem";
+char[] TEXT_lbound = "lbound";
+char[] TEXT_toArray = "toArray";
+char[] TEXT_ubound = "ubound";
+
+char[] TEXT_ScriptEngine = "ScriptEngine";
+char[] TEXT_ScriptEngineBuildVersion = "ScriptEngineBuildVersion";
+char[] TEXT_ScriptEngineMajorVersion = "ScriptEngineMajorVersion";
+char[] TEXT_ScriptEngineMinorVersion = "ScriptEngineMinorVersion";
+char[] TEXT_DMDScript =  "DMDScript";
+
+char[] TEXT_date = "date";
+char[] TEXT_unknown = "unknown";
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/dmdscript_tango/textgen/textgen.d	Sun Jan 24 12:34:47 2010 +0200
@@ -0,0 +1,181 @@
+
+/* 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.
+ */
+
+// Program to generate string files in script data structures.
+// Saves much tedious typing, and eliminates typo problems.
+// Generates:
+//	text.d
+
+import std.c.stdio;
+import std.c.stdlib;
+import std.stdio;
+
+
+struct Msgtable
+{
+	char[] name;
+	int value;
+	char[] ident;
+}
+
+
+Msgtable errtable[] =
+[
+    { "DMDScript fatal runtime error: ",                         0, "ERR_RUNTIME_PREFIX" },
+    { "No default value for COM object",                         0, "ERR_COM_NO_DEFAULT_VALUE" },
+    { "%s does not have a [[Construct]] property",               0, "ERR_COM_NO_CONSTRUCT_PROPERTY" },
+    { "argument type mismatch for %s",			         0, "ERR_DISP_E_TYPEMISMATCH" },
+    { "wrong number of arguments for %s",		         0, "ERR_DISP_E_BADPARAMCOUNT" },
+    { "%s Invoke() fails with COM error %x",                     0, "ERR_COM_FUNCTION_ERROR" },
+    { "Dcomobject: %s.%s fails with COM error %x",               0, "ERR_COM_OBJECT_ERROR" },
+    { "unrecognized switch '%s'",                                0, "ERR_BAD_SWITCH" },
+    { "undefined label '%s' in function '%s'",                   0, "ERR_UNDEFINED_LABEL" },
+    { "unterminated /* */ comment",                              0, "ERR_BAD_C_COMMENT" },
+    { "<!-- comment does not end in newline",                    0, "ERR_BAD_HTML_COMMENT" },
+    { "unsupported char '%s'",                                   0, "ERR_BAD_CHAR_C" },
+    { "unsupported char 0x%02x",                                 0, "ERR_BAD_CHAR_X" },
+    { "escape hex sequence requires 2 hex digits",               0, "ERR_BAD_HEX_SEQUENCE" },
+    { "undefined escape sequence \\\\%c",                        0, "ERR_UNDEFINED_ESC_SEQUENCE" },
+    { "string is missing an end quote %s",                       0, "ERR_STRING_NO_END_QUOTE" },
+    { "end of file before end of string",                        0, "ERR_UNTERMINATED_STRING" },
+    { "\\\\u sequence must be followed by 4 hex characters",     0, "ERR_BAD_U_SEQUENCE" },
+    { "unrecognized numeric literal",                            0, "ERR_UNRECOGNIZED_N_LITERAL" },
+    { "Identifier expected in FormalParameterList, not %s",      0, "ERR_FPL_EXPECTED_IDENTIFIER" },
+    { "comma expected in FormalParameterList, not %s",           0, "ERR_FPL_EXPECTED_COMMA" },
+    { "identifier expected",                                     0, "ERR_EXPECTED_IDENTIFIER" },
+    { "found '%s' when expecting '%s'",                          0, "ERR_EXPECTED_GENERIC" },
+    { "identifier expected instead of '%s'",                     0, "ERR_EXPECTED_IDENTIFIER_PARAM" },
+    { "identifier expected following '%s', not '%s'",            0, "ERR_EXPECTED_IDENTIFIER_2PARAM" },
+    { "EOF found before closing ']' of block statement",         0, "ERR_UNTERMINATED_BLOCK" },
+    { "only one variable can be declared for 'in', not %d",      0, "ERR_TOO_MANY_IN_VARS" },
+    { "';' or 'in' expected, not '%s'",                          0, "ERR_IN_EXPECTED" },
+    { "label expected after goto, not '%s'",                     0, "ERR_GOTO_LABEL_EXPECTED" },
+    { "catch or finally expected following try",                 0, "ERR_TRY_CATCH_EXPECTED" },
+    { "found '%s' instead of statement",                         0, "ERR_STATEMENT_EXPECTED" },
+    { "expression expected, not '%s'",                           0, "ERR_EXPECTED_EXPRESSION" },
+    { "Object literal in initializer",                           0, "ERR_OBJ_LITERAL_IN_INITIALIZER" },
+    { "label '%s' is already defined",                           0, "ERR_LABEL_ALREADY_DEFINED" },
+    { "redundant case %s",                                       0, "ERR_SWITCH_REDUNDANT_CASE" },
+    { "case %s: is not in a switch statement",                   0, "ERR_MISPLACED_SWITCH_CASE" },
+    { "redundant default in switch statement",                   0, "ERR_SWITCH_REDUNDANT_DEFAULT" },
+    { "default is not in a switch statement",                    0, "ERR_MISPLACED_SWITCH_DEFAULT" },
+    { "init statement must be expression or var",                0, "ERR_INIT_NOT_EXPRESSION" },
+    { "can only break from within loop or switch",               0, "ERR_MISPLACED_BREAK" },
+    { "continue is not in a loop",                               0, "ERR_MISPLACED_CONTINUE" },
+    { "Statement label '%s' is undefined",                       0, "ERR_UNDEFINED_STATEMENT_LABEL" },
+    { "cannot goto into with statement",                         0, "ERR_GOTO_INTO_WITH" },
+    { "can only return from within function",                    0, "ERR_MISPLACED_RETURN" },
+    { "no expression for throw",                                 0, "ERR_NO_THROW_EXPRESSION" },
+    { "%s.%s is undefined",                                      0, "ERR_UNDEFINED_OBJECT_SYMBOL" },
+    { "Number.prototype.%s() expects a Number not a %s",         0, "ERR_FUNCTION_WANTS_NUMBER" },
+    { "String.prototype.%s() expects a String not a %s",         0, "ERR_FUNCTION_WANTS_STRING" },
+    { "Date.prototype.%s() expects a Date not a %s",             0, "ERR_FUNCTION_WANTS_DATE" },
+    { "%s %s is undefined and has no Call method",               0, "ERR_UNDEFINED_NO_CALL2"},
+    { "%s %s.%s is undefined and has no Call method",            0, "ERR_UNDEFINED_NO_CALL3"},
+    { "Boolean.prototype.%s() expects a Boolean not a %s",       0, "ERR_FUNCTION_WANTS_BOOL" },
+    { "arg to Array(len) must be 0 .. 2**32-1, not %.16g",       0, "ERR_ARRAY_LEN_OUT_OF_BOUNDS" },
+    { "Number.prototype.%s() %s out of range",                   0, "ERR_VALUE_OUT_OF_RANGE" },
+    { "TypeError in %s",                                         0, "ERR_TYPE_ERROR" },
+    { "Error compiling regular expression",                      0, "ERR_REGEXP_COMPILE" },
+    { "%s not transferrable",                                    0, "ERR_NOT_TRANSFERRABLE" },
+    { "%s %s cannot convert to Object",                          0, "ERR_CANNOT_CONVERT_TO_OBJECT2" },
+    { "%s %s.%s cannot convert to Object",                       0, "ERR_CANNOT_CONVERT_TO_OBJECT3" },
+    { "cannot convert %s to Object",                             0, "ERR_CANNOT_CONVERT_TO_OBJECT4" },
+    { "cannot assign to %s",                                     0, "ERR_CANNOT_ASSIGN_TO" },
+    { "cannot assign %s to %s",                                  0, "ERR_CANNOT_ASSIGN" },
+    { "cannot assign to %s.%s",                                  0, "ERR_CANNOT_ASSIGN_TO2" },
+    { "cannot assign to function",				 0, "ERR_FUNCTION_NOT_LVALUE"},
+    { "RHS of %s must be an Object, not a %s",                   0, "ERR_RHS_MUST_BE_OBJECT" },
+    { "can't Put('%s', %s) to a primitive %s",                   0, "ERR_CANNOT_PUT_TO_PRIMITIVE" },
+    { "can't Put(%u, %s) to a primitive %s",                     0, "ERR_CANNOT_PUT_INDEX_TO_PRIMITIVE" },
+    { "object cannot be converted to a primitive type",          0, "ERR_OBJECT_CANNOT_BE_PRIMITIVE" },
+    { "can't Get(%s) from primitive %s(%s)",                     0, "ERR_CANNOT_GET_FROM_PRIMITIVE" },
+    { "can't Get(%d) from primitive %s(%s)",                     0, "ERR_CANNOT_GET_INDEX_FROM_PRIMITIVE" },
+    { "primitive %s has no Construct method",                    0, "ERR_PRIMITIVE_NO_CONSTRUCT" },
+    { "primitive %s has no Call method",                         0, "ERR_PRIMITIVE_NO_CALL" },
+    { "for-in must be on an object, not a primitive",            0, "ERR_FOR_IN_MUST_BE_OBJECT" },
+    { "assert() line %d",					 0, "ERR_ASSERT"},
+    { "object does not have a [[Call]] property",		 0, "ERR_OBJECT_NO_CALL"},
+    { "%s: %s",							 0, "ERR_S_S"},
+    { "no Default Put for object",				 0, "ERR_NO_DEFAULT_PUT"},
+    { "%s does not have a [[Construct]] property",		 0, "ERR_S_NO_CONSTRUCT"},
+    { "%s does not have a [[Call]] property",			 0, "ERR_S_NO_CALL"},
+    { "%s does not have a [[HasInstance]] property",		 0, "ERR_S_NO_INSTANCE"},
+    { "length property must be an integer",			 0, "ERR_LENGTH_INT"},
+    { "Array.prototype.toLocaleString() not transferrable",	 0, "ERR_TLS_NOT_TRANSFERRABLE"},
+    { "Function.prototype.toString() not transferrable",	 0, "ERR_TS_NOT_TRANSFERRABLE"},
+    { "Function.prototype.apply(): argArray must be array or arguments object", 0, "ERR_ARRAY_ARGS"},
+    { ".prototype must be an Object, not a %s",			 0, "ERR_MUST_BE_OBJECT"},
+    { "VBArray expected, not a %s",				 0, "ERR_VBARRAY_EXPECTED"},
+    { "VBArray subscript out of range",				 0, "ERR_VBARRAY_SUBSCRIPT"},
+    { "Type mismatch",						 0, "ERR_ACTIVEX"},
+    { "no property %s",						 0, "ERR_NO_PROPERTY"},
+    { "Put of %s failed",					 0, "ERR_PUT_FAILED"},
+    { "Get of %s failed",					 0, "ERR_GET_FAILED"},
+    { "argument not a collection",				 0, "ERR_NOT_COLLECTION"},
+    { "%s.%s expects a valid UTF codepoint not \\\\u%x",	 0, "ERR_NOT_VALID_UTF"},
+
+// COM error messages
+    { "Unexpected",						 0, "ERR_E_UNEXPECTED"},
+];
+
+int main()
+{
+    FILE* fp;
+    uint i;
+
+    fp = fopen("errmsgs.d","w");
+    if (!fp)
+    {
+	printf("can't open errmsgs.d\n");
+	exit(EXIT_FAILURE);
+    }
+
+    fprintf(fp, "// File generated by textgen.d\n");
+    fprintf(fp, "//\n");
+
+    fprintf(fp, "// *** ERROR MESSAGES ***\n");
+    fprintf(fp, "//\n");
+    fprintf(fp, "module dmdscript.errmsgs;\n");
+    fprintf(fp, "enum {\n");
+    for (i = 0; i < errtable.length; i++)
+    {	char[] id = errtable[i].ident;
+
+	if (!id)
+	    id = errtable[i].name;
+	fwritefln(fp,"\t%s = %d,", id, i);
+    }
+    fprintf(fp, "};\n");
+
+    fprintf(fp, "// *** ERROR MESSAGES ***\n");
+    fprintf(fp, "//\n");
+    fprintf(fp, "char[][] errmsgtbl = [\n");
+    for (i = 0; i < errtable.length; i++)
+    {	char[] id = errtable[i].ident;
+	char[] p = errtable[i].name;
+
+	fwritefln(fp,"\t\"%s\",", p);
+    }
+    fprintf(fp, "];\n");
+
+    fclose(fp);
+
+    return EXIT_SUCCESS;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/dmdscript_tango/threadcontext.d	Sun Jan 24 12:34:47 2010 +0200
@@ -0,0 +1,132 @@
+
+/* 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.threadcontext;
+
+import std.thread;
+
+alias std.thread.Thread Thread;
+
+import dmdscript.script;
+import dmdscript.program;
+import dmdscript.dmath;
+import dmdscript.dobject;
+import dmdscript.dfunction;
+
+// These are our per-thread global variables
+
+struct ThreadContext
+{
+    Thread threadid;	// identifier of current thread
+
+    // Tables where the prototype and constructor object are stored.
+    Dobject[d_string] protoTable;
+    Dfunction[d_string] ctorTable;
+
+    // Table where object initializers go
+    static void function(ThreadContext*)[] initTable;
+
+    // Values from here to the end of the struct are 0'd by dobject_term()
+    Program program;	// associated data
+
+    Dfunction Dobject_constructor;
+    Dobject Dobject_prototype;
+
+    Dfunction Dfunction_constructor;
+    Dobject Dfunction_prototype;
+
+    Dfunction Darray_constructor;
+    Dobject Darray_prototype;
+
+    Dfunction Dstring_constructor;
+    Dobject Dstring_prototype;
+
+    Dfunction Dboolean_constructor;
+    Dobject Dboolean_prototype;
+
+    Dfunction Dnumber_constructor;
+    Dobject Dnumber_prototype;
+
+    Dfunction Derror_constructor;
+    Dobject Derror_prototype;
+
+    Dfunction Ddate_constructor;
+    Dobject Ddate_prototype;
+
+    Dfunction Dregexp_constructor;
+    Dobject Dregexp_prototype;
+
+    Dfunction Denumerator_constructor;
+    Dobject Denumerator_prototype;
+
+    Dmath Dmath_object;
+
+    /***********************************************
+     * Get ThreadContext associated with this thread.
+     */
+
+    static ThreadContext[Thread] threadtable;
+
+    static Thread cache_ti;
+    static ThreadContext* cache_cc;
+
+    static ThreadContext* getThreadContext()
+    {
+	/* This works by creating an array of ThreadContext's, one
+	 * for each thread. We match up by thread id.
+	 */
+
+	Thread ti;
+	ThreadContext *cc;
+
+	//writef("ThreadContext.getThreadContext()\n");
+
+	ti = Thread.getThis();
+
+	synchronized
+	{
+	    // Used cached version if we can
+	    if (ti == cache_ti)
+	    {
+		cc = cache_cc;
+		//exception(L"getThreadContext(): cache x%x", ti);
+	    }
+	    else
+	    {
+		cc = ti in threadtable;
+		if (!cc)
+		{
+		    threadtable[ti] = ThreadContext.init;
+		    cc = &threadtable[ti];
+		}
+
+		cc.threadid = ti;
+
+		// Cache for next time
+		cache_ti = ti;
+		cache_cc = cc;
+	    }
+	}
+	return cc;
+    }
+}
+
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/dmdscript_tango/value.d	Sun Jan 24 12:34:47 2010 +0200
@@ -0,0 +1,1094 @@
+
+/* 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.value;
+
+import std.math;
+import std.date;
+import std.string;
+import std.stdio;
+import std.c.string;
+
+import dmdscript.script;
+import dmdscript.dobject;
+import dmdscript.iterator;
+import dmdscript.identifier;
+import dmdscript.errmsgs;
+import dmdscript.text;
+import dmdscript.program;
+import dmdscript.dstring;
+import dmdscript.dnumber;
+import dmdscript.dboolean;
+
+// Porting issues:
+// A lot of scaling is done on arrays of Value's. Therefore, adjusting
+// it to come out to a size of 16 bytes makes the scaling an efficient
+// operation. In fact, in some cases (opcodes.c) we prescale the addressing
+// by 16 bytes at compile time instead of runtime.
+// So, Value must be looked at in any port to verify that:
+// 1) the size comes out as 16 bytes, padding as necessary
+// 2) Value::copy() copies the used data bytes, NOT the padding.
+//    It's faster to not copy the padding, and the
+//    padding can contain garbage stack pointers which can
+//    prevent memory from being garbage collected.
+
+version (DigitalMars)
+    version (D_InlineAsm)
+	version = UseAsm;
+
+enum
+{
+    V_NONE      = 0,
+    V_UNDEFINED = 1,
+    V_NULL      = 2,
+    V_BOOLEAN   = 3,
+    V_NUMBER    = 4,
+    V_STRING    = 5,
+    V_OBJECT    = 6,
+    V_ITER      = 7,
+}
+
+struct Value
+{
+    ubyte vtype = V_UNDEFINED;
+
+    uint hash;			// cache 'hash' value
+
+    union
+    {
+	d_boolean dbool;	// can be true or false
+	d_number number;
+	tchar[] string;
+	Dobject object;
+	d_int32  int32;
+	d_uint32 uint32;
+	d_uint16 uint16;
+
+	Iterator* iter;		// V_ITER
+    }
+
+    void putVundefined()
+    {
+	vtype = V_UNDEFINED;
+	hash = 0;
+	string = null;
+    }
+
+    void putVnull()
+    {	vtype = V_NULL;
+    }
+
+    void putVboolean(d_boolean b)
+	in
+	{   assert(b == 1 || b == 0);
+	}
+	body
+	{   vtype = V_BOOLEAN;
+	    dbool = b;
+	}
+
+    void putVnumber(d_number n)
+    {	vtype = V_NUMBER;
+	number = n;
+    }
+
+    void putVtime(d_time n)
+    {	vtype = V_NUMBER;
+	number = (n == d_time_nan) ? d_number.nan : n;
+    }
+
+    void putVstring(d_string s)
+    {	vtype = V_STRING;
+	hash = 0;
+	string = s;
+    }
+
+    void putVstring(d_string s, uint hash)
+    {	vtype = V_STRING;
+	this.hash = hash;
+	this.string = s;
+    }
+
+    void putVobject(Dobject o)
+    {	vtype = V_OBJECT;
+	object = o;
+    }
+
+    void putViterator(Iterator* i)
+    {	vtype = V_ITER;
+	iter = i;
+    }
+
+    invariant
+    {
+/+
+	switch (vtype)
+	{
+	    case V_UNDEFINED:
+	    case V_NULL:
+		break;
+	    case V_BOOLEAN:
+		assert(dbool == 1 || dbool == 0);
+		break;
+	    case V_NUMBER:
+	    case V_STRING:
+	    case V_OBJECT:
+	    case V_ITER:
+		break;
+	    case V_NONE:
+		break;
+	    default:
+		writefln("vtype = %d", vtype);
+		assert(0);
+		break;
+	}
++/
+    }
+
+    static void copy(Value* to, Value* from)
+/+    in { }
+    out { assert(memcmp(to, from, Value.sizeof) == 0); }
+    body
++/
+    {
+	version (all /*UseAsm*/)
+	{
+	    asm
+	    {	naked			;
+		push	ESI		;
+		mov	ECX,[EAX]	;
+		mov	ESI,8[ESP]	;
+		mov	[ESI],ECX	;
+		mov	EDX,4[EAX]	;
+		mov	ECX,8[EAX]	;
+		mov	EAX,12[EAX]	;
+		mov	4[ESI],EDX	;
+		mov	8[ESI],ECX	;
+		mov	12[ESI],EAX	;
+		pop	ESI		;
+		ret	4		;
+	     }
+	}
+	else
+	{
+	    *to = *from;
+	    //(cast(uint *)to)[0] = (cast(uint *)from)[0];
+	    //(cast(uint *)to)[1] = (cast(uint *)from)[1];
+	    //(cast(uint *)to)[2] = (cast(uint *)from)[2];
+	    //(cast(uint *)to)[3] = (cast(uint *)from)[3];
+	}
+    }
+
+    void* toPrimitive(Value* v, tchar[] PreferredType)
+    {
+	if (vtype == V_OBJECT)
+	{
+	    /*	ECMA 9.1
+		Return a default value for the Object.
+		The default value of an object is retrieved by
+		calling the internal [[DefaultValue]] method
+		of the object, passing the optional hint
+		PreferredType. The behavior of the [[DefaultValue]]
+		method is defined by this specification for all
+		native ECMAScript objects (see section 8.6.2.6).
+		If the return value is of type Object or Reference,
+		a runtime error is generated.
+	     */
+	    void* a;
+
+	    assert(object);
+	    a = object.DefaultValue(v, PreferredType);
+	    if (a)
+		return a;
+	    if (!v.isPrimitive())
+	    {
+		ErrInfo errinfo;
+
+		v.putVundefined();
+		return Dobject.RuntimeError(&errinfo,
+			errmsgtbl[ERR_OBJECT_CANNOT_BE_PRIMITIVE]);
+	    }
+	}
+	else
+	{
+	    copy(v, this);
+	}
+	return null;
+    }
+
+
+    d_boolean toBoolean()
+    {
+	switch (vtype)
+	{
+	    case V_UNDEFINED:
+	    case V_NULL:
+		return false;
+	    case V_BOOLEAN:
+		return dbool;
+	    case V_NUMBER:
+		return !(number == 0.0 || isnan(number));
+	    case V_STRING:
+		return string.length ? true : false;
+	    case V_OBJECT:
+		return true;
+	    default:
+		assert(0);
+	}
+	assert(0);
+    }
+
+
+    d_number toNumber()
+    {
+	switch (vtype)
+	{
+	    case V_UNDEFINED:
+		return d_number.nan;
+	    case V_NULL:
+		return 0;
+	    case V_BOOLEAN:
+		return dbool ? 1 : 0;
+	    case V_NUMBER:
+		return number;
+	    case V_STRING:
+	    {
+		d_number n;
+		size_t len;
+		size_t endidx;
+
+		len = string.length;
+		n = StringNumericLiteral(string, endidx, 0);
+
+		// Consume trailing whitespace
+		//writefln("n = %s, string = '%s', endidx = %s, length = %s", n, string, endidx, string.length);
+		foreach (dchar c; string[endidx .. length])
+		{   if (!isStrWhiteSpaceChar(c))
+		    {	n = d_number.nan;
+			break;
+		    }
+		}
+
+		return n;
+	    }
+	    case V_OBJECT:
+	    {   Value val;
+		Value* v;
+
+		//writefln("Vobject.toNumber()");
+		v = &val;
+		toPrimitive(v, TypeNumber);
+		if (v.isPrimitive())
+		    return v.toNumber();
+		else
+		    return d_number.nan;
+	    }
+	    default:
+		assert(0);
+	}
+	assert(0);
+    }
+
+
+    d_time toDtime()
+    {
+	return cast(d_time)toNumber();
+    }
+
+
+    d_number toInteger()
+    {
+	switch (vtype)
+	{
+	    case V_UNDEFINED:
+		return d_number.nan;
+	    case V_NULL:
+		return 0;
+	    case V_BOOLEAN:
+		return dbool ? 1 : 0;
+
+	    default:
+	    {   d_number number;
+
+		number = toNumber();
+		if (isnan(number))
+		    number = 0;
+		else if (number == 0 || std.math.isinf(number))
+		    { }
+		else if (number > 0)
+		    number = std.math.floor(number);
+		else
+		    number = -std.math.floor(-number);
+		return number;
+	    }
+	}
+	assert(0);
+    }
+
+
+    d_int32 toInt32()
+    {
+	switch (vtype)
+	{
+	    case V_UNDEFINED:
+	    case V_NULL:
+		return 0;
+	    case V_BOOLEAN:
+		return dbool ? 1 : 0;
+
+	    default:
+	    {   d_int32 int32;
+		d_number number;
+		long ll;
+
+		number = toNumber();
+		if (isnan(number))
+		    int32 = 0;
+		else if (number == 0 || std.math.isinf(number))
+		    int32 = 0;
+		else
+		{   if (number > 0)
+			number = std.math.floor(number);
+		    else
+			number = -std.math.floor(-number);
+
+		    ll = cast(long) number;
+		    int32 = cast(int) ll;
+		}
+		return int32;
+	    }
+	}
+	assert(0);
+    }
+
+
+    d_uint32 toUint32()
+    {
+	switch (vtype)
+	{
+	    case V_UNDEFINED:
+	    case V_NULL:
+		return 0;
+	    case V_BOOLEAN:
+		return dbool ? 1 : 0;
+
+	    default:
+	    {   d_uint32 uint32;
+		d_number number;
+		long ll;
+
+		number = toNumber();
+		if (isnan(number))
+		    uint32 = 0;
+		else if (number == 0 || std.math.isinf(number))
+		    uint32 = 0;
+		else
+		{   if (number > 0)
+			number = std.math.floor(number);
+		    else
+			number = -std.math.floor(-number);
+
+		    ll = cast(long) number;
+		    uint32 = cast(uint) ll;
+		}
+		return uint32;
+	    }
+	}
+	assert(0);
+    }
+
+    d_uint16 toUint16()
+    {
+	switch (vtype)
+	{
+	    case V_UNDEFINED:
+	    case V_NULL:
+		return 0;
+	    case V_BOOLEAN:
+		return cast(d_uint16) (dbool ? 1 : 0);
+
+	    default:
+	    {   d_uint16 uint16;
+		d_number number;
+
+		number = toNumber();
+		if (isnan(number))
+		    uint16 = 0;
+		else if (number == 0 || std.math.isinf(number))
+		    uint16 = 0;
+		else
+		{   if (number > 0)
+			number = std.math.floor(number);
+		    else
+			number = -std.math.floor(-number);
+
+		    uint16 = cast(ushort)number;
+		}
+		return uint16;
+	    }
+	}
+	assert(0);
+    }
+
+    d_string toString()
+    {
+	switch (vtype)
+	{
+	    case V_UNDEFINED:
+		return TEXT_undefined;
+	    case V_NULL:
+		return TEXT_null;
+	    case V_BOOLEAN:
+		return dbool ? TEXT_true : TEXT_false;
+	    case V_NUMBER:
+		{   d_string string;
+		    static d_string* strings[10] =
+		    [   &TEXT_0,&TEXT_1,&TEXT_2,&TEXT_3,&TEXT_4,
+			&TEXT_5,&TEXT_6,&TEXT_7,&TEXT_8,&TEXT_9 ];
+
+		    //writefln("Vnumber.toString(%g)", number);
+		    if (isnan(number))
+			string = TEXT_NaN;
+		    else if (number >= 0 && number <= 9 && number == cast(int) number)
+			string = *strings[cast(int) number];
+		    else if (std.math.isinf(number))
+		    {
+			if (number < 0)
+			    string = TEXT_negInfinity;
+			else
+			    string = TEXT_Infinity;
+		    }
+		    else
+		    {
+			tchar[100] buffer;	// should shrink this to max size,
+						// but doesn't really matter
+			tchar* p;
+
+			// ECMA 262 requires %.21g (21 digits) of precision. But, the
+			// C runtime library doesn't handle that. Until the C runtime
+			// library is upgraded to ANSI C 99 conformance, use
+			// 16 digits, which is all the GCC library will round correctly.
+
+			std.string.sformat(buffer, "%.16g\0", number);
+			//std.c.stdio.sprintf(buffer.ptr, "%.16g", number);
+
+			// Trim leading spaces
+			// Trim leading spaces
+			for (p = buffer.ptr; *p == ' '; p++) { }
+
+			{   // Trim any 0's following exponent 'e'
+			    tchar* q;
+			    tchar* t;
+
+			    for (q = p; *q; q++)
+			    {
+				if (*q == 'e')
+				{
+				    q++;
+				    if (*q == '+' || *q == '-')
+					q++;
+				    t = q;
+				    while (*q == '0')
+					q++;
+				    if (t != q)
+				    {
+					for (;;)
+					{
+					    *t = *q;
+					    if (*t == 0)
+						break;
+					    t++;
+					    q++;
+					}
+				    }
+				    break;
+				}
+			    }
+			}
+			string = p[0 .. std.c.string.strlen(p)].dup;
+		    }
+		    //writefln("string = '%s'", string);
+		    return string;
+		}
+	    case V_STRING:
+		return string;
+	    case V_OBJECT:
+	    {   Value val;
+		Value* v = &val;
+		void* a;
+
+		//writef("Vobject.toString()\n");
+		a = toPrimitive(v, TypeString);
+		//assert(!a);
+		if (v.isPrimitive())
+		    return v.toString();
+		else
+		    return v.toObject().classname;
+	    }
+	    default:
+		assert(0);
+	}
+	assert(0);
+    }
+
+    d_string toLocaleString()
+    {
+	return toString();
+    }
+
+    d_string toString(int radix)
+    {
+	if (vtype == V_NUMBER)
+	{
+	    assert(2 <= radix && radix <= 36);
+	    return std.string.toString(cast(long)number, cast(uint)radix);
+	}
+	else
+	{
+	    return toString();
+	}
+    }
+
+    d_string toSource()
+    {
+	switch (vtype)
+	{
+	    case V_STRING:
+	    {	d_string s;
+
+		s = "\"" ~ string ~ "\"";
+		return s;
+	    }
+	    case V_OBJECT:
+	    {   Value* v;
+
+		//writefln("Vobject.toSource()");
+		v = Get(TEXT_toSource);
+		if (!v)
+		    v = &vundefined;
+		if (v.isPrimitive())
+		    return v.toSource();
+		else	// it's an Object
+		{   void* a;
+		    CallContext *cc;
+		    Dobject o;
+		    Value* ret;
+		    Value val;
+
+		    o = v.object;
+		    cc = Program.getProgram().callcontext;
+		    ret = &val;
+		    a = o.Call(cc, this.object, ret, null);
+		    if (a)			// if exception was thrown
+		    {
+			/*return a*/;
+			writef("Vobject.toSource() failed with %x\n", a);
+		    }
+		    else if (ret.isPrimitive())
+			return ret.toString();
+		}
+		return TEXT_undefined;
+	    }
+	    default:
+		return toString();
+	}
+	assert(0);
+    }
+
+    Dobject toObject()
+    {
+	switch (vtype)
+	{
+	    case V_UNDEFINED:
+		//RuntimeErrorx("cannot convert undefined to Object");
+		return null;
+	    case V_NULL:
+		//RuntimeErrorx("cannot convert null to Object");
+		return null;
+	    case V_BOOLEAN:
+		return new Dboolean(dbool);
+	    case V_NUMBER:
+		return new Dnumber(number);
+	    case V_STRING:
+		return new Dstring(string);
+	    case V_OBJECT:
+		return object;
+	    default:
+		assert(0);
+	}
+	assert(0);
+    }
+
+    int opEquals(Value* v)
+    {
+	return (opCmp(v) == 0);
+    }
+
+    /*********************************
+     * Use this instead of std.string.cmp() because
+     * we don't care about lexicographic ordering.
+     * This is faster.
+     */
+
+    static int stringcmp(d_string s1, d_string s2)
+    {
+	int c = s1.length - s2.length;
+	if (c == 0)
+	{
+	    if (s1.ptr == s2.ptr)
+		return 0;
+	    c = memcmp(s1.ptr, s2.ptr, s1.length);
+	}
+	return c;
+    }
+
+    int opCmp(Value* v)
+    {
+	switch (vtype)
+	{
+	    case V_UNDEFINED:
+		if (vtype == v.vtype)
+		    return 0;
+		break;
+	    case V_NULL:
+		if (vtype == v.vtype)
+		    return 0;
+		break;
+	    case V_BOOLEAN:
+		if (vtype == v.vtype)
+		    return v.dbool - dbool;
+		break;
+	    case V_NUMBER:
+		if (v.vtype == V_NUMBER)
+		{
+		    if (number == v.number)
+			return 0;
+		    if (isnan(number) && isnan(v.number))
+			return 0;
+		    if (number > v.number)
+			return 1;
+		}
+		else if (v.vtype == V_STRING)
+		{
+		    return stringcmp(toString(), v.string);
+		}
+		break;
+	    case V_STRING:
+		if (v.vtype == V_STRING)
+		{
+		    //writefln("'%s'.compareTo('%s')", string, v.string);
+		    int len = string.length - v.string.length;
+		    if (len == 0)
+		    {
+			if (string.ptr == v.string.ptr)
+			    return 0;
+			len = memcmp(string.ptr, v.string.ptr, string.length);
+		    }
+		    return len;
+		}
+		else if (v.vtype == V_NUMBER)
+		{
+		    //writefln("'%s'.compareTo(%g)\n", string, v.number);
+		    return stringcmp(string, v.toString());
+		}
+		break;
+	    case V_OBJECT:
+		if (v.object == object)
+		    return 0;
+		break;
+	    default:
+		assert(0);
+	}
+	return -1;
+    }
+
+    void copyTo(Value* v)
+    {	// Copy everything, including vptr
+	copy(this, v);
+    }
+
+    tchar[] getType()
+    {	tchar[] s;
+
+	switch (vtype)
+	{
+	    case V_UNDEFINED:	s = TypeUndefined; break;
+	    case V_NULL:	s = TypeNull;      break;
+	    case V_BOOLEAN:	s = TypeBoolean;   break;
+	    case V_NUMBER:	s = TypeNumber;    break;
+	    case V_STRING:	s = TypeString;    break;
+	    case V_OBJECT:	s = TypeObject;    break;
+	    case V_ITER:	s = TypeIterator;  break;
+	    default:
+		writefln("vtype = %d", vtype);
+		assert(0);
+	}
+	return s;
+    }
+
+    d_string getTypeof()
+    {	tchar[] s;
+
+	switch (vtype)
+	{
+	    case V_UNDEFINED:	s = TEXT_undefined;	break;
+	    case V_NULL:	s = TEXT_object;	break;
+	    case V_BOOLEAN:	s = TEXT_boolean;	break;
+	    case V_NUMBER:	s = TEXT_number;	break;
+	    case V_STRING:	s = TEXT_string;	break;
+	    case V_OBJECT:	s = object.getTypeof();	break;
+	    default:
+		writefln("vtype = %d", vtype);
+		assert(0);
+	}
+	return s;
+    }
+
+    int isUndefined() { return vtype == V_UNDEFINED; }
+    int isNull()      { return vtype == V_NULL;      }
+    int isBoolean()   { return vtype == V_BOOLEAN;   }
+    int isNumber()    { return vtype == V_NUMBER;    }
+    int isString()    { return vtype == V_STRING;    }
+    int isObject()    { return vtype == V_OBJECT;    }
+    int isIterator()  { return vtype == V_ITER;      }
+
+    int isUndefinedOrNull() { return vtype == V_UNDEFINED || vtype == V_NULL; }
+
+    int isPrimitive() { return vtype != V_OBJECT; }
+
+    int isArrayIndex(out d_uint32 index)
+    {
+	switch (vtype)
+	{
+	    case V_NUMBER:
+		index = toUint32();
+		return true;
+	    case V_STRING:
+		return StringToIndex(string, index);
+	    default:
+		index = 0;
+		return false;
+	}
+	assert(0);
+    }
+
+    static uint calcHash(uint u)
+    {
+	return u ^ 0x55555555;
+    }
+
+    static uint calcHash(double d)
+    {
+	return calcHash(cast(uint) d);
+    }
+
+    static uint calcHash(d_string s)
+    {
+	uint hash;
+
+	/* If it looks like an array index, hash it to the
+	 * same value as if it was an array index.
+	 * This means that "1234" hashes to the same value as 1234.
+	 */
+	hash = 0;
+	foreach (tchar c; s)
+	{
+	    switch (c)
+	    {
+		case '0':	hash *= 10;		break;
+		case '1':	hash = hash * 10 + 1;	break;
+
+		case '2':
+		case '3':
+		case '4':
+		case '5':
+		case '6':
+		case '7':
+		case '8':
+		case '9':
+		    hash = hash * 10 + (c - '0');
+		    break;
+
+		default:
+		{   uint len = s.length;
+		    ubyte *str = cast(ubyte*)s.ptr;
+
+		    hash = 0;
+		    while (1)
+		    {
+			switch (len)
+			{
+			    case 0:
+				break;
+
+			    case 1:
+				hash *= 9;
+				hash += *cast(ubyte *)str;
+				break;
+
+			    case 2:
+				hash *= 9;
+				hash += *cast(ushort *)str;
+				break;
+
+			    case 3:
+				hash *= 9;
+				hash += (*cast(ushort *)str << 8) +
+					(cast(ubyte *)str)[2];
+				break;
+
+			    default:
+				hash *= 9;
+				hash += *cast(uint *)str;
+				str += 4;
+				len -= 4;
+				continue;
+			}
+			break;
+		    }
+		    break;
+		}
+		// return s.hash;
+	    }
+	}
+	return calcHash(hash);
+    }
+
+    uint toHash()
+    {	uint h;
+
+	switch (vtype)
+	{
+	    case V_UNDEFINED:
+	    case V_NULL:
+		h = 0;
+		break;
+	    case V_BOOLEAN:
+		h = dbool ? 1 : 0;
+		break;
+	    case V_NUMBER:
+		h = calcHash(number);
+		break;
+	    case V_STRING:
+		// Since strings are immutable, if we've already
+		// computed the hash, use previous value
+		if (!hash)
+		    hash = calcHash(string);
+		h = hash;
+		break;
+	    case V_OBJECT:
+		/* Uses the address of the object as the hash.
+		 * Since the object never moves, it will work
+		 * as its hash.
+		 * BUG: shouldn't do this.
+		 */
+		h = cast(uint)cast(void*) object;
+		break;
+	    default:
+		assert(0);
+	}
+	//writefln("\tValue.toHash() = %x", h);
+	return h;
+    }
+
+    Value* Put(d_string PropertyName, Value* value)
+    {
+	if (vtype == V_OBJECT)
+	    return object.Put(PropertyName, value, 0);
+	else	
+	{
+	    ErrInfo errinfo;
+
+	    return Dobject.RuntimeError(&errinfo,
+		    errmsgtbl[ERR_CANNOT_PUT_TO_PRIMITIVE],
+		    PropertyName, value.toString(),
+		    getType());
+	}
+    }
+
+    Value* Put(d_uint32 index, Value* vindex, Value* value)
+    {
+	if (vtype == V_OBJECT)
+	    return object.Put(index, vindex, value, 0);
+	else	
+	{
+	    ErrInfo errinfo;
+
+	    return Dobject.RuntimeError(&errinfo,
+		    errmsgtbl[ERR_CANNOT_PUT_INDEX_TO_PRIMITIVE],
+		    index,
+		    value.toString(), getType());
+	}
+    }
+
+    Value* Get(d_string PropertyName)
+    {
+	if (vtype == V_OBJECT)
+	    return object.Get(PropertyName);
+	else	
+	{
+	    // Should we generate the error, or just return undefined?
+	    tchar[] msg;
+
+	    msg = std.string.format(errmsgtbl[ERR_CANNOT_GET_FROM_PRIMITIVE],
+		PropertyName, getType(), toString());
+	    throw new ScriptException(msg);
+	    //return &vundefined;
+	}
+    }
+
+    Value* Get(d_uint32 index)
+    {
+	if (vtype == V_OBJECT)
+	    return object.Get(index);
+	else	
+	{
+	    // Should we generate the error, or just return undefined?
+	    tchar[] msg;
+
+	    msg = std.string.format(errmsgtbl[ERR_CANNOT_GET_INDEX_FROM_PRIMITIVE],
+		index, getType(), toString());
+	    throw new ScriptException(msg);
+	    //return &vundefined;
+	}
+    }
+
+    Value* Get(Identifier *id)
+    {
+	if (vtype == V_OBJECT)
+	    return object.Get(id);
+	else	
+	{
+	    // Should we generate the error, or just return undefined?
+	    tchar[] msg;
+
+	    msg = std.string.format(errmsgtbl[ERR_CANNOT_GET_FROM_PRIMITIVE],
+		id.toString(), getType(), toString());
+	    throw new ScriptException(msg);
+	    //return &vundefined;
+	}
+    }
+/+
+    Value* Get(d_string PropertyName, uint hash)
+    {
+	if (vtype == V_OBJECT)
+	    return object.Get(PropertyName, hash);
+	else	
+	{
+	    // Should we generate the error, or just return undefined?
+	    tchar[] msg;
+
+	    msg = std.string.format(errmsgtbl[ERR_CANNOT_GET_FROM_PRIMITIVE],
+		PropertyName, getType(), toString());
+	    throw new ScriptException(msg);
+	    //return &vundefined;
+	}
+    }
++/
+    void* Construct(CallContext *cc, Value *ret, Value[] arglist)
+    {
+	if (vtype == V_OBJECT)
+	    return object.Construct(cc, ret, arglist);
+	else	
+	{
+	    ErrInfo errinfo;
+	    ret.putVundefined();
+	    return Dobject.RuntimeError(&errinfo,
+		errmsgtbl[ERR_PRIMITIVE_NO_CONSTRUCT], getType());
+	}
+    }
+
+    void* Call(CallContext *cc, Dobject othis, Value* ret, Value[] arglist)
+    {
+	if (vtype == V_OBJECT)
+	{
+	    void* a;
+
+	    a = object.Call(cc, othis, ret, arglist);
+	    //if (a) writef("Vobject.Call() returned %x\n", a);
+	    return a;
+	}
+	else	
+	{
+	    ErrInfo errinfo;
+	    //PRINTF("Call method not implemented for primitive %p (%s)\n", this, d_string_ptr(toString()));
+	    ret.putVundefined();
+	    return Dobject.RuntimeError(&errinfo,
+		errmsgtbl[ERR_PRIMITIVE_NO_CALL], getType());
+	}
+    }
+
+    Value* putIterator(Value* v)
+    {
+	if (vtype == V_OBJECT)
+	    return object.putIterator(v);
+	else	
+	{
+	    ErrInfo errinfo;
+	    v.putVundefined();
+	    return Dobject.RuntimeError(&errinfo,
+		errmsgtbl[ERR_FOR_IN_MUST_BE_OBJECT]);
+	}
+    }
+
+
+    void getErrInfo(ErrInfo *perrinfo, int linnum)
+    {
+	if (vtype == V_OBJECT)
+	    object.getErrInfo(perrinfo, linnum);
+	else	
+	{
+	    ErrInfo errinfo;
+
+	    if (linnum && errinfo.linnum == 0)
+		errinfo.linnum = linnum;
+	    errinfo.message = "Unhandled exception: " ~ toString();
+	    if (perrinfo)
+		*perrinfo = errinfo;
+	}
+    }
+
+    void dump()
+    {   uint *v = cast(uint *)this;
+
+	writef("v[%x] = %8x, %8x, %8x, %8x\n", cast(uint)v, v[0], v[1], v[2], v[3]);
+    }
+}
+
+static assert(Value.sizeof == 16);
+
+Value vundefined = { V_UNDEFINED };
+Value vnull = { V_NULL };
+
+tchar[] TypeUndefined = "Undefined";
+tchar[] TypeNull      = "Null";
+tchar[] TypeBoolean   = "Boolean";
+tchar[] TypeNumber    = "Number";
+tchar[] TypeString    = "String";
+tchar[] TypeObject    = "Object";
+
+tchar[] TypeIterator  = "Iterator";
+
+
+
+
+
+
+