comparison 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
comparison
equal deleted inserted replaced
-1:000000000000 0:55c2951c07be
1
2 /* Digital Mars DMDScript source code.
3 * Copyright (c) 2000-2002 by Chromium Communications
4 * D version Copyright (c) 2004-2005 by Digital Mars
5 * All Rights Reserved
6 * written by Walter Bright
7 * www.digitalmars.com
8 * Use at your own risk. There is no warranty, express or implied.
9 * License for redistribution is by the GNU General Public License in gpl.txt.
10 *
11 * A binary, non-exclusive license for commercial use can be
12 * purchased from www.digitalmars.com/dscript/buy.html.
13 *
14 * DMDScript is implemented in the D Programming Language,
15 * www.digitalmars.com/d/
16 *
17 * For a C++ implementation of DMDScript, including COM support,
18 * see www.digitalmars.com/dscript/cppscript.html.
19 */
20
21 module dmdscript.value;
22
23 import std.math;
24 import std.date;
25 import std.string;
26 import std.stdio;
27 import std.c.string;
28
29 import dmdscript.script;
30 import dmdscript.dobject;
31 import dmdscript.iterator;
32 import dmdscript.identifier;
33 import dmdscript.errmsgs;
34 import dmdscript.text;
35 import dmdscript.program;
36 import dmdscript.dstring;
37 import dmdscript.dnumber;
38 import dmdscript.dboolean;
39
40 // Porting issues:
41 // A lot of scaling is done on arrays of Value's. Therefore, adjusting
42 // it to come out to a size of 16 bytes makes the scaling an efficient
43 // operation. In fact, in some cases (opcodes.c) we prescale the addressing
44 // by 16 bytes at compile time instead of runtime.
45 // So, Value must be looked at in any port to verify that:
46 // 1) the size comes out as 16 bytes, padding as necessary
47 // 2) Value::copy() copies the used data bytes, NOT the padding.
48 // It's faster to not copy the padding, and the
49 // padding can contain garbage stack pointers which can
50 // prevent memory from being garbage collected.
51
52 version (DigitalMars)
53 version (D_InlineAsm)
54 version = UseAsm;
55
56 enum
57 {
58 V_NONE = 0,
59 V_UNDEFINED = 1,
60 V_NULL = 2,
61 V_BOOLEAN = 3,
62 V_NUMBER = 4,
63 V_STRING = 5,
64 V_OBJECT = 6,
65 V_ITER = 7,
66 }
67
68 struct Value
69 {
70 ubyte vtype = V_UNDEFINED;
71
72 uint hash; // cache 'hash' value
73
74 union
75 {
76 d_boolean dbool; // can be true or false
77 d_number number;
78 tchar[] string;
79 Dobject object;
80 d_int32 int32;
81 d_uint32 uint32;
82 d_uint16 uint16;
83
84 Iterator* iter; // V_ITER
85 }
86
87 void putVundefined()
88 {
89 vtype = V_UNDEFINED;
90 hash = 0;
91 string = null;
92 }
93
94 void putVnull()
95 { vtype = V_NULL;
96 }
97
98 void putVboolean(d_boolean b)
99 in
100 { assert(b == 1 || b == 0);
101 }
102 body
103 { vtype = V_BOOLEAN;
104 dbool = b;
105 }
106
107 void putVnumber(d_number n)
108 { vtype = V_NUMBER;
109 number = n;
110 }
111
112 void putVtime(d_time n)
113 { vtype = V_NUMBER;
114 number = (n == d_time_nan) ? d_number.nan : n;
115 }
116
117 void putVstring(d_string s)
118 { vtype = V_STRING;
119 hash = 0;
120 string = s;
121 }
122
123 void putVstring(d_string s, uint hash)
124 { vtype = V_STRING;
125 this.hash = hash;
126 this.string = s;
127 }
128
129 void putVobject(Dobject o)
130 { vtype = V_OBJECT;
131 object = o;
132 }
133
134 void putViterator(Iterator* i)
135 { vtype = V_ITER;
136 iter = i;
137 }
138
139 invariant
140 {
141 /+
142 switch (vtype)
143 {
144 case V_UNDEFINED:
145 case V_NULL:
146 break;
147 case V_BOOLEAN:
148 assert(dbool == 1 || dbool == 0);
149 break;
150 case V_NUMBER:
151 case V_STRING:
152 case V_OBJECT:
153 case V_ITER:
154 break;
155 case V_NONE:
156 break;
157 default:
158 writefln("vtype = %d", vtype);
159 assert(0);
160 break;
161 }
162 +/
163 }
164
165 static void copy(Value* to, Value* from)
166 /+ in { }
167 out { assert(memcmp(to, from, Value.sizeof) == 0); }
168 body
169 +/
170 {
171 version (all /*UseAsm*/)
172 {
173 asm
174 { naked ;
175 push ESI ;
176 mov ECX,[EAX] ;
177 mov ESI,8[ESP] ;
178 mov [ESI],ECX ;
179 mov EDX,4[EAX] ;
180 mov ECX,8[EAX] ;
181 mov EAX,12[EAX] ;
182 mov 4[ESI],EDX ;
183 mov 8[ESI],ECX ;
184 mov 12[ESI],EAX ;
185 pop ESI ;
186 ret 4 ;
187 }
188 }
189 else
190 {
191 *to = *from;
192 //(cast(uint *)to)[0] = (cast(uint *)from)[0];
193 //(cast(uint *)to)[1] = (cast(uint *)from)[1];
194 //(cast(uint *)to)[2] = (cast(uint *)from)[2];
195 //(cast(uint *)to)[3] = (cast(uint *)from)[3];
196 }
197 }
198
199 void* toPrimitive(Value* v, tchar[] PreferredType)
200 {
201 if (vtype == V_OBJECT)
202 {
203 /* ECMA 9.1
204 Return a default value for the Object.
205 The default value of an object is retrieved by
206 calling the internal [[DefaultValue]] method
207 of the object, passing the optional hint
208 PreferredType. The behavior of the [[DefaultValue]]
209 method is defined by this specification for all
210 native ECMAScript objects (see section 8.6.2.6).
211 If the return value is of type Object or Reference,
212 a runtime error is generated.
213 */
214 void* a;
215
216 assert(object);
217 a = object.DefaultValue(v, PreferredType);
218 if (a)
219 return a;
220 if (!v.isPrimitive())
221 {
222 ErrInfo errinfo;
223
224 v.putVundefined();
225 return Dobject.RuntimeError(&errinfo,
226 errmsgtbl[ERR_OBJECT_CANNOT_BE_PRIMITIVE]);
227 }
228 }
229 else
230 {
231 copy(v, this);
232 }
233 return null;
234 }
235
236
237 d_boolean toBoolean()
238 {
239 switch (vtype)
240 {
241 case V_UNDEFINED:
242 case V_NULL:
243 return false;
244 case V_BOOLEAN:
245 return dbool;
246 case V_NUMBER:
247 return !(number == 0.0 || isnan(number));
248 case V_STRING:
249 return string.length ? true : false;
250 case V_OBJECT:
251 return true;
252 default:
253 assert(0);
254 }
255 assert(0);
256 }
257
258
259 d_number toNumber()
260 {
261 switch (vtype)
262 {
263 case V_UNDEFINED:
264 return d_number.nan;
265 case V_NULL:
266 return 0;
267 case V_BOOLEAN:
268 return dbool ? 1 : 0;
269 case V_NUMBER:
270 return number;
271 case V_STRING:
272 {
273 d_number n;
274 size_t len;
275 size_t endidx;
276
277 len = string.length;
278 n = StringNumericLiteral(string, endidx, 0);
279
280 // Consume trailing whitespace
281 //writefln("n = %s, string = '%s', endidx = %s, length = %s", n, string, endidx, string.length);
282 foreach (dchar c; string[endidx .. length])
283 { if (!isStrWhiteSpaceChar(c))
284 { n = d_number.nan;
285 break;
286 }
287 }
288
289 return n;
290 }
291 case V_OBJECT:
292 { Value val;
293 Value* v;
294
295 //writefln("Vobject.toNumber()");
296 v = &val;
297 toPrimitive(v, TypeNumber);
298 if (v.isPrimitive())
299 return v.toNumber();
300 else
301 return d_number.nan;
302 }
303 default:
304 assert(0);
305 }
306 assert(0);
307 }
308
309
310 d_time toDtime()
311 {
312 return cast(d_time)toNumber();
313 }
314
315
316 d_number toInteger()
317 {
318 switch (vtype)
319 {
320 case V_UNDEFINED:
321 return d_number.nan;
322 case V_NULL:
323 return 0;
324 case V_BOOLEAN:
325 return dbool ? 1 : 0;
326
327 default:
328 { d_number number;
329
330 number = toNumber();
331 if (isnan(number))
332 number = 0;
333 else if (number == 0 || std.math.isinf(number))
334 { }
335 else if (number > 0)
336 number = std.math.floor(number);
337 else
338 number = -std.math.floor(-number);
339 return number;
340 }
341 }
342 assert(0);
343 }
344
345
346 d_int32 toInt32()
347 {
348 switch (vtype)
349 {
350 case V_UNDEFINED:
351 case V_NULL:
352 return 0;
353 case V_BOOLEAN:
354 return dbool ? 1 : 0;
355
356 default:
357 { d_int32 int32;
358 d_number number;
359 long ll;
360
361 number = toNumber();
362 if (isnan(number))
363 int32 = 0;
364 else if (number == 0 || std.math.isinf(number))
365 int32 = 0;
366 else
367 { if (number > 0)
368 number = std.math.floor(number);
369 else
370 number = -std.math.floor(-number);
371
372 ll = cast(long) number;
373 int32 = cast(int) ll;
374 }
375 return int32;
376 }
377 }
378 assert(0);
379 }
380
381
382 d_uint32 toUint32()
383 {
384 switch (vtype)
385 {
386 case V_UNDEFINED:
387 case V_NULL:
388 return 0;
389 case V_BOOLEAN:
390 return dbool ? 1 : 0;
391
392 default:
393 { d_uint32 uint32;
394 d_number number;
395 long ll;
396
397 number = toNumber();
398 if (isnan(number))
399 uint32 = 0;
400 else if (number == 0 || std.math.isinf(number))
401 uint32 = 0;
402 else
403 { if (number > 0)
404 number = std.math.floor(number);
405 else
406 number = -std.math.floor(-number);
407
408 ll = cast(long) number;
409 uint32 = cast(uint) ll;
410 }
411 return uint32;
412 }
413 }
414 assert(0);
415 }
416
417 d_uint16 toUint16()
418 {
419 switch (vtype)
420 {
421 case V_UNDEFINED:
422 case V_NULL:
423 return 0;
424 case V_BOOLEAN:
425 return cast(d_uint16) (dbool ? 1 : 0);
426
427 default:
428 { d_uint16 uint16;
429 d_number number;
430
431 number = toNumber();
432 if (isnan(number))
433 uint16 = 0;
434 else if (number == 0 || std.math.isinf(number))
435 uint16 = 0;
436 else
437 { if (number > 0)
438 number = std.math.floor(number);
439 else
440 number = -std.math.floor(-number);
441
442 uint16 = cast(ushort)number;
443 }
444 return uint16;
445 }
446 }
447 assert(0);
448 }
449
450 d_string toString()
451 {
452 switch (vtype)
453 {
454 case V_UNDEFINED:
455 return TEXT_undefined;
456 case V_NULL:
457 return TEXT_null;
458 case V_BOOLEAN:
459 return dbool ? TEXT_true : TEXT_false;
460 case V_NUMBER:
461 { d_string string;
462 static d_string* strings[10] =
463 [ &TEXT_0,&TEXT_1,&TEXT_2,&TEXT_3,&TEXT_4,
464 &TEXT_5,&TEXT_6,&TEXT_7,&TEXT_8,&TEXT_9 ];
465
466 //writefln("Vnumber.toString(%g)", number);
467 if (isnan(number))
468 string = TEXT_NaN;
469 else if (number >= 0 && number <= 9 && number == cast(int) number)
470 string = *strings[cast(int) number];
471 else if (std.math.isinf(number))
472 {
473 if (number < 0)
474 string = TEXT_negInfinity;
475 else
476 string = TEXT_Infinity;
477 }
478 else
479 {
480 tchar[100] buffer; // should shrink this to max size,
481 // but doesn't really matter
482 tchar* p;
483
484 // ECMA 262 requires %.21g (21 digits) of precision. But, the
485 // C runtime library doesn't handle that. Until the C runtime
486 // library is upgraded to ANSI C 99 conformance, use
487 // 16 digits, which is all the GCC library will round correctly.
488
489 std.string.sformat(buffer, "%.16g\0", number);
490 //std.c.stdio.sprintf(buffer.ptr, "%.16g", number);
491
492 // Trim leading spaces
493 // Trim leading spaces
494 for (p = buffer.ptr; *p == ' '; p++) { }
495
496 { // Trim any 0's following exponent 'e'
497 tchar* q;
498 tchar* t;
499
500 for (q = p; *q; q++)
501 {
502 if (*q == 'e')
503 {
504 q++;
505 if (*q == '+' || *q == '-')
506 q++;
507 t = q;
508 while (*q == '0')
509 q++;
510 if (t != q)
511 {
512 for (;;)
513 {
514 *t = *q;
515 if (*t == 0)
516 break;
517 t++;
518 q++;
519 }
520 }
521 break;
522 }
523 }
524 }
525 string = p[0 .. std.c.string.strlen(p)].dup;
526 }
527 //writefln("string = '%s'", string);
528 return string;
529 }
530 case V_STRING:
531 return string;
532 case V_OBJECT:
533 { Value val;
534 Value* v = &val;
535 void* a;
536
537 //writef("Vobject.toString()\n");
538 a = toPrimitive(v, TypeString);
539 //assert(!a);
540 if (v.isPrimitive())
541 return v.toString();
542 else
543 return v.toObject().classname;
544 }
545 default:
546 assert(0);
547 }
548 assert(0);
549 }
550
551 d_string toLocaleString()
552 {
553 return toString();
554 }
555
556 d_string toString(int radix)
557 {
558 if (vtype == V_NUMBER)
559 {
560 assert(2 <= radix && radix <= 36);
561 return std.string.toString(cast(long)number, cast(uint)radix);
562 }
563 else
564 {
565 return toString();
566 }
567 }
568
569 d_string toSource()
570 {
571 switch (vtype)
572 {
573 case V_STRING:
574 { d_string s;
575
576 s = "\"" ~ string ~ "\"";
577 return s;
578 }
579 case V_OBJECT:
580 { Value* v;
581
582 //writefln("Vobject.toSource()");
583 v = Get(TEXT_toSource);
584 if (!v)
585 v = &vundefined;
586 if (v.isPrimitive())
587 return v.toSource();
588 else // it's an Object
589 { void* a;
590 CallContext *cc;
591 Dobject o;
592 Value* ret;
593 Value val;
594
595 o = v.object;
596 cc = Program.getProgram().callcontext;
597 ret = &val;
598 a = o.Call(cc, this.object, ret, null);
599 if (a) // if exception was thrown
600 {
601 /*return a*/;
602 writef("Vobject.toSource() failed with %x\n", a);
603 }
604 else if (ret.isPrimitive())
605 return ret.toString();
606 }
607 return TEXT_undefined;
608 }
609 default:
610 return toString();
611 }
612 assert(0);
613 }
614
615 Dobject toObject()
616 {
617 switch (vtype)
618 {
619 case V_UNDEFINED:
620 //RuntimeErrorx("cannot convert undefined to Object");
621 return null;
622 case V_NULL:
623 //RuntimeErrorx("cannot convert null to Object");
624 return null;
625 case V_BOOLEAN:
626 return new Dboolean(dbool);
627 case V_NUMBER:
628 return new Dnumber(number);
629 case V_STRING:
630 return new Dstring(string);
631 case V_OBJECT:
632 return object;
633 default:
634 assert(0);
635 }
636 assert(0);
637 }
638
639 int opEquals(Value* v)
640 {
641 return (opCmp(v) == 0);
642 }
643
644 /*********************************
645 * Use this instead of std.string.cmp() because
646 * we don't care about lexicographic ordering.
647 * This is faster.
648 */
649
650 static int stringcmp(d_string s1, d_string s2)
651 {
652 int c = s1.length - s2.length;
653 if (c == 0)
654 {
655 if (s1.ptr == s2.ptr)
656 return 0;
657 c = memcmp(s1.ptr, s2.ptr, s1.length);
658 }
659 return c;
660 }
661
662 int opCmp(Value* v)
663 {
664 switch (vtype)
665 {
666 case V_UNDEFINED:
667 if (vtype == v.vtype)
668 return 0;
669 break;
670 case V_NULL:
671 if (vtype == v.vtype)
672 return 0;
673 break;
674 case V_BOOLEAN:
675 if (vtype == v.vtype)
676 return v.dbool - dbool;
677 break;
678 case V_NUMBER:
679 if (v.vtype == V_NUMBER)
680 {
681 if (number == v.number)
682 return 0;
683 if (isnan(number) && isnan(v.number))
684 return 0;
685 if (number > v.number)
686 return 1;
687 }
688 else if (v.vtype == V_STRING)
689 {
690 return stringcmp(toString(), v.string);
691 }
692 break;
693 case V_STRING:
694 if (v.vtype == V_STRING)
695 {
696 //writefln("'%s'.compareTo('%s')", string, v.string);
697 int len = string.length - v.string.length;
698 if (len == 0)
699 {
700 if (string.ptr == v.string.ptr)
701 return 0;
702 len = memcmp(string.ptr, v.string.ptr, string.length);
703 }
704 return len;
705 }
706 else if (v.vtype == V_NUMBER)
707 {
708 //writefln("'%s'.compareTo(%g)\n", string, v.number);
709 return stringcmp(string, v.toString());
710 }
711 break;
712 case V_OBJECT:
713 if (v.object == object)
714 return 0;
715 break;
716 default:
717 assert(0);
718 }
719 return -1;
720 }
721
722 void copyTo(Value* v)
723 { // Copy everything, including vptr
724 copy(this, v);
725 }
726
727 tchar[] getType()
728 { tchar[] s;
729
730 switch (vtype)
731 {
732 case V_UNDEFINED: s = TypeUndefined; break;
733 case V_NULL: s = TypeNull; break;
734 case V_BOOLEAN: s = TypeBoolean; break;
735 case V_NUMBER: s = TypeNumber; break;
736 case V_STRING: s = TypeString; break;
737 case V_OBJECT: s = TypeObject; break;
738 case V_ITER: s = TypeIterator; break;
739 default:
740 writefln("vtype = %d", vtype);
741 assert(0);
742 }
743 return s;
744 }
745
746 d_string getTypeof()
747 { tchar[] s;
748
749 switch (vtype)
750 {
751 case V_UNDEFINED: s = TEXT_undefined; break;
752 case V_NULL: s = TEXT_object; break;
753 case V_BOOLEAN: s = TEXT_boolean; break;
754 case V_NUMBER: s = TEXT_number; break;
755 case V_STRING: s = TEXT_string; break;
756 case V_OBJECT: s = object.getTypeof(); break;
757 default:
758 writefln("vtype = %d", vtype);
759 assert(0);
760 }
761 return s;
762 }
763
764 int isUndefined() { return vtype == V_UNDEFINED; }
765 int isNull() { return vtype == V_NULL; }
766 int isBoolean() { return vtype == V_BOOLEAN; }
767 int isNumber() { return vtype == V_NUMBER; }
768 int isString() { return vtype == V_STRING; }
769 int isObject() { return vtype == V_OBJECT; }
770 int isIterator() { return vtype == V_ITER; }
771
772 int isUndefinedOrNull() { return vtype == V_UNDEFINED || vtype == V_NULL; }
773
774 int isPrimitive() { return vtype != V_OBJECT; }
775
776 int isArrayIndex(out d_uint32 index)
777 {
778 switch (vtype)
779 {
780 case V_NUMBER:
781 index = toUint32();
782 return true;
783 case V_STRING:
784 return StringToIndex(string, index);
785 default:
786 index = 0;
787 return false;
788 }
789 assert(0);
790 }
791
792 static uint calcHash(uint u)
793 {
794 return u ^ 0x55555555;
795 }
796
797 static uint calcHash(double d)
798 {
799 return calcHash(cast(uint) d);
800 }
801
802 static uint calcHash(d_string s)
803 {
804 uint hash;
805
806 /* If it looks like an array index, hash it to the
807 * same value as if it was an array index.
808 * This means that "1234" hashes to the same value as 1234.
809 */
810 hash = 0;
811 foreach (tchar c; s)
812 {
813 switch (c)
814 {
815 case '0': hash *= 10; break;
816 case '1': hash = hash * 10 + 1; break;
817
818 case '2':
819 case '3':
820 case '4':
821 case '5':
822 case '6':
823 case '7':
824 case '8':
825 case '9':
826 hash = hash * 10 + (c - '0');
827 break;
828
829 default:
830 { uint len = s.length;
831 ubyte *str = cast(ubyte*)s.ptr;
832
833 hash = 0;
834 while (1)
835 {
836 switch (len)
837 {
838 case 0:
839 break;
840
841 case 1:
842 hash *= 9;
843 hash += *cast(ubyte *)str;
844 break;
845
846 case 2:
847 hash *= 9;
848 hash += *cast(ushort *)str;
849 break;
850
851 case 3:
852 hash *= 9;
853 hash += (*cast(ushort *)str << 8) +
854 (cast(ubyte *)str)[2];
855 break;
856
857 default:
858 hash *= 9;
859 hash += *cast(uint *)str;
860 str += 4;
861 len -= 4;
862 continue;
863 }
864 break;
865 }
866 break;
867 }
868 // return s.hash;
869 }
870 }
871 return calcHash(hash);
872 }
873
874 uint toHash()
875 { uint h;
876
877 switch (vtype)
878 {
879 case V_UNDEFINED:
880 case V_NULL:
881 h = 0;
882 break;
883 case V_BOOLEAN:
884 h = dbool ? 1 : 0;
885 break;
886 case V_NUMBER:
887 h = calcHash(number);
888 break;
889 case V_STRING:
890 // Since strings are immutable, if we've already
891 // computed the hash, use previous value
892 if (!hash)
893 hash = calcHash(string);
894 h = hash;
895 break;
896 case V_OBJECT:
897 /* Uses the address of the object as the hash.
898 * Since the object never moves, it will work
899 * as its hash.
900 * BUG: shouldn't do this.
901 */
902 h = cast(uint)cast(void*) object;
903 break;
904 default:
905 assert(0);
906 }
907 //writefln("\tValue.toHash() = %x", h);
908 return h;
909 }
910
911 Value* Put(d_string PropertyName, Value* value)
912 {
913 if (vtype == V_OBJECT)
914 return object.Put(PropertyName, value, 0);
915 else
916 {
917 ErrInfo errinfo;
918
919 return Dobject.RuntimeError(&errinfo,
920 errmsgtbl[ERR_CANNOT_PUT_TO_PRIMITIVE],
921 PropertyName, value.toString(),
922 getType());
923 }
924 }
925
926 Value* Put(d_uint32 index, Value* vindex, Value* value)
927 {
928 if (vtype == V_OBJECT)
929 return object.Put(index, vindex, value, 0);
930 else
931 {
932 ErrInfo errinfo;
933
934 return Dobject.RuntimeError(&errinfo,
935 errmsgtbl[ERR_CANNOT_PUT_INDEX_TO_PRIMITIVE],
936 index,
937 value.toString(), getType());
938 }
939 }
940
941 Value* Get(d_string PropertyName)
942 {
943 if (vtype == V_OBJECT)
944 return object.Get(PropertyName);
945 else
946 {
947 // Should we generate the error, or just return undefined?
948 tchar[] msg;
949
950 msg = std.string.format(errmsgtbl[ERR_CANNOT_GET_FROM_PRIMITIVE],
951 PropertyName, getType(), toString());
952 throw new ScriptException(msg);
953 //return &vundefined;
954 }
955 }
956
957 Value* Get(d_uint32 index)
958 {
959 if (vtype == V_OBJECT)
960 return object.Get(index);
961 else
962 {
963 // Should we generate the error, or just return undefined?
964 tchar[] msg;
965
966 msg = std.string.format(errmsgtbl[ERR_CANNOT_GET_INDEX_FROM_PRIMITIVE],
967 index, getType(), toString());
968 throw new ScriptException(msg);
969 //return &vundefined;
970 }
971 }
972
973 Value* Get(Identifier *id)
974 {
975 if (vtype == V_OBJECT)
976 return object.Get(id);
977 else
978 {
979 // Should we generate the error, or just return undefined?
980 tchar[] msg;
981
982 msg = std.string.format(errmsgtbl[ERR_CANNOT_GET_FROM_PRIMITIVE],
983 id.toString(), getType(), toString());
984 throw new ScriptException(msg);
985 //return &vundefined;
986 }
987 }
988 /+
989 Value* Get(d_string PropertyName, uint hash)
990 {
991 if (vtype == V_OBJECT)
992 return object.Get(PropertyName, hash);
993 else
994 {
995 // Should we generate the error, or just return undefined?
996 tchar[] msg;
997
998 msg = std.string.format(errmsgtbl[ERR_CANNOT_GET_FROM_PRIMITIVE],
999 PropertyName, getType(), toString());
1000 throw new ScriptException(msg);
1001 //return &vundefined;
1002 }
1003 }
1004 +/
1005 void* Construct(CallContext *cc, Value *ret, Value[] arglist)
1006 {
1007 if (vtype == V_OBJECT)
1008 return object.Construct(cc, ret, arglist);
1009 else
1010 {
1011 ErrInfo errinfo;
1012 ret.putVundefined();
1013 return Dobject.RuntimeError(&errinfo,
1014 errmsgtbl[ERR_PRIMITIVE_NO_CONSTRUCT], getType());
1015 }
1016 }
1017
1018 void* Call(CallContext *cc, Dobject othis, Value* ret, Value[] arglist)
1019 {
1020 if (vtype == V_OBJECT)
1021 {
1022 void* a;
1023
1024 a = object.Call(cc, othis, ret, arglist);
1025 //if (a) writef("Vobject.Call() returned %x\n", a);
1026 return a;
1027 }
1028 else
1029 {
1030 ErrInfo errinfo;
1031 //PRINTF("Call method not implemented for primitive %p (%s)\n", this, d_string_ptr(toString()));
1032 ret.putVundefined();
1033 return Dobject.RuntimeError(&errinfo,
1034 errmsgtbl[ERR_PRIMITIVE_NO_CALL], getType());
1035 }
1036 }
1037
1038 Value* putIterator(Value* v)
1039 {
1040 if (vtype == V_OBJECT)
1041 return object.putIterator(v);
1042 else
1043 {
1044 ErrInfo errinfo;
1045 v.putVundefined();
1046 return Dobject.RuntimeError(&errinfo,
1047 errmsgtbl[ERR_FOR_IN_MUST_BE_OBJECT]);
1048 }
1049 }
1050
1051
1052 void getErrInfo(ErrInfo *perrinfo, int linnum)
1053 {
1054 if (vtype == V_OBJECT)
1055 object.getErrInfo(perrinfo, linnum);
1056 else
1057 {
1058 ErrInfo errinfo;
1059
1060 if (linnum && errinfo.linnum == 0)
1061 errinfo.linnum = linnum;
1062 errinfo.message = "Unhandled exception: " ~ toString();
1063 if (perrinfo)
1064 *perrinfo = errinfo;
1065 }
1066 }
1067
1068 void dump()
1069 { uint *v = cast(uint *)this;
1070
1071 writef("v[%x] = %8x, %8x, %8x, %8x\n", cast(uint)v, v[0], v[1], v[2], v[3]);
1072 }
1073 }
1074
1075 static assert(Value.sizeof == 16);
1076
1077 Value vundefined = { V_UNDEFINED };
1078 Value vnull = { V_NULL };
1079
1080 tchar[] TypeUndefined = "Undefined";
1081 tchar[] TypeNull = "Null";
1082 tchar[] TypeBoolean = "Boolean";
1083 tchar[] TypeNumber = "Number";
1084 tchar[] TypeString = "String";
1085 tchar[] TypeObject = "Object";
1086
1087 tchar[] TypeIterator = "Iterator";
1088
1089
1090
1091
1092
1093
1094