# 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 ~ + ""; + + 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 ~ + ""; + + 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" }, + { "