xref: /inferno-os/appl/lib/ecmascript/obj.b (revision 37da2899f40661e3e9631e497da8dc59b971cbd0)
1*37da2899SCharles.Forsyth#
2*37da2899SCharles.Forsyth# want to use the value in a context which
3*37da2899SCharles.Forsyth# prefers an object, so coerce schizo vals
4*37da2899SCharles.Forsyth# to object versions
5*37da2899SCharles.Forsyth#
6*37da2899SCharles.ForsythcoerceToObj(ex: ref Exec, v: ref Val): ref Val
7*37da2899SCharles.Forsyth{
8*37da2899SCharles.Forsyth	o: ref Obj;
9*37da2899SCharles.Forsyth
10*37da2899SCharles.Forsyth	case v.ty{
11*37da2899SCharles.Forsyth	TBool =>
12*37da2899SCharles.Forsyth		o = mkobj(ex.boolproto, "Boolean");
13*37da2899SCharles.Forsyth		o.val = v;
14*37da2899SCharles.Forsyth	TStr =>
15*37da2899SCharles.Forsyth		o = mkobj(ex.strproto, "String");
16*37da2899SCharles.Forsyth		o.val = v;
17*37da2899SCharles.Forsyth		valinstant(o, DontEnum|DontDelete|ReadOnly, "length", numval(real len v.str));
18*37da2899SCharles.Forsyth	TNum =>
19*37da2899SCharles.Forsyth		o = mkobj(ex.numproto, "Number");
20*37da2899SCharles.Forsyth		o.val = v;
21*37da2899SCharles.Forsyth	TRegExp =>
22*37da2899SCharles.Forsyth		o = mkobj(ex.regexpproto, "RegExp");
23*37da2899SCharles.Forsyth		o.val = v;
24*37da2899SCharles.Forsyth		valinstant(o, DontEnum|DontDelete|ReadOnly, "length", numval(real len v.rev.p));
25*37da2899SCharles.Forsyth		valinstant(o, DontEnum|DontDelete|ReadOnly, "source", strval(v.rev.p));
26*37da2899SCharles.Forsyth		valinstant(o, DontEnum|DontDelete|ReadOnly, "global", strhas(v.rev.f, 'g'));
27*37da2899SCharles.Forsyth		valinstant(o, DontEnum|DontDelete|ReadOnly, "ignoreCase", strhas(v.rev.f, 'i'));
28*37da2899SCharles.Forsyth		valinstant(o, DontEnum|DontDelete|ReadOnly, "multiline", strhas(v.rev.f, 'm'));
29*37da2899SCharles.Forsyth		valinstant(o, DontEnum|DontDelete, "lastIndex", numval(real v.rev.i));
30*37da2899SCharles.Forsyth	* =>
31*37da2899SCharles.Forsyth		return v;
32*37da2899SCharles.Forsyth	}
33*37da2899SCharles.Forsyth	return objval(o);
34*37da2899SCharles.Forsyth}
35*37da2899SCharles.Forsyth
36*37da2899SCharles.ForsythcoerceToVal(v: ref Val): ref Val
37*37da2899SCharles.Forsyth{
38*37da2899SCharles.Forsyth	if(v.ty != TObj)
39*37da2899SCharles.Forsyth		return v;
40*37da2899SCharles.Forsyth	o := v.obj;
41*37da2899SCharles.Forsyth	if(o.host != nil && o.host != me
42*37da2899SCharles.Forsyth	|| o.class != "String"
43*37da2899SCharles.Forsyth	|| o.class != "Number"
44*37da2899SCharles.Forsyth	|| o.class != "Boolean")
45*37da2899SCharles.Forsyth		return v;
46*37da2899SCharles.Forsyth	return o.val;
47*37da2899SCharles.Forsyth}
48*37da2899SCharles.Forsyth
49*37da2899SCharles.Forsythisstrobj(o: ref Obj): int
50*37da2899SCharles.Forsyth{
51*37da2899SCharles.Forsyth	return (o.host == nil || o.host == me) && o.class == "String";
52*37da2899SCharles.Forsyth}
53*37da2899SCharles.Forsyth
54*37da2899SCharles.Forsythisnumobj(o: ref Obj): int
55*37da2899SCharles.Forsyth{
56*37da2899SCharles.Forsyth	return (o.host == nil || o.host == me) && o.class == "Number";
57*37da2899SCharles.Forsyth}
58*37da2899SCharles.Forsyth
59*37da2899SCharles.Forsythisboolobj(o: ref Obj): int
60*37da2899SCharles.Forsyth{
61*37da2899SCharles.Forsyth	return (o.host == nil || o.host == me) && o.class == "Boolean";
62*37da2899SCharles.Forsyth}
63*37da2899SCharles.Forsyth
64*37da2899SCharles.Forsythisdateobj(o: ref Obj): int
65*37da2899SCharles.Forsyth{
66*37da2899SCharles.Forsyth	return (o.host == nil || o.host == me) && o.class == "Date";
67*37da2899SCharles.Forsyth}
68*37da2899SCharles.Forsyth
69*37da2899SCharles.Forsythisregexpobj(o: ref Obj): int
70*37da2899SCharles.Forsyth{
71*37da2899SCharles.Forsyth	return (o.host == nil || o.host == me) && o.class == "RegExp";
72*37da2899SCharles.Forsyth}
73*37da2899SCharles.Forsyth
74*37da2899SCharles.Forsythisfuncobj(o: ref Obj): int
75*37da2899SCharles.Forsyth{
76*37da2899SCharles.Forsyth	return (o.host == nil || o.host == me) && o.class == "Function";
77*37da2899SCharles.Forsyth}
78*37da2899SCharles.Forsyth
79*37da2899SCharles.Forsythisarray(o: ref Obj): int
80*37da2899SCharles.Forsyth{
81*37da2899SCharles.Forsyth#	return (o.host == nil || o.host == me) && o.class == "Array";
82*37da2899SCharles.Forsyth	# relax the host test
83*37da2899SCharles.Forsyth	# so that hosts can intercept Array operations and defer
84*37da2899SCharles.Forsyth	# unhandled ops to the builtin
85*37da2899SCharles.Forsyth	return o.class == "Array";
86*37da2899SCharles.Forsyth}
87*37da2899SCharles.Forsyth
88*37da2899SCharles.Forsythiserr(o: ref Obj): int
89*37da2899SCharles.Forsyth{
90*37da2899SCharles.Forsyth	return (o.host == nil || o.host == me) && o.class == "Error";
91*37da2899SCharles.Forsyth}
92*37da2899SCharles.Forsyth
93*37da2899SCharles.Forsythisactobj(o: ref Obj): int
94*37da2899SCharles.Forsyth{
95*37da2899SCharles.Forsyth	return o.host == nil && o.class == "Activation";
96*37da2899SCharles.Forsyth}
97*37da2899SCharles.Forsyth
98*37da2899SCharles.Forsythisnull(v: ref Val): int
99*37da2899SCharles.Forsyth{
100*37da2899SCharles.Forsyth	return v == null || v == nil;
101*37da2899SCharles.Forsyth}
102*37da2899SCharles.Forsyth
103*37da2899SCharles.Forsythisundefined(v: ref Val): int
104*37da2899SCharles.Forsyth{
105*37da2899SCharles.Forsyth	return v == undefined;
106*37da2899SCharles.Forsyth}
107*37da2899SCharles.Forsyth
108*37da2899SCharles.Forsythisstr(v: ref Val): int
109*37da2899SCharles.Forsyth{
110*37da2899SCharles.Forsyth	return v.ty == TStr;
111*37da2899SCharles.Forsyth}
112*37da2899SCharles.Forsyth
113*37da2899SCharles.Forsythisnum(v: ref Val): int
114*37da2899SCharles.Forsyth{
115*37da2899SCharles.Forsyth	return v.ty == TNum;
116*37da2899SCharles.Forsyth}
117*37da2899SCharles.Forsyth
118*37da2899SCharles.Forsythisbool(v: ref Val): int
119*37da2899SCharles.Forsyth{
120*37da2899SCharles.Forsyth	return v.ty == TBool;
121*37da2899SCharles.Forsyth}
122*37da2899SCharles.Forsyth
123*37da2899SCharles.Forsythisobj(v: ref Val): int
124*37da2899SCharles.Forsyth{
125*37da2899SCharles.Forsyth	return v.ty == TObj;
126*37da2899SCharles.Forsyth}
127*37da2899SCharles.Forsyth
128*37da2899SCharles.Forsythisregexp(v: ref Val): int
129*37da2899SCharles.Forsyth{
130*37da2899SCharles.Forsyth	return v.ty == TRegExp || v.ty == TObj && isregexpobj(v.obj);
131*37da2899SCharles.Forsyth}
132*37da2899SCharles.Forsyth
133*37da2899SCharles.Forsyth#
134*37da2899SCharles.Forsyth# retrieve the object field if it's valid
135*37da2899SCharles.Forsyth#
136*37da2899SCharles.Forsythgetobj(v: ref Val): ref Obj
137*37da2899SCharles.Forsyth{
138*37da2899SCharles.Forsyth	if(v.ty == TObj)
139*37da2899SCharles.Forsyth		return v.obj;
140*37da2899SCharles.Forsyth	return nil;
141*37da2899SCharles.Forsyth}
142*37da2899SCharles.Forsyth
143*37da2899SCharles.Forsythisprimval(v: ref Val): int
144*37da2899SCharles.Forsyth{
145*37da2899SCharles.Forsyth	return v.ty != TObj;
146*37da2899SCharles.Forsyth}
147*37da2899SCharles.Forsyth
148*37da2899SCharles.Forsythpushscope(ex: ref Exec, o: ref Obj)
149*37da2899SCharles.Forsyth{
150*37da2899SCharles.Forsyth	ex.scopechain = o :: ex.scopechain;
151*37da2899SCharles.Forsyth}
152*37da2899SCharles.Forsyth
153*37da2899SCharles.Forsythpopscope(ex: ref Exec)
154*37da2899SCharles.Forsyth{
155*37da2899SCharles.Forsyth	ex.scopechain = tl ex.scopechain;
156*37da2899SCharles.Forsyth}
157*37da2899SCharles.Forsyth
158*37da2899SCharles.Forsythruntime(ex: ref Exec, o: ref Obj, s: string)
159*37da2899SCharles.Forsyth{
160*37da2899SCharles.Forsyth	ex.error = s;
161*37da2899SCharles.Forsyth	if(o == nil)
162*37da2899SCharles.Forsyth		ex.errval = undefined;
163*37da2899SCharles.Forsyth	else
164*37da2899SCharles.Forsyth		ex.errval = objval(o);
165*37da2899SCharles.Forsyth	if(debug['r']){
166*37da2899SCharles.Forsyth		print("ecmascript runtime error: %s\n", s);
167*37da2899SCharles.Forsyth		if(""[5] == -1);	# abort
168*37da2899SCharles.Forsyth	}
169*37da2899SCharles.Forsyth	raise "throw";
170*37da2899SCharles.Forsyth	exit;	# never reached
171*37da2899SCharles.Forsyth}
172*37da2899SCharles.Forsyth
173*37da2899SCharles.Forsythmkobj(proto: ref Obj, class: string): ref Obj
174*37da2899SCharles.Forsyth{
175*37da2899SCharles.Forsyth	if(class == nil)
176*37da2899SCharles.Forsyth		class = "Object";
177*37da2899SCharles.Forsyth	return ref Obj(nil, proto, nil, nil, nil, class, nil, nil);
178*37da2899SCharles.Forsyth}
179*37da2899SCharles.Forsyth
180*37da2899SCharles.Forsythvalcheck(ex: ref Exec, v: ref Val, hint: int)
181*37da2899SCharles.Forsyth{
182*37da2899SCharles.Forsyth	if(v == nil
183*37da2899SCharles.Forsyth	|| v.ty < 0
184*37da2899SCharles.Forsyth	|| v.ty >= NoHint
185*37da2899SCharles.Forsyth	|| v.ty == TBool && v != true && v != false
186*37da2899SCharles.Forsyth	|| v.ty == TObj && v.obj == nil
187*37da2899SCharles.Forsyth	|| hint != NoHint && v.ty != hint)
188*37da2899SCharles.Forsyth		runtime(ex, RangeError, "bad value generated by host object");
189*37da2899SCharles.Forsyth}
190*37da2899SCharles.Forsyth
191*37da2899SCharles.Forsyth# builtin methods for properties
192*37da2899SCharles.Forsythesget(ex: ref Exec, o: ref Obj, prop: string, force: int): ref Val
193*37da2899SCharles.Forsyth{
194*37da2899SCharles.Forsyth	for( ; o != nil; o = o.prototype){
195*37da2899SCharles.Forsyth		if(!force && o.host != nil && o.host != me){
196*37da2899SCharles.Forsyth			v := o.host->get(ex, o, prop);
197*37da2899SCharles.Forsyth			valcheck(ex, v, NoHint);
198*37da2899SCharles.Forsyth			return v;
199*37da2899SCharles.Forsyth		}
200*37da2899SCharles.Forsyth
201*37da2899SCharles.Forsyth		for(i := 0; i < len o.props; i++)
202*37da2899SCharles.Forsyth			if(o.props[i] != nil && o.props[i].name == prop)
203*37da2899SCharles.Forsyth				return o.props[i].val.val;
204*37da2899SCharles.Forsyth		force = 0;
205*37da2899SCharles.Forsyth	}
206*37da2899SCharles.Forsyth	return undefined;
207*37da2899SCharles.Forsyth}
208*37da2899SCharles.Forsyth
209*37da2899SCharles.Forsythesputind(o: ref Obj, prop: string): int
210*37da2899SCharles.Forsyth{
211*37da2899SCharles.Forsyth	empty := -1;
212*37da2899SCharles.Forsyth	props := o.props;
213*37da2899SCharles.Forsyth	for(i := 0; i < len props; i++){
214*37da2899SCharles.Forsyth		if(props[i] == nil)
215*37da2899SCharles.Forsyth			empty = i;
216*37da2899SCharles.Forsyth		else if(props[i].name == prop)
217*37da2899SCharles.Forsyth			return i;
218*37da2899SCharles.Forsyth	}
219*37da2899SCharles.Forsyth	if(empty != -1)
220*37da2899SCharles.Forsyth		return empty;
221*37da2899SCharles.Forsyth
222*37da2899SCharles.Forsyth	props = array[i+1] of ref Prop;
223*37da2899SCharles.Forsyth	props[:] = o.props;
224*37da2899SCharles.Forsyth	o.props = props;
225*37da2899SCharles.Forsyth	return i;
226*37da2899SCharles.Forsyth}
227*37da2899SCharles.Forsyth
228*37da2899SCharles.Forsythesput(ex: ref Exec, o: ref Obj, prop: string, v: ref Val, force: int)
229*37da2899SCharles.Forsyth{
230*37da2899SCharles.Forsyth	ai: big;
231*37da2899SCharles.Forsyth
232*37da2899SCharles.Forsyth	if(!force && o.host != nil && o.host != me)
233*37da2899SCharles.Forsyth		return o.host->put(ex, o, prop, v);
234*37da2899SCharles.Forsyth
235*37da2899SCharles.Forsyth	if(escanput(ex, o, prop, 0) != true)
236*37da2899SCharles.Forsyth		return;
237*37da2899SCharles.Forsyth
238*37da2899SCharles.Forsyth	#
239*37da2899SCharles.Forsyth	# should this test for prototype == ex.arrayproto?
240*37da2899SCharles.Forsyth	# hard to say, but 15.4.5 "Properties of Array Instances" implies not
241*37da2899SCharles.Forsyth	#
242*37da2899SCharles.Forsyth	if(isarray(o))
243*37da2899SCharles.Forsyth		al := toUint32(ex, esget(ex, o, "length", 1));
244*37da2899SCharles.Forsyth
245*37da2899SCharles.Forsyth	i := esputind(o, prop);
246*37da2899SCharles.Forsyth	props := o.props;
247*37da2899SCharles.Forsyth	if(props[i] != nil)
248*37da2899SCharles.Forsyth		props[i].val.val = v;
249*37da2899SCharles.Forsyth	else
250*37da2899SCharles.Forsyth		props[i] = ref Prop(0, prop, ref RefVal(v));
251*37da2899SCharles.Forsyth	if(!isarray(o))
252*37da2899SCharles.Forsyth		return;
253*37da2899SCharles.Forsyth
254*37da2899SCharles.Forsyth	if(prop == "length"){
255*37da2899SCharles.Forsyth		nl := toUint32(ex, v);
256*37da2899SCharles.Forsyth		for(ai = nl; ai < al; ai++)
257*37da2899SCharles.Forsyth			esdelete(ex, o, string ai, 1);
258*37da2899SCharles.Forsyth		props[i].val.val = numval(real nl);
259*37da2899SCharles.Forsyth	}else{
260*37da2899SCharles.Forsyth		ai = big prop;
261*37da2899SCharles.Forsyth		if(prop != string ai || ai < big 0 || ai >= 16rffffffff)
262*37da2899SCharles.Forsyth			return;
263*37da2899SCharles.Forsyth		i = esputind(o, "length");
264*37da2899SCharles.Forsyth		if(props[i] == nil)
265*37da2899SCharles.Forsyth			fatal(ex, "bogus array esput");
266*37da2899SCharles.Forsyth		else if(toUint32(ex, props[i].val.val) <= ai)
267*37da2899SCharles.Forsyth			props[i].val.val = numval(real(ai+big 1));
268*37da2899SCharles.Forsyth	}
269*37da2899SCharles.Forsyth}
270*37da2899SCharles.Forsyth
271*37da2899SCharles.Forsythescanput(ex: ref Exec, o: ref Obj, prop: string, force: int): ref Val
272*37da2899SCharles.Forsyth{
273*37da2899SCharles.Forsyth	for( ; o != nil; o = o.prototype){
274*37da2899SCharles.Forsyth		if(!force && o.host != nil && o.host != me){
275*37da2899SCharles.Forsyth			v := o.host->canput(ex, o, prop);
276*37da2899SCharles.Forsyth			valcheck(ex, v, TBool);
277*37da2899SCharles.Forsyth			return v;
278*37da2899SCharles.Forsyth		}
279*37da2899SCharles.Forsyth
280*37da2899SCharles.Forsyth		for(i := 0; i < len o.props; i++){
281*37da2899SCharles.Forsyth			if(o.props[i] != nil && o.props[i].name == prop){
282*37da2899SCharles.Forsyth				if(o.props[i].attr & ReadOnly)
283*37da2899SCharles.Forsyth					return false;
284*37da2899SCharles.Forsyth				else
285*37da2899SCharles.Forsyth					return true;
286*37da2899SCharles.Forsyth			}
287*37da2899SCharles.Forsyth		}
288*37da2899SCharles.Forsyth
289*37da2899SCharles.Forsyth		force = 0;
290*37da2899SCharles.Forsyth	}
291*37da2899SCharles.Forsyth	return true;
292*37da2899SCharles.Forsyth}
293*37da2899SCharles.Forsyth
294*37da2899SCharles.Forsytheshasproperty(ex: ref Exec, o: ref Obj, prop: string, force: int): ref Val
295*37da2899SCharles.Forsyth{
296*37da2899SCharles.Forsyth	for(; o != nil; o = o.prototype){
297*37da2899SCharles.Forsyth		if(!force && o.host != nil && o.host != me){
298*37da2899SCharles.Forsyth			v := o.host->hasproperty(ex, o, prop);
299*37da2899SCharles.Forsyth			valcheck(ex, v, TBool);
300*37da2899SCharles.Forsyth			return v;
301*37da2899SCharles.Forsyth		}
302*37da2899SCharles.Forsyth		for(i := 0; i < len o.props; i++)
303*37da2899SCharles.Forsyth			if(o.props[i] != nil && o.props[i].name == prop)
304*37da2899SCharles.Forsyth				return true;
305*37da2899SCharles.Forsyth	}
306*37da2899SCharles.Forsyth	return false;
307*37da2899SCharles.Forsyth}
308*37da2899SCharles.Forsyth
309*37da2899SCharles.Forsytheshasenumprop(o: ref Obj, prop: string): ref Val
310*37da2899SCharles.Forsyth{
311*37da2899SCharles.Forsyth	for(i := 0; i < len o.props; i++)
312*37da2899SCharles.Forsyth		if(o.props[i] != nil && o.props[i].name == prop){
313*37da2899SCharles.Forsyth			if(o.props[i].attr & DontEnum)
314*37da2899SCharles.Forsyth				return false;
315*37da2899SCharles.Forsyth			return true;
316*37da2899SCharles.Forsyth		}
317*37da2899SCharles.Forsyth	return false;
318*37da2899SCharles.Forsyth}
319*37da2899SCharles.Forsyth
320*37da2899SCharles.Forsythpropshadowed(start, end: ref Obj, prop: string): int
321*37da2899SCharles.Forsyth{
322*37da2899SCharles.Forsyth	for(o := start; o != end; o = o.prototype){
323*37da2899SCharles.Forsyth		if(o.host != nil && o.host != me)
324*37da2899SCharles.Forsyth			return 0;
325*37da2899SCharles.Forsyth		for(i := 0; i < len o.props; i++)
326*37da2899SCharles.Forsyth			if(o.props[i] != nil && o.props[i].name == prop)
327*37da2899SCharles.Forsyth				return 1;
328*37da2899SCharles.Forsyth	}
329*37da2899SCharles.Forsyth	return 0;
330*37da2899SCharles.Forsyth}
331*37da2899SCharles.Forsyth
332*37da2899SCharles.Forsythesdelete(ex: ref Exec, o: ref Obj, prop: string, force: int)
333*37da2899SCharles.Forsyth{
334*37da2899SCharles.Forsyth	if(!force && o.host != nil && o.host != me)
335*37da2899SCharles.Forsyth		return o.host->delete(ex, o, prop);
336*37da2899SCharles.Forsyth
337*37da2899SCharles.Forsyth	for(i := 0; i < len o.props; i++){
338*37da2899SCharles.Forsyth		if(o.props[i] != nil && o.props[i].name == prop){
339*37da2899SCharles.Forsyth			if(!(o.props[i].attr & DontDelete))
340*37da2899SCharles.Forsyth				o.props[i] = nil;
341*37da2899SCharles.Forsyth			return;
342*37da2899SCharles.Forsyth		}
343*37da2899SCharles.Forsyth	}
344*37da2899SCharles.Forsyth}
345*37da2899SCharles.Forsyth
346*37da2899SCharles.Forsythesdeforder := array[] of {"valueOf", "toString"};
347*37da2899SCharles.Forsythesdefaultval(ex: ref Exec, o: ref Obj, ty: int, force: int): ref Val
348*37da2899SCharles.Forsyth{
349*37da2899SCharles.Forsyth	v: ref Val;
350*37da2899SCharles.Forsyth
351*37da2899SCharles.Forsyth	if(!force && o.host != nil && o.host != me){
352*37da2899SCharles.Forsyth		v = o.host->defaultval(ex, o, ty);
353*37da2899SCharles.Forsyth		valcheck(ex, v, NoHint);
354*37da2899SCharles.Forsyth		if(!isprimval(v))
355*37da2899SCharles.Forsyth			runtime(ex, TypeError, "host object returned an object to [[DefaultValue]]");
356*37da2899SCharles.Forsyth		return v;
357*37da2899SCharles.Forsyth	}
358*37da2899SCharles.Forsyth
359*37da2899SCharles.Forsyth	hintstr := 0;
360*37da2899SCharles.Forsyth	if(ty == TStr || ty == NoHint && isdateobj(o))
361*37da2899SCharles.Forsyth		hintstr = 1;
362*37da2899SCharles.Forsyth
363*37da2899SCharles.Forsyth	for(i := 0; i < 2; i++){
364*37da2899SCharles.Forsyth		v = esget(ex, o, esdeforder[hintstr ^ i], 0);
365*37da2899SCharles.Forsyth		if(v != undefined && v.ty == TObj && v.obj.call != nil){
366*37da2899SCharles.Forsyth			r := escall(ex, v.obj, o, nil, 0);
367*37da2899SCharles.Forsyth			v = nil;
368*37da2899SCharles.Forsyth			if(!r.isref)
369*37da2899SCharles.Forsyth				v = r.val;
370*37da2899SCharles.Forsyth			if(v != nil && isprimval(v))
371*37da2899SCharles.Forsyth				return v;
372*37da2899SCharles.Forsyth		}
373*37da2899SCharles.Forsyth	}
374*37da2899SCharles.Forsyth	runtime(ex, TypeError, "no default value");
375*37da2899SCharles.Forsyth	return nil;
376*37da2899SCharles.Forsyth}
377*37da2899SCharles.Forsyth
378*37da2899SCharles.Forsythesprimid(ex: ref Exec, s: string): ref Ref
379*37da2899SCharles.Forsyth{
380*37da2899SCharles.Forsyth	for(sc := ex.scopechain; sc != nil; sc = tl sc){
381*37da2899SCharles.Forsyth		o := hd sc;
382*37da2899SCharles.Forsyth		if(eshasproperty(ex, o, s, 0) == true)
383*37da2899SCharles.Forsyth			return ref Ref(1, nil, o, s);
384*37da2899SCharles.Forsyth	}
385*37da2899SCharles.Forsyth
386*37da2899SCharles.Forsyth	#
387*37da2899SCharles.Forsyth	# the right place to add literals?
388*37da2899SCharles.Forsyth	#
389*37da2899SCharles.Forsyth	case s{
390*37da2899SCharles.Forsyth	"null" =>
391*37da2899SCharles.Forsyth		return ref Ref(0, null, nil, "null");
392*37da2899SCharles.Forsyth	"true" =>
393*37da2899SCharles.Forsyth		return ref Ref(0, true, nil, "true");
394*37da2899SCharles.Forsyth	"false" =>
395*37da2899SCharles.Forsyth		return ref Ref(0, false, nil, "false");
396*37da2899SCharles.Forsyth	}
397*37da2899SCharles.Forsyth	return ref Ref(1, nil, nil, s);
398*37da2899SCharles.Forsyth}
399*37da2899SCharles.Forsyth
400*37da2899SCharles.Forsythbivar(ex: ref Exec, sc: list of ref Obj, s: string): ref Val
401*37da2899SCharles.Forsyth{
402*37da2899SCharles.Forsyth	for(; sc != nil; sc = tl sc){
403*37da2899SCharles.Forsyth		o := hd sc;
404*37da2899SCharles.Forsyth		if(eshasproperty(ex, o, s, 0) == true)
405*37da2899SCharles.Forsyth			return esget(ex, o, s, 0);
406*37da2899SCharles.Forsyth	}
407*37da2899SCharles.Forsyth	return nil;
408*37da2899SCharles.Forsyth}
409*37da2899SCharles.Forsyth
410*37da2899SCharles.Forsythesconstruct(ex: ref Exec, func: ref Obj, args: array of ref Val): ref Obj
411*37da2899SCharles.Forsyth{
412*37da2899SCharles.Forsyth	o: ref Obj;
413*37da2899SCharles.Forsyth
414*37da2899SCharles.Forsyth	if(func.construct == nil)
415*37da2899SCharles.Forsyth		runtime(ex, TypeError, "new must be applied to a constructor object");
416*37da2899SCharles.Forsyth	if(func.host != nil)
417*37da2899SCharles.Forsyth		o = func.host->construct(ex, func, args);
418*37da2899SCharles.Forsyth	else{
419*37da2899SCharles.Forsyth		o = getobj(esget(ex, func, "prototype", 0));
420*37da2899SCharles.Forsyth		if(o == nil)
421*37da2899SCharles.Forsyth			o = ex.objproto;
422*37da2899SCharles.Forsyth		this := mkobj(o, "Object");
423*37da2899SCharles.Forsyth		o = getobj(getValue(ex, escall(ex, func, this, args, 0)));
424*37da2899SCharles.Forsyth
425*37da2899SCharles.Forsyth		# Divergence from ECMA-262
426*37da2899SCharles.Forsyth		#
427*37da2899SCharles.Forsyth		# observed that not all script-defined constructors return an object,
428*37da2899SCharles.Forsyth		# the value of 'this' is assumed to be the value of the constructor
429*37da2899SCharles.Forsyth		if (o == nil)
430*37da2899SCharles.Forsyth			o = this;
431*37da2899SCharles.Forsyth	}
432*37da2899SCharles.Forsyth	if(o == nil)
433*37da2899SCharles.Forsyth		runtime(ex, TypeError, func.val.str+" failed to generate an object");
434*37da2899SCharles.Forsyth	return o;
435*37da2899SCharles.Forsyth}
436*37da2899SCharles.Forsyth
437*37da2899SCharles.Forsythescall(ex: ref Exec, func, this: ref Obj, args: array of ref Val, eval: int): ref Ref
438*37da2899SCharles.Forsyth{
439*37da2899SCharles.Forsyth	if(func.call == nil)
440*37da2899SCharles.Forsyth		runtime(ex, TypeError, "can only call function objects");
441*37da2899SCharles.Forsyth	if(this == nil)
442*37da2899SCharles.Forsyth		this = ex.global;
443*37da2899SCharles.Forsyth
444*37da2899SCharles.Forsyth	r: ref Ref = nil;
445*37da2899SCharles.Forsyth	if(func.host != nil){
446*37da2899SCharles.Forsyth		r = func.host->call(ex, func, this, args, 0);
447*37da2899SCharles.Forsyth		if(r.isref && r.name == nil)
448*37da2899SCharles.Forsyth			runtime(ex, ReferenceError, "host call returned a bad reference");
449*37da2899SCharles.Forsyth		else if(!r.isref)
450*37da2899SCharles.Forsyth			valcheck(ex, r.val, NoHint);
451*37da2899SCharles.Forsyth		return r;
452*37da2899SCharles.Forsyth	}
453*37da2899SCharles.Forsyth
454*37da2899SCharles.Forsyth	argobj := mkobj(ex.objproto, "Object");
455*37da2899SCharles.Forsyth	actobj := mkobj(nil, "Activation");
456*37da2899SCharles.Forsyth
457*37da2899SCharles.Forsyth	oargs: ref RefVal = nil;
458*37da2899SCharles.Forsyth	props := func.props;
459*37da2899SCharles.Forsyth	empty := -1;
460*37da2899SCharles.Forsyth	i := 0;
461*37da2899SCharles.Forsyth	for(i = 0; i < len props; i++){
462*37da2899SCharles.Forsyth		if(props[i] == nil)
463*37da2899SCharles.Forsyth			empty = i;
464*37da2899SCharles.Forsyth		else if(props[i].name == "arguments"){
465*37da2899SCharles.Forsyth			oargs = props[i].val;
466*37da2899SCharles.Forsyth			empty = i;
467*37da2899SCharles.Forsyth			break;
468*37da2899SCharles.Forsyth		}
469*37da2899SCharles.Forsyth	}
470*37da2899SCharles.Forsyth	if(i == len func.props){
471*37da2899SCharles.Forsyth		if(empty == -1){
472*37da2899SCharles.Forsyth			props = array[i+1] of ref Prop;
473*37da2899SCharles.Forsyth			props[:] = func.props;
474*37da2899SCharles.Forsyth			func.props = props;
475*37da2899SCharles.Forsyth			empty = i;
476*37da2899SCharles.Forsyth		}
477*37da2899SCharles.Forsyth		props[empty] = ref Prop(DontDelete|DontEnum|ReadOnly, "arguments", nil);
478*37da2899SCharles.Forsyth	}
479*37da2899SCharles.Forsyth	props[empty].val = ref RefVal(objval(argobj));
480*37da2899SCharles.Forsyth
481*37da2899SCharles.Forsyth	#
482*37da2899SCharles.Forsyth	#see section 10.1.3 page 33
483*37da2899SCharles.Forsyth	# if multiple params share the same name, the last one takes effect
484*37da2899SCharles.Forsyth	# vars don't override params of the same name, or earlier parms defs
485*37da2899SCharles.Forsyth	#
486*37da2899SCharles.Forsyth	actobj.props = array[] of {ref Prop(DontDelete, "arguments", ref RefVal(objval(argobj)))};
487*37da2899SCharles.Forsyth
488*37da2899SCharles.Forsyth	argobj.props = array[len args + 2] of {
489*37da2899SCharles.Forsyth		ref Prop(DontEnum, "callee", ref RefVal(objval(func))),
490*37da2899SCharles.Forsyth		ref Prop(DontEnum, "length", ref RefVal(numval(real len args))),
491*37da2899SCharles.Forsyth	};
492*37da2899SCharles.Forsyth
493*37da2899SCharles.Forsyth	#
494*37da2899SCharles.Forsyth	# instantiate the arguments by name in the activation object
495*37da2899SCharles.Forsyth	# and by number in the arguments object, aliased to the same RefVal.
496*37da2899SCharles.Forsyth	#
497*37da2899SCharles.Forsyth	params := func.call.params;
498*37da2899SCharles.Forsyth	for(i = 0; i < len args; i++){
499*37da2899SCharles.Forsyth		rjv := ref RefVal(args[i]);
500*37da2899SCharles.Forsyth		argobj.props[i+2] = ref Prop(DontEnum, string i, rjv);
501*37da2899SCharles.Forsyth		if(i < len params)
502*37da2899SCharles.Forsyth			fvarinstant(actobj, 1, DontDelete, params[i], rjv);
503*37da2899SCharles.Forsyth	}
504*37da2899SCharles.Forsyth	for(; i < len params; i++)
505*37da2899SCharles.Forsyth		fvarinstant(actobj, 1, DontDelete, params[i], ref RefVal(undefined));
506*37da2899SCharles.Forsyth
507*37da2899SCharles.Forsyth	#
508*37da2899SCharles.Forsyth	# instantiate the local variables defined within the function
509*37da2899SCharles.Forsyth	#
510*37da2899SCharles.Forsyth	vars := func.call.code.vars;
511*37da2899SCharles.Forsyth	for(i = 0; i < len vars; i++)
512*37da2899SCharles.Forsyth		valinstant(actobj, DontDelete, vars[i].name, undefined);
513*37da2899SCharles.Forsyth
514*37da2899SCharles.Forsyth	# NOTE: the treatment of scopechain here is wrong if nested functions are
515*37da2899SCharles.Forsyth	# permitted.  ECMA-262 currently does not support nested functions (so we
516*37da2899SCharles.Forsyth	# are ok for now) - but other flavours of Javascript do.
517*37da2899SCharles.Forsyth	# Difficulties are introduced by multiple execution contexts.
518*37da2899SCharles.Forsyth	# e.g. in web browsers, one frame can ref a func in
519*37da2899SCharles.Forsyth	# another frame (each frame has a distinct execution context), but the func
520*37da2899SCharles.Forsyth	# ids must bind as if in original lexical context
521*37da2899SCharles.Forsyth
522*37da2899SCharles.Forsyth	osc := ex.scopechain;
523*37da2899SCharles.Forsyth	ex.this = this;
524*37da2899SCharles.Forsyth	ex.scopechain = actobj :: osc;
525*37da2899SCharles.Forsyth	(k, v, nil) := exec(ex, func.call.code);
526*37da2899SCharles.Forsyth	ex.scopechain = osc;
527*37da2899SCharles.Forsyth
528*37da2899SCharles.Forsyth	#
529*37da2899SCharles.Forsyth	# i can find nothing in the docs which defines
530*37da2899SCharles.Forsyth	# the value of a function call
531*37da2899SCharles.Forsyth	# this seems like a reasonable definition
532*37da2899SCharles.Forsyth	#
533*37da2899SCharles.Forsyth	if (k == CThrow)
534*37da2899SCharles.Forsyth		raise "throw";
535*37da2899SCharles.Forsyth	if(!eval && k != CReturn || v == nil)
536*37da2899SCharles.Forsyth		v = undefined;
537*37da2899SCharles.Forsyth	r = valref(v);
538*37da2899SCharles.Forsyth
539*37da2899SCharles.Forsyth	props = func.props;
540*37da2899SCharles.Forsyth	for(i = 0; i < len props; i++){
541*37da2899SCharles.Forsyth		if(props[i] != nil && props[i].name == "arguments"){
542*37da2899SCharles.Forsyth			if(oargs == nil)
543*37da2899SCharles.Forsyth				props[i] = nil;
544*37da2899SCharles.Forsyth			else
545*37da2899SCharles.Forsyth				props[i].val = oargs;
546*37da2899SCharles.Forsyth			break;
547*37da2899SCharles.Forsyth		}
548*37da2899SCharles.Forsyth	}
549*37da2899SCharles.Forsyth
550*37da2899SCharles.Forsyth	return r;
551*37da2899SCharles.Forsyth}
552*37da2899SCharles.Forsyth
553*37da2899SCharles.Forsyth#
554*37da2899SCharles.Forsyth# routines for instantiating variables
555*37da2899SCharles.Forsyth#
556*37da2899SCharles.Forsythfvarinstant(o: ref Obj, force, attr: int, s: string, v: ref RefVal)
557*37da2899SCharles.Forsyth{
558*37da2899SCharles.Forsyth	props := o.props;
559*37da2899SCharles.Forsyth	empty := -1;
560*37da2899SCharles.Forsyth	for(i := 0; i < len props; i++){
561*37da2899SCharles.Forsyth		if(props[i] == nil)
562*37da2899SCharles.Forsyth			empty = i;
563*37da2899SCharles.Forsyth		else if(props[i].name == s){
564*37da2899SCharles.Forsyth			if(force){
565*37da2899SCharles.Forsyth				props[i].attr = attr;
566*37da2899SCharles.Forsyth				props[i].val = v;
567*37da2899SCharles.Forsyth			}
568*37da2899SCharles.Forsyth			return;
569*37da2899SCharles.Forsyth		}
570*37da2899SCharles.Forsyth	}
571*37da2899SCharles.Forsyth	if(empty == -1){
572*37da2899SCharles.Forsyth		props = array[i+1] of ref Prop;
573*37da2899SCharles.Forsyth		props[:] = o.props;
574*37da2899SCharles.Forsyth		o.props = props;
575*37da2899SCharles.Forsyth		empty = i;
576*37da2899SCharles.Forsyth	}
577*37da2899SCharles.Forsyth	props[empty] = ref Prop(attr, s, v);
578*37da2899SCharles.Forsyth}
579*37da2899SCharles.Forsyth
580*37da2899SCharles.Forsythvarinstant(o: ref Obj, attr: int, s: string, v: ref RefVal)
581*37da2899SCharles.Forsyth{
582*37da2899SCharles.Forsyth	fvarinstant(o, 0, attr, s, v);
583*37da2899SCharles.Forsyth}
584*37da2899SCharles.Forsyth
585*37da2899SCharles.Forsythvalinstant(o: ref Obj, attr: int, s: string, v: ref Val)
586*37da2899SCharles.Forsyth{
587*37da2899SCharles.Forsyth	fvarinstant(o, 0, attr, s, ref RefVal(v));
588*37da2899SCharles.Forsyth}
589*37da2899SCharles.Forsyth
590*37da2899SCharles.Forsyth#
591*37da2899SCharles.Forsyth# instantiate global or val variables
592*37da2899SCharles.Forsyth# note that only function variables are forced to be redefined;
593*37da2899SCharles.Forsyth# all other variables have a undefined val.val field
594*37da2899SCharles.Forsyth#
595*37da2899SCharles.Forsythglobalinstant(o: ref Obj, vars: array of ref Prop)
596*37da2899SCharles.Forsyth{
597*37da2899SCharles.Forsyth	for(i := 0; i < len vars; i++){
598*37da2899SCharles.Forsyth		force := vars[i].val.val != undefined;
599*37da2899SCharles.Forsyth		fvarinstant(o, force, 0, vars[i].name, vars[i].val);
600*37da2899SCharles.Forsyth	}
601*37da2899SCharles.Forsyth}
602*37da2899SCharles.Forsyth
603*37da2899SCharles.Forsythnumval(r: real): ref Val
604*37da2899SCharles.Forsyth{
605*37da2899SCharles.Forsyth	return ref Val(TNum, r, nil, nil, nil);
606*37da2899SCharles.Forsyth}
607*37da2899SCharles.Forsyth
608*37da2899SCharles.Forsythstrval(s: string): ref Val
609*37da2899SCharles.Forsyth{
610*37da2899SCharles.Forsyth	return ref Val(TStr, 0., s, nil, nil);
611*37da2899SCharles.Forsyth}
612*37da2899SCharles.Forsyth
613*37da2899SCharles.Forsythobjval(o: ref Obj): ref Val
614*37da2899SCharles.Forsyth{
615*37da2899SCharles.Forsyth	return ref Val(TObj, 0., nil, o, nil);
616*37da2899SCharles.Forsyth}
617*37da2899SCharles.Forsyth
618*37da2899SCharles.Forsythregexpval(p: string, f: string, i: int): ref Val
619*37da2899SCharles.Forsyth{
620*37da2899SCharles.Forsyth	return ref Val(TRegExp, 0., nil, nil, ref REval(p, f, i));
621*37da2899SCharles.Forsyth}
622*37da2899SCharles.Forsyth
623*37da2899SCharles.Forsyth#
624*37da2899SCharles.Forsyth# operations on refereneces
625*37da2899SCharles.Forsyth# note the substitution of nil for an object
626*37da2899SCharles.Forsyth# version of null, implied in the discussion of
627*37da2899SCharles.Forsyth# Reference Types, since there isn't a null object
628*37da2899SCharles.Forsyth#
629*37da2899SCharles.Forsythvalref(v: ref Val): ref Ref
630*37da2899SCharles.Forsyth{
631*37da2899SCharles.Forsyth	return ref Ref(0, v, nil, nil);
632*37da2899SCharles.Forsyth}
633*37da2899SCharles.Forsyth
634*37da2899SCharles.ForsythgetBase(ex: ref Exec, r: ref Ref): ref Obj
635*37da2899SCharles.Forsyth{
636*37da2899SCharles.Forsyth	if(!r.isref)
637*37da2899SCharles.Forsyth		runtime(ex, ReferenceError, "not a reference");
638*37da2899SCharles.Forsyth	return r.base;
639*37da2899SCharles.Forsyth}
640*37da2899SCharles.Forsyth
641*37da2899SCharles.ForsythgetPropertyName(ex: ref Exec, r: ref Ref): string
642*37da2899SCharles.Forsyth{
643*37da2899SCharles.Forsyth	if(!r.isref)
644*37da2899SCharles.Forsyth		runtime(ex, ReferenceError, "not a reference");
645*37da2899SCharles.Forsyth	return r.name;
646*37da2899SCharles.Forsyth}
647*37da2899SCharles.Forsyth
648*37da2899SCharles.ForsythgetValue(ex: ref Exec, r: ref Ref): ref Val
649*37da2899SCharles.Forsyth{
650*37da2899SCharles.Forsyth	if(!r.isref)
651*37da2899SCharles.Forsyth		return r.val;
652*37da2899SCharles.Forsyth	b := r.base;
653*37da2899SCharles.Forsyth	if(b == nil)
654*37da2899SCharles.Forsyth		runtime(ex, ReferenceError, "reference " + r.name + " is null");
655*37da2899SCharles.Forsyth	return esget(ex, b, r.name, 0);
656*37da2899SCharles.Forsyth}
657*37da2899SCharles.Forsyth
658*37da2899SCharles.ForsythputValue(ex: ref Exec, r: ref Ref, v: ref Val)
659*37da2899SCharles.Forsyth{
660*37da2899SCharles.Forsyth	if(!r.isref)
661*37da2899SCharles.Forsyth		runtime(ex, ReferenceError, "not a reference: " + r.name);
662*37da2899SCharles.Forsyth	b := r.base;
663*37da2899SCharles.Forsyth	if(b == nil)
664*37da2899SCharles.Forsyth		b = ex.global;
665*37da2899SCharles.Forsyth	esput(ex, b, r.name, v, 0);
666*37da2899SCharles.Forsyth}
667*37da2899SCharles.Forsyth
668*37da2899SCharles.Forsyth#
669*37da2899SCharles.Forsyth# conversion routines defined by the abstract machine
670*37da2899SCharles.Forsyth# see section 9.
671*37da2899SCharles.Forsyth# note that string, boolean, and number objects are
672*37da2899SCharles.Forsyth# not automaically coerced to values, and vice versa.
673*37da2899SCharles.Forsyth#
674*37da2899SCharles.ForsythtoPrimitive(ex: ref Exec, v: ref Val, ty: int): ref Val
675*37da2899SCharles.Forsyth{
676*37da2899SCharles.Forsyth	if(v.ty != TObj)
677*37da2899SCharles.Forsyth		return v;
678*37da2899SCharles.Forsyth	v = esdefaultval(ex, v.obj, ty, 0);
679*37da2899SCharles.Forsyth	if(v.ty == TObj)
680*37da2899SCharles.Forsyth		runtime(ex, TypeError, "toPrimitive returned an object");
681*37da2899SCharles.Forsyth	return v;
682*37da2899SCharles.Forsyth}
683*37da2899SCharles.Forsyth
684*37da2899SCharles.ForsythtoBoolean(ex: ref Exec, v: ref Val): ref Val
685*37da2899SCharles.Forsyth{
686*37da2899SCharles.Forsyth	case v.ty{
687*37da2899SCharles.Forsyth	TUndef or
688*37da2899SCharles.Forsyth	TNull =>
689*37da2899SCharles.Forsyth		return false;
690*37da2899SCharles.Forsyth	TBool =>
691*37da2899SCharles.Forsyth		return v;
692*37da2899SCharles.Forsyth	TNum =>
693*37da2899SCharles.Forsyth		if(isnan(v.num))
694*37da2899SCharles.Forsyth			return false;
695*37da2899SCharles.Forsyth		if(v.num == 0.)
696*37da2899SCharles.Forsyth			return false;
697*37da2899SCharles.Forsyth	TStr =>
698*37da2899SCharles.Forsyth		if(v.str == "")
699*37da2899SCharles.Forsyth			return false;
700*37da2899SCharles.Forsyth	TObj =>
701*37da2899SCharles.Forsyth		break;
702*37da2899SCharles.Forsyth	TRegExp =>
703*37da2899SCharles.Forsyth		break;
704*37da2899SCharles.Forsyth	* =>
705*37da2899SCharles.Forsyth		runtime(ex, TypeError, "unknown type in toBoolean");
706*37da2899SCharles.Forsyth	}
707*37da2899SCharles.Forsyth	return true;
708*37da2899SCharles.Forsyth}
709*37da2899SCharles.Forsyth
710*37da2899SCharles.ForsythtoNumber(ex: ref Exec, v: ref Val): real
711*37da2899SCharles.Forsyth{
712*37da2899SCharles.Forsyth	case v.ty{
713*37da2899SCharles.Forsyth	TUndef =>
714*37da2899SCharles.Forsyth		return NaN;
715*37da2899SCharles.Forsyth	TNull =>
716*37da2899SCharles.Forsyth		return 0.;
717*37da2899SCharles.Forsyth	TBool =>
718*37da2899SCharles.Forsyth		if(v == false)
719*37da2899SCharles.Forsyth			return 0.;
720*37da2899SCharles.Forsyth		return 1.;
721*37da2899SCharles.Forsyth	TNum =>
722*37da2899SCharles.Forsyth		return v.num;
723*37da2899SCharles.Forsyth	TStr =>
724*37da2899SCharles.Forsyth		(si, r) := parsenum(ex, v.str, 0, ParseReal|ParseHex|ParseTrim|ParseEmpty);
725*37da2899SCharles.Forsyth		if(si != len v.str)
726*37da2899SCharles.Forsyth			r = Math->NaN;
727*37da2899SCharles.Forsyth		return r;
728*37da2899SCharles.Forsyth	TObj =>
729*37da2899SCharles.Forsyth		return toNumber(ex, toPrimitive(ex, v, TNum));
730*37da2899SCharles.Forsyth	TRegExp =>
731*37da2899SCharles.Forsyth		return NaN;
732*37da2899SCharles.Forsyth	* =>
733*37da2899SCharles.Forsyth		runtime(ex, TypeError, "unknown type in toNumber");
734*37da2899SCharles.Forsyth		return 0.;
735*37da2899SCharles.Forsyth	}
736*37da2899SCharles.Forsyth}
737*37da2899SCharles.Forsyth
738*37da2899SCharles.ForsythtoInteger(ex: ref Exec, v: ref Val): real
739*37da2899SCharles.Forsyth{
740*37da2899SCharles.Forsyth	r := toNumber(ex, v);
741*37da2899SCharles.Forsyth	if(isnan(r))
742*37da2899SCharles.Forsyth		return 0.;
743*37da2899SCharles.Forsyth	if(r == 0. || r == +Infinity || r == -Infinity)
744*37da2899SCharles.Forsyth		return r;
745*37da2899SCharles.Forsyth	return copysign(floor(fabs(r)), r);
746*37da2899SCharles.Forsyth}
747*37da2899SCharles.Forsyth
748*37da2899SCharles.Forsyth#
749*37da2899SCharles.Forsyth# toInt32 == toUint32, except for numbers > 2^31
750*37da2899SCharles.Forsyth#
751*37da2899SCharles.ForsythtoInt32(ex: ref Exec, v: ref Val): int
752*37da2899SCharles.Forsyth{
753*37da2899SCharles.Forsyth	r := toNumber(ex, v);
754*37da2899SCharles.Forsyth	if(isnan(r) || r == 0. || r == +Infinity || r == -Infinity)
755*37da2899SCharles.Forsyth		return 0;
756*37da2899SCharles.Forsyth	r = copysign(floor(fabs(r)), r);
757*37da2899SCharles.Forsyth	# need to convert to big since it might be unsigned
758*37da2899SCharles.Forsyth	return int big fmod(r, 4294967296.);
759*37da2899SCharles.Forsyth}
760*37da2899SCharles.Forsyth
761*37da2899SCharles.ForsythtoUint32(ex: ref Exec, v: ref Val): big
762*37da2899SCharles.Forsyth{
763*37da2899SCharles.Forsyth	r := toNumber(ex, v);
764*37da2899SCharles.Forsyth	if(isnan(r) || r == 0. || r == +Infinity || r == -Infinity)
765*37da2899SCharles.Forsyth		return big 0;
766*37da2899SCharles.Forsyth	r = copysign(floor(fabs(r)), r);
767*37da2899SCharles.Forsyth	# need to convert to big since it might be unsigned
768*37da2899SCharles.Forsyth	b := big fmod(r, 4294967296.);
769*37da2899SCharles.Forsyth	if(b < big 0)
770*37da2899SCharles.Forsyth		fatal(ex, "uint32 < 0");
771*37da2899SCharles.Forsyth	return b;
772*37da2899SCharles.Forsyth}
773*37da2899SCharles.Forsyth
774*37da2899SCharles.ForsythtoUint16(ex: ref Exec, v: ref Val): int
775*37da2899SCharles.Forsyth{
776*37da2899SCharles.Forsyth	return toInt32(ex, v) & 16rffff;
777*37da2899SCharles.Forsyth}
778*37da2899SCharles.Forsyth
779*37da2899SCharles.ForsythtoString(ex: ref Exec, v: ref Val): string
780*37da2899SCharles.Forsyth{
781*37da2899SCharles.Forsyth	case v.ty{
782*37da2899SCharles.Forsyth	TUndef =>
783*37da2899SCharles.Forsyth		return "undefined";
784*37da2899SCharles.Forsyth	TNull =>
785*37da2899SCharles.Forsyth		return "null";
786*37da2899SCharles.Forsyth	TBool =>
787*37da2899SCharles.Forsyth		if(v == false)
788*37da2899SCharles.Forsyth			return "false";
789*37da2899SCharles.Forsyth		return "true";
790*37da2899SCharles.Forsyth	TNum =>
791*37da2899SCharles.Forsyth		r := v.num;
792*37da2899SCharles.Forsyth		if(isnan(r))
793*37da2899SCharles.Forsyth			return "NaN";
794*37da2899SCharles.Forsyth		if(r == 0.)
795*37da2899SCharles.Forsyth			return "0";
796*37da2899SCharles.Forsyth		if(r == Infinity)
797*37da2899SCharles.Forsyth			return "Infinity";
798*37da2899SCharles.Forsyth		if(r == -Infinity)
799*37da2899SCharles.Forsyth			return "-Infinity";
800*37da2899SCharles.Forsyth		# this is wrong, but right is too hard
801*37da2899SCharles.Forsyth		if(r < 1000000000000000000000. && r >= 1./(1000000.)){
802*37da2899SCharles.Forsyth			return string r;
803*37da2899SCharles.Forsyth		}
804*37da2899SCharles.Forsyth		return string r;
805*37da2899SCharles.Forsyth	TStr =>
806*37da2899SCharles.Forsyth		return v.str;
807*37da2899SCharles.Forsyth	TObj =>
808*37da2899SCharles.Forsyth		return toString(ex, toPrimitive(ex, v, TStr));
809*37da2899SCharles.Forsyth	TRegExp =>
810*37da2899SCharles.Forsyth		return "/" + v.rev.p + "/" + v.rev.f;
811*37da2899SCharles.Forsyth	* =>
812*37da2899SCharles.Forsyth		runtime(ex, TypeError, "unknown type in ToString");
813*37da2899SCharles.Forsyth		return "";
814*37da2899SCharles.Forsyth	}
815*37da2899SCharles.Forsyth}
816*37da2899SCharles.Forsyth
817*37da2899SCharles.ForsythtoObject(ex: ref Exec, v: ref Val): ref Obj
818*37da2899SCharles.Forsyth{
819*37da2899SCharles.Forsyth	case v.ty{
820*37da2899SCharles.Forsyth	TUndef =>
821*37da2899SCharles.Forsyth		runtime(ex, TypeError, "can't convert undefined to an object");
822*37da2899SCharles.Forsyth	TNull =>
823*37da2899SCharles.Forsyth		runtime(ex, TypeError, "can't convert null to an object");
824*37da2899SCharles.Forsyth	TBool or
825*37da2899SCharles.Forsyth	TStr or
826*37da2899SCharles.Forsyth	TNum or
827*37da2899SCharles.Forsyth	TRegExp =>
828*37da2899SCharles.Forsyth		return coerceToObj(ex, v).obj;
829*37da2899SCharles.Forsyth	TObj =>
830*37da2899SCharles.Forsyth		return v.obj;
831*37da2899SCharles.Forsyth	* =>
832*37da2899SCharles.Forsyth		runtime(ex, TypeError, "unknown type in toObject");
833*37da2899SCharles.Forsyth		return nil;
834*37da2899SCharles.Forsyth	}
835*37da2899SCharles.Forsyth	return nil;
836*37da2899SCharles.Forsyth}
837