# HG changeset patch
# User saaadel
# Date 1264329287 -7200
# Node ID 55c2951c07be8daae7e30c4ee3aaf39be6d0a0ef
initial, files origin, premoved tree
diff -r 000000000000 -r 55c2951c07be .classpath
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/.classpath Sun Jan 24 12:34:47 2010 +0200
@@ -0,0 +1,6 @@
+
+
+
+
+
+
diff -r 000000000000 -r 55c2951c07be .project
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/.project Sun Jan 24 12:34:47 2010 +0200
@@ -0,0 +1,17 @@
+
+
+ DMDScript-tango
+
+
+
+
+
+ descent.core.dbuilder
+
+
+
+
+
+ descent.core.dnature
+
+
diff -r 000000000000 -r 55c2951c07be dmdscript_tango/darguments.d
--- /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);
+ }
+}
+
diff -r 000000000000 -r 55c2951c07be dmdscript_tango/darray.d
--- /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);
+ }
+}
+
diff -r 000000000000 -r 55c2951c07be dmdscript_tango/dboolean.d
--- /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);
+ }
+}
+
diff -r 000000000000 -r 55c2951c07be dmdscript_tango/ddate.d
--- /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;
+ }
+}
+
+
diff -r 000000000000 -r 55c2951c07be dmdscript_tango/ddeclaredfunction.d
--- /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;
+ }
+}
+
+
diff -r 000000000000 -r 55c2951c07be dmdscript_tango/derror.d
--- /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);
+ }
+}
+
diff -r 000000000000 -r 55c2951c07be dmdscript_tango/dfunction.d
--- /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;
+ }
+}
diff -r 000000000000 -r 55c2951c07be dmdscript_tango/dglobal.d
--- /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);
+ }
+}
diff -r 000000000000 -r 55c2951c07be dmdscript_tango/dmath.d
--- /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);
+ }
+}
+
diff -r 000000000000 -r 55c2951c07be dmdscript_tango/dnative.d
--- /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);
+ }
+ }
+}
diff -r 000000000000 -r 55c2951c07be dmdscript_tango/dnumber.d
--- /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);
+ }
+}
+
diff -r 000000000000 -r 55c2951c07be dmdscript_tango/dobject.d
--- /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);
+}
diff -r 000000000000 -r 55c2951c07be dmdscript_tango/dregexp.d
--- /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);
+ }
+}
diff -r 000000000000 -r 55c2951c07be dmdscript_tango/dstring.d
--- /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, ®ret, 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, ®ret, 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:
+ // foo
+
+ 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:
+ // foo
+
+ 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 othis
+ */
+
+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:
+ // foo
+
+ 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;
+ }
+}
diff -r 000000000000 -r 55c2951c07be dmdscript_tango/expression.d
--- /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);
+ }
+}
+
diff -r 000000000000 -r 55c2951c07be dmdscript_tango/functiondefinition.d
--- /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()");
+ }
+}
diff -r 000000000000 -r 55c2951c07be dmdscript_tango/identifier.d
--- /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;
+ }
+}
+
+
diff -r 000000000000 -r 55c2951c07be dmdscript_tango/ir.d
--- /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
+}
+
+
diff -r 000000000000 -r 55c2951c07be dmdscript_tango/irstate.d
--- /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);
+ }
+ }
+}
diff -r 000000000000 -r 55c2951c07be dmdscript_tango/iterator.d
--- /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);
+ }
+}
diff -r 000000000000 -r 55c2951c07be dmdscript_tango/lexer.d
--- /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;
+}
+
diff -r 000000000000 -r 55c2951c07be dmdscript_tango/license/gpl.txt
--- /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.
+
+
+ Copyright (C) 19yy
+
+ 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.
+
+ , 1 April 1989
+ Ty Coon, President of Vice
+
+That's all there is to it!
diff -r 000000000000 -r 55c2951c07be dmdscript_tango/license/saaadel.readme.txt
--- /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
diff -r 000000000000 -r 55c2951c07be dmdscript_tango/opcodes.d
--- /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;
+ }
+}
diff -r 000000000000 -r 55c2951c07be dmdscript_tango/parse.d
--- /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;
+ }
+
+}
+
+/********************************* ***************************/
+
diff -r 000000000000 -r 55c2951c07be dmdscript_tango/program.d
--- /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;
+ }
+
+}
diff -r 000000000000 -r 55c2951c07be dmdscript_tango/property.d
--- /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);
+ }
+}
+
+
diff -r 000000000000 -r 55c2951c07be dmdscript_tango/protoerror.d
--- /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;
+}
diff -r 000000000000 -r 55c2951c07be dmdscript_tango/scopex.d
--- /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;
+ }
+}
+
diff -r 000000000000 -r 55c2951c07be dmdscript_tango/script.d
--- /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: //
+ case '\f':
+ case '\v':
+ case '\r':
+ case '\n':
+ case 0x2028: //
+ case 0x2029: //
+ case 0x2001: //
+ 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);
+}
+
diff -r 000000000000 -r 55c2951c07be dmdscript_tango/statement.d
--- /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;
+ }
+}
diff -r 000000000000 -r 55c2951c07be dmdscript_tango/symbol.d
--- /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;
+ }
+}
+
+
diff -r 000000000000 -r 55c2951c07be dmdscript_tango/test/testscript.d
--- /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);
+ }
+}
diff -r 000000000000 -r 55c2951c07be dmdscript_tango/text.d
--- /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";
diff -r 000000000000 -r 55c2951c07be dmdscript_tango/textgen/textgen.d
--- /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" },
+ { "