diff dmdscript_tango/value.d @ 0:55c2951c07be

initial, files origin, premoved tree
author saaadel
date Sun, 24 Jan 2010 12:34:47 +0200
parents
children 8363a4bf6a8f
line wrap: on
line diff
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/dmdscript_tango/value.d	Sun Jan 24 12:34:47 2010 +0200
@@ -0,0 +1,1094 @@
+
+/* Digital Mars DMDScript source code.
+ * Copyright (c) 2000-2002 by Chromium Communications
+ * D version Copyright (c) 2004-2005 by Digital Mars
+ * All Rights Reserved
+ * written by Walter Bright
+ * www.digitalmars.com
+ * Use at your own risk. There is no warranty, express or implied.
+ * License for redistribution is by the GNU General Public License in gpl.txt.
+ *
+ * A binary, non-exclusive license for commercial use can be
+ * purchased from www.digitalmars.com/dscript/buy.html.
+ *
+ * DMDScript is implemented in the D Programming Language,
+ * www.digitalmars.com/d/
+ *
+ * For a C++ implementation of DMDScript, including COM support,
+ * see www.digitalmars.com/dscript/cppscript.html.
+ */
+
+module dmdscript.value;
+
+import std.math;
+import std.date;
+import std.string;
+import std.stdio;
+import std.c.string;
+
+import dmdscript.script;
+import dmdscript.dobject;
+import dmdscript.iterator;
+import dmdscript.identifier;
+import dmdscript.errmsgs;
+import dmdscript.text;
+import dmdscript.program;
+import dmdscript.dstring;
+import dmdscript.dnumber;
+import dmdscript.dboolean;
+
+// Porting issues:
+// A lot of scaling is done on arrays of Value's. Therefore, adjusting
+// it to come out to a size of 16 bytes makes the scaling an efficient
+// operation. In fact, in some cases (opcodes.c) we prescale the addressing
+// by 16 bytes at compile time instead of runtime.
+// So, Value must be looked at in any port to verify that:
+// 1) the size comes out as 16 bytes, padding as necessary
+// 2) Value::copy() copies the used data bytes, NOT the padding.
+//    It's faster to not copy the padding, and the
+//    padding can contain garbage stack pointers which can
+//    prevent memory from being garbage collected.
+
+version (DigitalMars)
+    version (D_InlineAsm)
+	version = UseAsm;
+
+enum
+{
+    V_NONE      = 0,
+    V_UNDEFINED = 1,
+    V_NULL      = 2,
+    V_BOOLEAN   = 3,
+    V_NUMBER    = 4,
+    V_STRING    = 5,
+    V_OBJECT    = 6,
+    V_ITER      = 7,
+}
+
+struct Value
+{
+    ubyte vtype = V_UNDEFINED;
+
+    uint hash;			// cache 'hash' value
+
+    union
+    {
+	d_boolean dbool;	// can be true or false
+	d_number number;
+	tchar[] string;
+	Dobject object;
+	d_int32  int32;
+	d_uint32 uint32;
+	d_uint16 uint16;
+
+	Iterator* iter;		// V_ITER
+    }
+
+    void putVundefined()
+    {
+	vtype = V_UNDEFINED;
+	hash = 0;
+	string = null;
+    }
+
+    void putVnull()
+    {	vtype = V_NULL;
+    }
+
+    void putVboolean(d_boolean b)
+	in
+	{   assert(b == 1 || b == 0);
+	}
+	body
+	{   vtype = V_BOOLEAN;
+	    dbool = b;
+	}
+
+    void putVnumber(d_number n)
+    {	vtype = V_NUMBER;
+	number = n;
+    }
+
+    void putVtime(d_time n)
+    {	vtype = V_NUMBER;
+	number = (n == d_time_nan) ? d_number.nan : n;
+    }
+
+    void putVstring(d_string s)
+    {	vtype = V_STRING;
+	hash = 0;
+	string = s;
+    }
+
+    void putVstring(d_string s, uint hash)
+    {	vtype = V_STRING;
+	this.hash = hash;
+	this.string = s;
+    }
+
+    void putVobject(Dobject o)
+    {	vtype = V_OBJECT;
+	object = o;
+    }
+
+    void putViterator(Iterator* i)
+    {	vtype = V_ITER;
+	iter = i;
+    }
+
+    invariant
+    {
+/+
+	switch (vtype)
+	{
+	    case V_UNDEFINED:
+	    case V_NULL:
+		break;
+	    case V_BOOLEAN:
+		assert(dbool == 1 || dbool == 0);
+		break;
+	    case V_NUMBER:
+	    case V_STRING:
+	    case V_OBJECT:
+	    case V_ITER:
+		break;
+	    case V_NONE:
+		break;
+	    default:
+		writefln("vtype = %d", vtype);
+		assert(0);
+		break;
+	}
++/
+    }
+
+    static void copy(Value* to, Value* from)
+/+    in { }
+    out { assert(memcmp(to, from, Value.sizeof) == 0); }
+    body
++/
+    {
+	version (all /*UseAsm*/)
+	{
+	    asm
+	    {	naked			;
+		push	ESI		;
+		mov	ECX,[EAX]	;
+		mov	ESI,8[ESP]	;
+		mov	[ESI],ECX	;
+		mov	EDX,4[EAX]	;
+		mov	ECX,8[EAX]	;
+		mov	EAX,12[EAX]	;
+		mov	4[ESI],EDX	;
+		mov	8[ESI],ECX	;
+		mov	12[ESI],EAX	;
+		pop	ESI		;
+		ret	4		;
+	     }
+	}
+	else
+	{
+	    *to = *from;
+	    //(cast(uint *)to)[0] = (cast(uint *)from)[0];
+	    //(cast(uint *)to)[1] = (cast(uint *)from)[1];
+	    //(cast(uint *)to)[2] = (cast(uint *)from)[2];
+	    //(cast(uint *)to)[3] = (cast(uint *)from)[3];
+	}
+    }
+
+    void* toPrimitive(Value* v, tchar[] PreferredType)
+    {
+	if (vtype == V_OBJECT)
+	{
+	    /*	ECMA 9.1
+		Return a default value for the Object.
+		The default value of an object is retrieved by
+		calling the internal [[DefaultValue]] method
+		of the object, passing the optional hint
+		PreferredType. The behavior of the [[DefaultValue]]
+		method is defined by this specification for all
+		native ECMAScript objects (see section 8.6.2.6).
+		If the return value is of type Object or Reference,
+		a runtime error is generated.
+	     */
+	    void* a;
+
+	    assert(object);
+	    a = object.DefaultValue(v, PreferredType);
+	    if (a)
+		return a;
+	    if (!v.isPrimitive())
+	    {
+		ErrInfo errinfo;
+
+		v.putVundefined();
+		return Dobject.RuntimeError(&errinfo,
+			errmsgtbl[ERR_OBJECT_CANNOT_BE_PRIMITIVE]);
+	    }
+	}
+	else
+	{
+	    copy(v, this);
+	}
+	return null;
+    }
+
+
+    d_boolean toBoolean()
+    {
+	switch (vtype)
+	{
+	    case V_UNDEFINED:
+	    case V_NULL:
+		return false;
+	    case V_BOOLEAN:
+		return dbool;
+	    case V_NUMBER:
+		return !(number == 0.0 || isnan(number));
+	    case V_STRING:
+		return string.length ? true : false;
+	    case V_OBJECT:
+		return true;
+	    default:
+		assert(0);
+	}
+	assert(0);
+    }
+
+
+    d_number toNumber()
+    {
+	switch (vtype)
+	{
+	    case V_UNDEFINED:
+		return d_number.nan;
+	    case V_NULL:
+		return 0;
+	    case V_BOOLEAN:
+		return dbool ? 1 : 0;
+	    case V_NUMBER:
+		return number;
+	    case V_STRING:
+	    {
+		d_number n;
+		size_t len;
+		size_t endidx;
+
+		len = string.length;
+		n = StringNumericLiteral(string, endidx, 0);
+
+		// Consume trailing whitespace
+		//writefln("n = %s, string = '%s', endidx = %s, length = %s", n, string, endidx, string.length);
+		foreach (dchar c; string[endidx .. length])
+		{   if (!isStrWhiteSpaceChar(c))
+		    {	n = d_number.nan;
+			break;
+		    }
+		}
+
+		return n;
+	    }
+	    case V_OBJECT:
+	    {   Value val;
+		Value* v;
+
+		//writefln("Vobject.toNumber()");
+		v = &val;
+		toPrimitive(v, TypeNumber);
+		if (v.isPrimitive())
+		    return v.toNumber();
+		else
+		    return d_number.nan;
+	    }
+	    default:
+		assert(0);
+	}
+	assert(0);
+    }
+
+
+    d_time toDtime()
+    {
+	return cast(d_time)toNumber();
+    }
+
+
+    d_number toInteger()
+    {
+	switch (vtype)
+	{
+	    case V_UNDEFINED:
+		return d_number.nan;
+	    case V_NULL:
+		return 0;
+	    case V_BOOLEAN:
+		return dbool ? 1 : 0;
+
+	    default:
+	    {   d_number number;
+
+		number = toNumber();
+		if (isnan(number))
+		    number = 0;
+		else if (number == 0 || std.math.isinf(number))
+		    { }
+		else if (number > 0)
+		    number = std.math.floor(number);
+		else
+		    number = -std.math.floor(-number);
+		return number;
+	    }
+	}
+	assert(0);
+    }
+
+
+    d_int32 toInt32()
+    {
+	switch (vtype)
+	{
+	    case V_UNDEFINED:
+	    case V_NULL:
+		return 0;
+	    case V_BOOLEAN:
+		return dbool ? 1 : 0;
+
+	    default:
+	    {   d_int32 int32;
+		d_number number;
+		long ll;
+
+		number = toNumber();
+		if (isnan(number))
+		    int32 = 0;
+		else if (number == 0 || std.math.isinf(number))
+		    int32 = 0;
+		else
+		{   if (number > 0)
+			number = std.math.floor(number);
+		    else
+			number = -std.math.floor(-number);
+
+		    ll = cast(long) number;
+		    int32 = cast(int) ll;
+		}
+		return int32;
+	    }
+	}
+	assert(0);
+    }
+
+
+    d_uint32 toUint32()
+    {
+	switch (vtype)
+	{
+	    case V_UNDEFINED:
+	    case V_NULL:
+		return 0;
+	    case V_BOOLEAN:
+		return dbool ? 1 : 0;
+
+	    default:
+	    {   d_uint32 uint32;
+		d_number number;
+		long ll;
+
+		number = toNumber();
+		if (isnan(number))
+		    uint32 = 0;
+		else if (number == 0 || std.math.isinf(number))
+		    uint32 = 0;
+		else
+		{   if (number > 0)
+			number = std.math.floor(number);
+		    else
+			number = -std.math.floor(-number);
+
+		    ll = cast(long) number;
+		    uint32 = cast(uint) ll;
+		}
+		return uint32;
+	    }
+	}
+	assert(0);
+    }
+
+    d_uint16 toUint16()
+    {
+	switch (vtype)
+	{
+	    case V_UNDEFINED:
+	    case V_NULL:
+		return 0;
+	    case V_BOOLEAN:
+		return cast(d_uint16) (dbool ? 1 : 0);
+
+	    default:
+	    {   d_uint16 uint16;
+		d_number number;
+
+		number = toNumber();
+		if (isnan(number))
+		    uint16 = 0;
+		else if (number == 0 || std.math.isinf(number))
+		    uint16 = 0;
+		else
+		{   if (number > 0)
+			number = std.math.floor(number);
+		    else
+			number = -std.math.floor(-number);
+
+		    uint16 = cast(ushort)number;
+		}
+		return uint16;
+	    }
+	}
+	assert(0);
+    }
+
+    d_string toString()
+    {
+	switch (vtype)
+	{
+	    case V_UNDEFINED:
+		return TEXT_undefined;
+	    case V_NULL:
+		return TEXT_null;
+	    case V_BOOLEAN:
+		return dbool ? TEXT_true : TEXT_false;
+	    case V_NUMBER:
+		{   d_string string;
+		    static d_string* strings[10] =
+		    [   &TEXT_0,&TEXT_1,&TEXT_2,&TEXT_3,&TEXT_4,
+			&TEXT_5,&TEXT_6,&TEXT_7,&TEXT_8,&TEXT_9 ];
+
+		    //writefln("Vnumber.toString(%g)", number);
+		    if (isnan(number))
+			string = TEXT_NaN;
+		    else if (number >= 0 && number <= 9 && number == cast(int) number)
+			string = *strings[cast(int) number];
+		    else if (std.math.isinf(number))
+		    {
+			if (number < 0)
+			    string = TEXT_negInfinity;
+			else
+			    string = TEXT_Infinity;
+		    }
+		    else
+		    {
+			tchar[100] buffer;	// should shrink this to max size,
+						// but doesn't really matter
+			tchar* p;
+
+			// ECMA 262 requires %.21g (21 digits) of precision. But, the
+			// C runtime library doesn't handle that. Until the C runtime
+			// library is upgraded to ANSI C 99 conformance, use
+			// 16 digits, which is all the GCC library will round correctly.
+
+			std.string.sformat(buffer, "%.16g\0", number);
+			//std.c.stdio.sprintf(buffer.ptr, "%.16g", number);
+
+			// Trim leading spaces
+			// Trim leading spaces
+			for (p = buffer.ptr; *p == ' '; p++) { }
+
+			{   // Trim any 0's following exponent 'e'
+			    tchar* q;
+			    tchar* t;
+
+			    for (q = p; *q; q++)
+			    {
+				if (*q == 'e')
+				{
+				    q++;
+				    if (*q == '+' || *q == '-')
+					q++;
+				    t = q;
+				    while (*q == '0')
+					q++;
+				    if (t != q)
+				    {
+					for (;;)
+					{
+					    *t = *q;
+					    if (*t == 0)
+						break;
+					    t++;
+					    q++;
+					}
+				    }
+				    break;
+				}
+			    }
+			}
+			string = p[0 .. std.c.string.strlen(p)].dup;
+		    }
+		    //writefln("string = '%s'", string);
+		    return string;
+		}
+	    case V_STRING:
+		return string;
+	    case V_OBJECT:
+	    {   Value val;
+		Value* v = &val;
+		void* a;
+
+		//writef("Vobject.toString()\n");
+		a = toPrimitive(v, TypeString);
+		//assert(!a);
+		if (v.isPrimitive())
+		    return v.toString();
+		else
+		    return v.toObject().classname;
+	    }
+	    default:
+		assert(0);
+	}
+	assert(0);
+    }
+
+    d_string toLocaleString()
+    {
+	return toString();
+    }
+
+    d_string toString(int radix)
+    {
+	if (vtype == V_NUMBER)
+	{
+	    assert(2 <= radix && radix <= 36);
+	    return std.string.toString(cast(long)number, cast(uint)radix);
+	}
+	else
+	{
+	    return toString();
+	}
+    }
+
+    d_string toSource()
+    {
+	switch (vtype)
+	{
+	    case V_STRING:
+	    {	d_string s;
+
+		s = "\"" ~ string ~ "\"";
+		return s;
+	    }
+	    case V_OBJECT:
+	    {   Value* v;
+
+		//writefln("Vobject.toSource()");
+		v = Get(TEXT_toSource);
+		if (!v)
+		    v = &vundefined;
+		if (v.isPrimitive())
+		    return v.toSource();
+		else	// it's an Object
+		{   void* a;
+		    CallContext *cc;
+		    Dobject o;
+		    Value* ret;
+		    Value val;
+
+		    o = v.object;
+		    cc = Program.getProgram().callcontext;
+		    ret = &val;
+		    a = o.Call(cc, this.object, ret, null);
+		    if (a)			// if exception was thrown
+		    {
+			/*return a*/;
+			writef("Vobject.toSource() failed with %x\n", a);
+		    }
+		    else if (ret.isPrimitive())
+			return ret.toString();
+		}
+		return TEXT_undefined;
+	    }
+	    default:
+		return toString();
+	}
+	assert(0);
+    }
+
+    Dobject toObject()
+    {
+	switch (vtype)
+	{
+	    case V_UNDEFINED:
+		//RuntimeErrorx("cannot convert undefined to Object");
+		return null;
+	    case V_NULL:
+		//RuntimeErrorx("cannot convert null to Object");
+		return null;
+	    case V_BOOLEAN:
+		return new Dboolean(dbool);
+	    case V_NUMBER:
+		return new Dnumber(number);
+	    case V_STRING:
+		return new Dstring(string);
+	    case V_OBJECT:
+		return object;
+	    default:
+		assert(0);
+	}
+	assert(0);
+    }
+
+    int opEquals(Value* v)
+    {
+	return (opCmp(v) == 0);
+    }
+
+    /*********************************
+     * Use this instead of std.string.cmp() because
+     * we don't care about lexicographic ordering.
+     * This is faster.
+     */
+
+    static int stringcmp(d_string s1, d_string s2)
+    {
+	int c = s1.length - s2.length;
+	if (c == 0)
+	{
+	    if (s1.ptr == s2.ptr)
+		return 0;
+	    c = memcmp(s1.ptr, s2.ptr, s1.length);
+	}
+	return c;
+    }
+
+    int opCmp(Value* v)
+    {
+	switch (vtype)
+	{
+	    case V_UNDEFINED:
+		if (vtype == v.vtype)
+		    return 0;
+		break;
+	    case V_NULL:
+		if (vtype == v.vtype)
+		    return 0;
+		break;
+	    case V_BOOLEAN:
+		if (vtype == v.vtype)
+		    return v.dbool - dbool;
+		break;
+	    case V_NUMBER:
+		if (v.vtype == V_NUMBER)
+		{
+		    if (number == v.number)
+			return 0;
+		    if (isnan(number) && isnan(v.number))
+			return 0;
+		    if (number > v.number)
+			return 1;
+		}
+		else if (v.vtype == V_STRING)
+		{
+		    return stringcmp(toString(), v.string);
+		}
+		break;
+	    case V_STRING:
+		if (v.vtype == V_STRING)
+		{
+		    //writefln("'%s'.compareTo('%s')", string, v.string);
+		    int len = string.length - v.string.length;
+		    if (len == 0)
+		    {
+			if (string.ptr == v.string.ptr)
+			    return 0;
+			len = memcmp(string.ptr, v.string.ptr, string.length);
+		    }
+		    return len;
+		}
+		else if (v.vtype == V_NUMBER)
+		{
+		    //writefln("'%s'.compareTo(%g)\n", string, v.number);
+		    return stringcmp(string, v.toString());
+		}
+		break;
+	    case V_OBJECT:
+		if (v.object == object)
+		    return 0;
+		break;
+	    default:
+		assert(0);
+	}
+	return -1;
+    }
+
+    void copyTo(Value* v)
+    {	// Copy everything, including vptr
+	copy(this, v);
+    }
+
+    tchar[] getType()
+    {	tchar[] s;
+
+	switch (vtype)
+	{
+	    case V_UNDEFINED:	s = TypeUndefined; break;
+	    case V_NULL:	s = TypeNull;      break;
+	    case V_BOOLEAN:	s = TypeBoolean;   break;
+	    case V_NUMBER:	s = TypeNumber;    break;
+	    case V_STRING:	s = TypeString;    break;
+	    case V_OBJECT:	s = TypeObject;    break;
+	    case V_ITER:	s = TypeIterator;  break;
+	    default:
+		writefln("vtype = %d", vtype);
+		assert(0);
+	}
+	return s;
+    }
+
+    d_string getTypeof()
+    {	tchar[] s;
+
+	switch (vtype)
+	{
+	    case V_UNDEFINED:	s = TEXT_undefined;	break;
+	    case V_NULL:	s = TEXT_object;	break;
+	    case V_BOOLEAN:	s = TEXT_boolean;	break;
+	    case V_NUMBER:	s = TEXT_number;	break;
+	    case V_STRING:	s = TEXT_string;	break;
+	    case V_OBJECT:	s = object.getTypeof();	break;
+	    default:
+		writefln("vtype = %d", vtype);
+		assert(0);
+	}
+	return s;
+    }
+
+    int isUndefined() { return vtype == V_UNDEFINED; }
+    int isNull()      { return vtype == V_NULL;      }
+    int isBoolean()   { return vtype == V_BOOLEAN;   }
+    int isNumber()    { return vtype == V_NUMBER;    }
+    int isString()    { return vtype == V_STRING;    }
+    int isObject()    { return vtype == V_OBJECT;    }
+    int isIterator()  { return vtype == V_ITER;      }
+
+    int isUndefinedOrNull() { return vtype == V_UNDEFINED || vtype == V_NULL; }
+
+    int isPrimitive() { return vtype != V_OBJECT; }
+
+    int isArrayIndex(out d_uint32 index)
+    {
+	switch (vtype)
+	{
+	    case V_NUMBER:
+		index = toUint32();
+		return true;
+	    case V_STRING:
+		return StringToIndex(string, index);
+	    default:
+		index = 0;
+		return false;
+	}
+	assert(0);
+    }
+
+    static uint calcHash(uint u)
+    {
+	return u ^ 0x55555555;
+    }
+
+    static uint calcHash(double d)
+    {
+	return calcHash(cast(uint) d);
+    }
+
+    static uint calcHash(d_string s)
+    {
+	uint hash;
+
+	/* If it looks like an array index, hash it to the
+	 * same value as if it was an array index.
+	 * This means that "1234" hashes to the same value as 1234.
+	 */
+	hash = 0;
+	foreach (tchar c; s)
+	{
+	    switch (c)
+	    {
+		case '0':	hash *= 10;		break;
+		case '1':	hash = hash * 10 + 1;	break;
+
+		case '2':
+		case '3':
+		case '4':
+		case '5':
+		case '6':
+		case '7':
+		case '8':
+		case '9':
+		    hash = hash * 10 + (c - '0');
+		    break;
+
+		default:
+		{   uint len = s.length;
+		    ubyte *str = cast(ubyte*)s.ptr;
+
+		    hash = 0;
+		    while (1)
+		    {
+			switch (len)
+			{
+			    case 0:
+				break;
+
+			    case 1:
+				hash *= 9;
+				hash += *cast(ubyte *)str;
+				break;
+
+			    case 2:
+				hash *= 9;
+				hash += *cast(ushort *)str;
+				break;
+
+			    case 3:
+				hash *= 9;
+				hash += (*cast(ushort *)str << 8) +
+					(cast(ubyte *)str)[2];
+				break;
+
+			    default:
+				hash *= 9;
+				hash += *cast(uint *)str;
+				str += 4;
+				len -= 4;
+				continue;
+			}
+			break;
+		    }
+		    break;
+		}
+		// return s.hash;
+	    }
+	}
+	return calcHash(hash);
+    }
+
+    uint toHash()
+    {	uint h;
+
+	switch (vtype)
+	{
+	    case V_UNDEFINED:
+	    case V_NULL:
+		h = 0;
+		break;
+	    case V_BOOLEAN:
+		h = dbool ? 1 : 0;
+		break;
+	    case V_NUMBER:
+		h = calcHash(number);
+		break;
+	    case V_STRING:
+		// Since strings are immutable, if we've already
+		// computed the hash, use previous value
+		if (!hash)
+		    hash = calcHash(string);
+		h = hash;
+		break;
+	    case V_OBJECT:
+		/* Uses the address of the object as the hash.
+		 * Since the object never moves, it will work
+		 * as its hash.
+		 * BUG: shouldn't do this.
+		 */
+		h = cast(uint)cast(void*) object;
+		break;
+	    default:
+		assert(0);
+	}
+	//writefln("\tValue.toHash() = %x", h);
+	return h;
+    }
+
+    Value* Put(d_string PropertyName, Value* value)
+    {
+	if (vtype == V_OBJECT)
+	    return object.Put(PropertyName, value, 0);
+	else	
+	{
+	    ErrInfo errinfo;
+
+	    return Dobject.RuntimeError(&errinfo,
+		    errmsgtbl[ERR_CANNOT_PUT_TO_PRIMITIVE],
+		    PropertyName, value.toString(),
+		    getType());
+	}
+    }
+
+    Value* Put(d_uint32 index, Value* vindex, Value* value)
+    {
+	if (vtype == V_OBJECT)
+	    return object.Put(index, vindex, value, 0);
+	else	
+	{
+	    ErrInfo errinfo;
+
+	    return Dobject.RuntimeError(&errinfo,
+		    errmsgtbl[ERR_CANNOT_PUT_INDEX_TO_PRIMITIVE],
+		    index,
+		    value.toString(), getType());
+	}
+    }
+
+    Value* Get(d_string PropertyName)
+    {
+	if (vtype == V_OBJECT)
+	    return object.Get(PropertyName);
+	else	
+	{
+	    // Should we generate the error, or just return undefined?
+	    tchar[] msg;
+
+	    msg = std.string.format(errmsgtbl[ERR_CANNOT_GET_FROM_PRIMITIVE],
+		PropertyName, getType(), toString());
+	    throw new ScriptException(msg);
+	    //return &vundefined;
+	}
+    }
+
+    Value* Get(d_uint32 index)
+    {
+	if (vtype == V_OBJECT)
+	    return object.Get(index);
+	else	
+	{
+	    // Should we generate the error, or just return undefined?
+	    tchar[] msg;
+
+	    msg = std.string.format(errmsgtbl[ERR_CANNOT_GET_INDEX_FROM_PRIMITIVE],
+		index, getType(), toString());
+	    throw new ScriptException(msg);
+	    //return &vundefined;
+	}
+    }
+
+    Value* Get(Identifier *id)
+    {
+	if (vtype == V_OBJECT)
+	    return object.Get(id);
+	else	
+	{
+	    // Should we generate the error, or just return undefined?
+	    tchar[] msg;
+
+	    msg = std.string.format(errmsgtbl[ERR_CANNOT_GET_FROM_PRIMITIVE],
+		id.toString(), getType(), toString());
+	    throw new ScriptException(msg);
+	    //return &vundefined;
+	}
+    }
+/+
+    Value* Get(d_string PropertyName, uint hash)
+    {
+	if (vtype == V_OBJECT)
+	    return object.Get(PropertyName, hash);
+	else	
+	{
+	    // Should we generate the error, or just return undefined?
+	    tchar[] msg;
+
+	    msg = std.string.format(errmsgtbl[ERR_CANNOT_GET_FROM_PRIMITIVE],
+		PropertyName, getType(), toString());
+	    throw new ScriptException(msg);
+	    //return &vundefined;
+	}
+    }
++/
+    void* Construct(CallContext *cc, Value *ret, Value[] arglist)
+    {
+	if (vtype == V_OBJECT)
+	    return object.Construct(cc, ret, arglist);
+	else	
+	{
+	    ErrInfo errinfo;
+	    ret.putVundefined();
+	    return Dobject.RuntimeError(&errinfo,
+		errmsgtbl[ERR_PRIMITIVE_NO_CONSTRUCT], getType());
+	}
+    }
+
+    void* Call(CallContext *cc, Dobject othis, Value* ret, Value[] arglist)
+    {
+	if (vtype == V_OBJECT)
+	{
+	    void* a;
+
+	    a = object.Call(cc, othis, ret, arglist);
+	    //if (a) writef("Vobject.Call() returned %x\n", a);
+	    return a;
+	}
+	else	
+	{
+	    ErrInfo errinfo;
+	    //PRINTF("Call method not implemented for primitive %p (%s)\n", this, d_string_ptr(toString()));
+	    ret.putVundefined();
+	    return Dobject.RuntimeError(&errinfo,
+		errmsgtbl[ERR_PRIMITIVE_NO_CALL], getType());
+	}
+    }
+
+    Value* putIterator(Value* v)
+    {
+	if (vtype == V_OBJECT)
+	    return object.putIterator(v);
+	else	
+	{
+	    ErrInfo errinfo;
+	    v.putVundefined();
+	    return Dobject.RuntimeError(&errinfo,
+		errmsgtbl[ERR_FOR_IN_MUST_BE_OBJECT]);
+	}
+    }
+
+
+    void getErrInfo(ErrInfo *perrinfo, int linnum)
+    {
+	if (vtype == V_OBJECT)
+	    object.getErrInfo(perrinfo, linnum);
+	else	
+	{
+	    ErrInfo errinfo;
+
+	    if (linnum && errinfo.linnum == 0)
+		errinfo.linnum = linnum;
+	    errinfo.message = "Unhandled exception: " ~ toString();
+	    if (perrinfo)
+		*perrinfo = errinfo;
+	}
+    }
+
+    void dump()
+    {   uint *v = cast(uint *)this;
+
+	writef("v[%x] = %8x, %8x, %8x, %8x\n", cast(uint)v, v[0], v[1], v[2], v[3]);
+    }
+}
+
+static assert(Value.sizeof == 16);
+
+Value vundefined = { V_UNDEFINED };
+Value vnull = { V_NULL };
+
+tchar[] TypeUndefined = "Undefined";
+tchar[] TypeNull      = "Null";
+tchar[] TypeBoolean   = "Boolean";
+tchar[] TypeNumber    = "Number";
+tchar[] TypeString    = "String";
+tchar[] TypeObject    = "Object";
+
+tchar[] TypeIterator  = "Iterator";
+
+
+
+
+
+
+