xref: /inferno-os/appl/lib/ecmascript/builtin.b (revision d0e1d143ef6f03c75c008c7ec648859dd260cbab)
1#
2# utility functions
3#
4biinst(o: ref Obj, bi: Builtin, p: ref Obj, h: ESHostobj): ref Obj
5{
6	bo := mkobj(p, "Function");
7	bo.call = mkcall(nil, bi.params);
8	bo.val = strval(bi.val);
9	bo.host = h;
10	varinstant(bo, DontEnum|DontDelete|ReadOnly, "length", ref RefVal(numval(real bi.length)));
11	varinstant(o, DontEnum, bi.name, ref RefVal(objval(bo)));
12	return bo;
13}
14
15biminst(o: ref Obj, bis: array of Builtin, p: ref Obj, h: ESHostobj)
16{
17	for(i := 0; i < len bis; i++)
18		biinst(o, bis[i], p, h);
19}
20
21biarg(args: array of ref Val, i: int): ref Val
22{
23	if(i < len args)
24		return args[i];
25	return undefined;
26}
27
28#
29# interface to builtin objects
30#
31get(ex: ref Ecmascript->Exec, o: ref Ecmascript->Obj, property: string): ref Ecmascript->Val
32{
33	return esget(ex, o, property, 1);
34}
35
36put(ex: ref Ecmascript->Exec, o: ref Ecmascript->Obj, property: string, val: ref Ecmascript->Val)
37{
38	return esput(ex, o, property, val, 1);
39}
40
41canput(ex: ref Ecmascript->Exec, o: ref Ecmascript->Obj, property: string): ref Ecmascript->Val
42{
43	return escanput(ex, o, property, 1);
44}
45
46hasproperty(ex: ref Ecmascript->Exec, o: ref Ecmascript->Obj, property: string): ref Ecmascript->Val
47{
48	return eshasproperty(ex, o, property, 1);
49}
50
51delete(ex: ref Ecmascript->Exec, o: ref Ecmascript->Obj, property: string)
52{
53	return esdelete(ex, o, property, 1);
54}
55
56defaultval(ex: ref Ecmascript->Exec, o: ref Ecmascript->Obj, tyhint: int): ref Ecmascript->Val
57{
58	return esdefaultval(ex, o, tyhint, 1);
59}
60
61call(ex: ref Ecmascript->Exec, f, this: ref Ecmascript->Obj, args: array of ref Ecmascript->Val, eval: int): ref Ecmascript->Ref
62{
63	x, y: real;
64	v: ref Val;
65
66	if(this == nil)
67		this = ex.global;
68	if(f.host != me)
69		return escall(ex, f, this, args, eval);
70	case f.val.str{
71	"eval" =>
72		v = ceval(ex, f, this, args);
73	"parseInt" =>
74		v = cparseInt(ex, f, this, args);
75	"parseFloat" =>
76		v = cparseFloat(ex, f, this, args);
77	"escape" =>
78		v = cescape(ex, f, this, args);
79	"unescape" =>
80		v = cunescape(ex, f, this, args);
81	"isNaN" =>
82		v = cisNaN(ex, f, this, args);
83	"isFinite" =>
84		v = cisFinite(ex, f, this, args);
85	"decodeURI" =>
86		v = cdecodeuri(ex, f, this, args);
87	"encodeURI" =>
88		v = cencodeuri(ex, f, this, args);
89	"decodeURIComponent" =>
90		v = cdecodeuric(ex, f, this, args);
91	"encodeURIComponent" =>
92		v = cencodeuric(ex, f, this, args);
93	"Object" =>
94		v = cobj(ex, f, this, args);
95	"Object.prototype.toString" or
96	"Object.prototype.toLocaleString" =>
97		v = cobjprototoString(ex, f, this, args);
98	"Object.prototype.valueOf" =>
99		v = cobjprotovalueOf(ex, f, this, args);
100	"Object.prototype.hasOwnProperty" =>
101		v = cobjprotohasownprop(ex, f, this, args);
102	"Object.prototype.isPrototypeOf" =>
103		v = cobjprotoisprotoof(ex, f, this, args);
104	"Object.prototype.propertyisEnumerable" =>
105		v = cobjprotopropisenum(ex, f, this, args);
106	"Function" =>
107		v = objval(nfunc(ex, f, args));
108	"Function.Prototype" =>
109		v = undefined;
110	"Function.prototype.toString" =>
111		v = cfuncprototoString(ex, f, this, args);
112	"Function.prototype.apply" =>
113		v = cfuncprotoapply(ex, f, this, args);
114	"Function.prototype.call" =>
115		v = cfuncprotocall(ex, f, this, args);
116	"Error" =>
117		v = objval(nerr(ex, f, args, ex.errproto));
118	"Error.prototype.toString" =>
119		v = cerrprototoString(ex, f, this, args);
120	"EvalError" =>
121		v = objval(nerr(ex, f, args, ex.evlerrproto));
122	"EvalError.prototype.toString" =>
123		v = cerrprototoString(ex, f, this, args);
124	"RangeError" =>
125		v = objval(nerr(ex, f, args, ex.ranerrproto));
126	"RangeError.prototype.toString" =>
127		v = cerrprototoString(ex, f, this, args);
128	"ReferenceError" =>
129		v = objval(nerr(ex, f, args, ex.referrproto));
130	"ReferenceError.prototype.toString" =>
131		v = cerrprototoString(ex, f, this, args);
132	"SyntaxError" =>
133		v = objval(nerr(ex, f, args, ex.synerrproto));
134	"SyntaxError.prototype.toString" =>
135		v = cerrprototoString(ex, f, this, args);
136	"TypeError" =>
137		v = objval(nerr(ex, f, args, ex.typerrproto));
138	"TypeError.prototype.toString" =>
139		v = cerrprototoString(ex, f, this, args);
140	"URIError" =>
141		v = objval(nerr(ex, f, args, ex.urierrproto));
142	"URIError.prototype.toString" =>
143		v = cerrprototoString(ex, f, this, args);
144	"InternalError" =>
145		v = objval(nerr(ex, f, args, ex.interrproto));
146	"InternalError.prototype.toString" =>
147		v = cerrprototoString(ex, f, this, args);
148	"Array" =>
149		v = objval(narray(ex, f, args));
150	"Array.prototype.toString" or "Array.prototype.toLocaleString" =>
151		v = carrayprototoString(ex, f, this, args);
152	"Array.prototype.concat" =>
153		v = carrayprotoconcat(ex, f, this, args);
154	"Array.prototype.join" =>
155		v = carrayprotojoin(ex, f, this, args);
156	"Array.prototype.pop" =>
157		v = carrayprotopop(ex, f, this, args);
158	"Array.prototype.push" =>
159		v = carrayprotopush(ex, f, this, args);
160	"Array.prototype.reverse" =>
161		v = carrayprotoreverse(ex, f, this, args);
162	"Array.prototype.shift" =>
163		v = carrayprotoshift(ex, f, this, args);
164	"Array.prototype.slice" =>
165		v = carrayprotoslice(ex, f, this, args);
166	"Array.prototype.splice" =>
167		v = carrayprotosplice(ex, f, this, args);
168	"Array.prototype.sort" =>
169		v = carrayprotosort(ex, f, this, args);
170	"Array.prototype.unshift" =>
171		v = carrayprotounshift(ex, f, this, args);
172	"String" =>
173		v = cstr(ex, f, this, args);
174	"String.fromCharCode" =>
175		v = cstrfromCharCode(ex, f, this, args);
176	"String.prototype.toString" =>
177		v = cstrprototoString(ex, f, this, args);
178	"String.prototype.valueOf" =>
179		v = cstrprototoString(ex, f, this, args);
180	"String.prototype.charAt" =>
181		v = cstrprotocharAt(ex, f, this, args);
182	"String.prototype.charCodeAt" =>
183		v = cstrprotocharCodeAt(ex, f, this, args);
184	"String.prototype.concat" =>
185		v = cstrprotoconcat(ex, f, this, args);
186	"String.prototype.indexOf" =>
187		v = cstrprotoindexOf(ex, f, this, args);
188	"String.prototype.lastIndexOf" =>
189		v = cstrprotolastindexOf(ex, f, this, args);
190	"String.prototype.localeCompare" =>
191		v = cstrprotocmp(ex, f, this, args);
192	"String.prototype.slice" =>
193		v = cstrprotoslice(ex, f, this, args);
194	"String.prototype.split" =>
195		v = cstrprotosplit(ex, f, this, args);
196	"String.prototype.substr" =>
197		v = cstrprotosubstr(ex, f, this, args);
198	"String.prototype.substring" =>
199		v = cstrprotosubstring(ex, f, this, args);
200	"String.prototype.toLowerCase" or "String.prototype.toLocaleLowerCase" =>
201		v = cstrprototoLowerCase(ex, f, this, args);
202	"String.prototype.toUpperCase" or "String.prototype.toLocaleUpperCase" =>
203		v = cstrprototoUpperCase(ex, f, this, args);
204	"String.prototype.match" =>
205		v = cstrprotomatch(ex, f, this, args);
206	"String.prototype.replace" =>
207		v = cstrprotoreplace(ex, f, this, args);
208	"String.prototype.search" =>
209		v = cstrprotosearch(ex, f, this, args);
210# JavaScript 1.0
211	"String.prototype.anchor" or
212	"String.prototype.big" or
213	"String.prototype.blink" or
214	"String.prototype.bold" or
215	"String.prototype.fixed" or
216	"String.prototype.fontcolor" or
217	"String.prototype.fontsize" or
218	"String.prototype.italics" or
219	"String.prototype.link" or
220	"String.prototype.small" or
221	"String.prototype.strike" or
222	"String.prototype.sub" or
223	"String.prototype.sup" =>
224		s := toString(ex, objval(this));
225		arg := toString(ex, biarg(args, 0));
226		tag, endtag: string;
227		case f.val.str{
228		"String.prototype.anchor" =>
229			tag = "<A NAME=\"" + arg + "\">";
230			endtag = "</A>";
231		"String.prototype.big" =>
232			tag = "<BIG>";
233			endtag = "</BIG>";
234		"String.prototype.blink" =>
235			tag = "<BLINK>";
236			endtag = "</BLINK>";
237		"String.prototype.bold" =>
238			tag = "<B>";
239			endtag = "</B>";
240		"String.prototype.fixed" =>
241			tag = "<TT>";
242			endtag = "</TT>";
243		"String.prototype.fontcolor" =>
244			tag = "<FONT COLOR=\"" + arg + "\">";
245			endtag = "</FONT>";
246		"String.prototype.fontsize" =>
247			tag = "<FONT SIZE=\"" + arg + "\">";
248			endtag = "</FONT>";
249		"String.prototype.italics" =>
250			tag = "<I>";
251			endtag = "</I>";
252		"String.prototype.link" =>
253			tag = "<A HREF=\"" + arg + "\">";
254			endtag = "</A>";
255		"String.prototype.small" =>
256			tag = "<SMALL>";
257			endtag = "</SMALL>";
258		"String.prototype.strike" =>
259			tag = "<STRIKE>";
260			endtag = "</STRIKE>";
261		"String.prototype.sub" =>
262			tag = "<SUB>";
263			endtag = "</SUB>";
264		"String.prototype.sup" =>
265			tag = "<SUP>";
266			endtag = "</SUP>";
267		}
268		v = strval(tag + s + endtag);
269	"Boolean" =>
270		v = cbool(ex, f, this, args);
271	"Boolean.prototype.toString" =>
272		v = cboolprototoString(ex, f, this, args);
273	"Boolean.prototype.valueOf" =>
274		v = cboolprotovalueOf(ex, f, this, args);
275	"Number" =>
276		v = cnum(ex, f, this, args);
277	"Number.prototype.toString" or "Number.prototype.toLocaleString" =>
278		v = cnumprototoString(ex, f, this, args);
279	"Number.prototype.valueOf" =>
280		v = cnumprotovalueOf(ex, f, this, args);
281	"Number.prototype.toFixed" =>
282		v = cnumprotofix(ex, f, this, args);
283	"Number.prototype.toExponential" =>
284		v = cnumprotoexp(ex, f, this, args);
285	"Number.prototype.toPrecision" =>
286		v = cnumprotoprec(ex, f, this, args);
287	"RegExp" =>
288		v = cregexp(ex, f, this, args);
289	"RegExp.prototype.exec" =>
290		v = cregexpprotoexec(ex, f, this, args);
291	"RegExp.prototype.test" =>
292		v = cregexpprototest(ex, f, this, args);
293	"RegExp.prototype.toString" =>
294		v = cregexpprototoString(ex, f, this, args);
295	"Math.abs" or
296	"Math.acos" or
297	"Math.asin" or
298	"Math.atan" or
299	"Math.ceil" or
300	"Math.cos" or
301	"Math.exp" or
302	"Math.floor" or
303	"Math.log" or
304	"Math.round" or
305	"Math.sin" or
306	"Math.sqrt" or
307	"Math.tan" =>
308		x = toNumber(ex, biarg(args, 0));
309		case f.val.str{
310		"Math.abs" =>
311			if(x < 0.)
312				x = -x;
313			else if(x == 0.)
314				x = 0.;
315		"Math.acos" =>		x = math->acos(x);
316		"Math.asin" =>		x = math->asin(x);
317		"Math.atan" =>		x = math->atan(x);
318		"Math.ceil" =>		x = math->ceil(x);
319		"Math.cos" =>		x = math->cos(x);
320		"Math.exp" =>		x = math->exp(x);
321		"Math.floor" =>		x = math->floor(x);
322		"Math.log" =>		x = math->log(x);
323		"Math.round" =>		if((x == .0 && copysign(1., x) == -1.)
324					|| (x < .0 && x >= -0.5))
325						x = -0.;
326					else
327						x = math->floor(x+.5);
328		"Math.sin" =>		x = math->sin(x);
329		"Math.sqrt" =>		x = math->sqrt(x);
330		"Math.tan" =>		x = math->tan(x);
331		}
332		v = numval(x);
333	"Math.random" =>
334#		range := big 16r7fffffffffffffff;
335		range := big 1000000000;
336		v = numval(real bigrand(range)/ real range);
337	"Math.atan2" or
338	"Math.max" or
339	"Math.min" or
340	"Math.pow" =>
341		x = toNumber(ex, biarg(args, 0));
342		y = toNumber(ex, biarg(args, 1));
343		case f.val.str{
344		"Math.atan2" =>
345			x = math->atan2(x, y);
346		"Math.max" =>
347			if(x > y)
348				;
349			else if(x < y)
350				x = y;
351			else if(x == y){
352				if(x == 0. && copysign(1., x) == -1. && copysign(1., y) == 1.)
353					x = y;
354			}else
355				x = Math->NaN;
356		"Math.min" =>
357			if(x < y)
358				;
359			else if(x > y)
360				x = y;
361			else if(x == y){
362				if(x == 0. && copysign(1., x) == 1. && copysign(1., y) == -1.)
363					x = y;
364			}else
365				x = Math->NaN;
366		"Math.pow" =>
367			x = math->pow(x, y);
368		}
369		v = numval(x);
370	"Date" =>
371		v = cdate(ex, f, this, args);
372	"Date.parse" =>
373		v = cdateparse(ex, f, this, args);
374	"Date.UTC" =>
375		v = cdateUTC(ex, f, this, args);
376	"Date.prototype.toString" or
377	"Date.prototype.toLocaleString" =>
378		v = cdateprototoString(ex, f, this, args);
379	"Date.prototype.toDateString" or
380	"Date.prototype.toLocaleDateString" =>
381		v = cdateprototoDateString(ex, f, this, args);
382	"Date.prototype.toTimeString" or
383	"Date.prototype.toLocaleTimeString" =>
384		v = cdateprototoTimeString(ex, f, this, args);
385	"Date.prototype.valueOf" or
386	"Date.prototype.getTime" =>
387		v = cdateprotovalueOf(ex, f, this, args);
388	"Date.prototype.getYear" or
389	"Date.prototype.getFullYear" or
390	"Date.prototype.getMonth" or
391	"Date.prototype.getDate" or
392	"Date.prototype.getDay" or
393	"Date.prototype.getHours" or
394	"Date.prototype.getMinutes" or
395	"Date.prototype.getSeconds" =>
396		v = cdateprotoget(ex, f, this, args, !UTC);
397	"Date.prototype.getUTCFullYear" or
398	"Date.prototype.getUTCMonth" or
399	"Date.prototype.getUTCDate" or
400	"Date.prototype.getUTCDay" or
401	"Date.prototype.getUTCHours" or
402	"Date.prototype.getUTCMinutes" or
403	"Date.prototype.getUTCSeconds" =>
404		v = cdateprotoget(ex, f, this, args, UTC);
405	"Date.prototype.getMilliseconds" or
406	"Date.prototype.getUTCMilliseconds" =>
407		v = cdateprotogetMilliseconds(ex, f, this, args);
408	"Date.prototype.getTimezoneOffset" =>
409		v = cdateprotogetTimezoneOffset(ex, f, this, args);
410	"Date.prototype.setTime" =>
411		v = cdateprotosetTime(ex, f, this, args);
412	"Date.prototype.setMilliseconds" =>
413		v = cdateprotosetMilliseconds(ex, f, this, args, !UTC);
414	"Date.prototype.setUTCMilliseconds" =>
415		v = cdateprotosetMilliseconds(ex, f, this, args, UTC);
416	"Date.prototype.setSeconds" =>
417		v = cdateprotosetSeconds(ex, f, this, args, !UTC);
418	"Date.prototype.setUTCSeconds" =>
419		v = cdateprotosetSeconds(ex, f, this, args, UTC);
420	"Date.prototype.setMinutes" =>
421		v = cdateprotosetMinutes(ex, f, this, args, !UTC);
422	"Date.prototype.setUTCMinutes" =>
423		v = cdateprotosetMinutes(ex, f, this, args, UTC);
424	"Date.prototype.setHours" =>
425		v = cdateprotosetHours(ex, f, this, args, !UTC);
426	"Date.prototype.setUTCHours" =>
427		v = cdateprotosetHours(ex, f, this, args, UTC);
428	"Date.prototype.setDate" =>
429		v = cdateprotosetDate(ex, f, this, args, !UTC);
430	"Date.prototype.setUTCDate" =>
431		v = cdateprotosetDate(ex, f, this, args, UTC);
432	"Date.prototype.setMonth" =>
433		v = cdateprotosetMonth(ex, f, this, args, !UTC);
434	"Date.prototype.setUTCMonth" =>
435		v = cdateprotosetMonth(ex, f, this, args, UTC);
436	"Date.prototype.setFullYear" =>
437		v = cdateprotosetFullYear(ex, f, this, args, !UTC);
438	"Date.prototype.setUTCFullYear" =>
439		v = cdateprotosetFullYear(ex, f, this, args, UTC);
440	"Date.prototype.setYear" =>
441		v = cdateprotosetYear(ex, f, this, args);
442	"Date.prototype.toUTCString" or
443	"Date.prototype.toGMTString" =>
444		v = cdateprototoUTCString(ex, f, this, args);
445	* =>
446		v = nil;
447	}
448	if(v == nil)
449		runtime(ex, ReferenceError, "unknown function "+f.val.str+" in builtin call");
450	return valref(v);
451}
452
453rsalt := big 12345678;
454
455randinit(seed: big)
456{
457	rsalt = big seed;
458	bigrand(big 1);
459	bigrand(big 1);
460}
461
462RANDMASK: con (big 1<<63)-(big 1);
463
464bigrand(modulus: big): big
465{
466	rsalt = rsalt * big 1103515245 + big 12345;
467	if(modulus <= big 0)
468		return big 0;
469	return ((rsalt&RANDMASK)>>10) % modulus;
470}
471
472construct(ex: ref Ecmascript->Exec, f: ref Ecmascript->Obj, args: array of ref Ecmascript->Val): ref Ecmascript->Obj
473{
474	if(f.host != me)
475		runtime(ex, TypeError, "ecmascript builtin called incorrectly");
476	case f.val.str{
477	"Object" =>
478		return nobj(ex, f, args);
479	"Function" =>
480		return nfunc(ex, f, args);
481	"Array" =>
482		return narray(ex, f, args);
483	"Error" =>
484		return nerr(ex, f, args, ex.errproto);
485	"EvalError" =>
486		return nerr(ex, f, args, ex.evlerrproto);
487	"RangeError" =>
488		return nerr(ex, f, args, ex.ranerrproto);
489	"ReferenceError" =>
490		return nerr(ex, f, args, ex.referrproto);
491	"SyntaxError" =>
492		return nerr(ex, f, args, ex.synerrproto);
493	"TypeError" =>
494		return nerr(ex, f, args, ex.typerrproto);
495	"URIError" =>
496		return nerr(ex, f, args, ex.urierrproto);
497	"InternalError" =>
498		return nerr(ex, f, args, ex.interrproto);
499	"String" or
500	"Boolean" or
501	"Number" =>
502		return coerceToObj(ex, call(ex, f, nil, args, 0).val).obj;
503	"Date" =>
504		return ndate(ex, f, args);
505	"RegExp" =>
506		return nregexp(ex, f, args);
507	}
508	runtime(ex, ReferenceError, "unknown constructor "+f.val.str+" in builtin construct");
509	return nil;
510}
511
512ceval(ex: ref Exec, nil, nil: ref Ecmascript->Obj, args: array of ref Val): ref Val
513{
514	if(len args < 1)
515		return undefined;
516	vs := coerceToVal(args[0]);
517	if(!isstr(vs))
518		return args[0];
519	(k, v, nil) := eval(ex, vs.str);
520	if(k != CNormal || v == nil)
521		v = undefined;
522	return v;
523}
524
525cparseInt(ex: ref Exec, nil, nil: ref Ecmascript->Obj, args: array of ref Val): ref Val
526{
527	sv := biarg(args, 0);
528	s := toString(ex, sv);
529	neg := 0;
530	i := 0;
531	if(len s > i){
532		if(s[i] == '-'){
533			neg = 1;
534			i++;
535		}else if(s[i] == '+')
536			i++;
537	}
538	rv := biarg(args, 1);
539	if(rv == undefined)
540		r := big 0;
541	else
542		r = big toInt32(ex, rv);
543	if(r == big 0){
544		if(len s > i && s[i] == '0'){
545			r = big 8;
546			if(len s >= i+2 && (s[i+1] == 'x' || s[i+1] == 'X'))
547				r = big 16;
548		}else
549			r = big 10;
550	}else if(r < big 0 || r > big 36)
551		return numval(Math->NaN);
552	if(r == big 16 && len s >= i+2 && s[i] == '0' && (s[i+1] == 'x' || s[i+1] == 'X'))
553		i += 2;
554	ok := 0;
555	n := big 0;
556	for(; i < len s; i++) {
557		c := s[i];
558		v := r;
559		case c {
560		'a' to 'z' =>
561			v = big(c - 'a' + 10);
562		'A' to 'Z' =>
563			v = big(c - 'A' + 10);
564		'0' to '9' =>
565			v = big(c - '0');
566		}
567		if(v >= r)
568			break;
569		ok = 1;
570		n = n * r + v;
571	}
572	if(!ok)
573		return numval(Math->NaN);
574	if(neg)
575		n = -n;
576	return numval(real n);
577}
578
579cparseFloat(ex: ref Exec, nil, nil: ref Ecmascript->Obj, args: array of ref Val): ref Val
580{
581	s := toString(ex, biarg(args, 0));
582	(nil, r) := parsenum(ex, s, 0, ParseReal|ParseTrim);
583	return numval(r);
584}
585
586cescape(ex: ref Exec, nil, nil: ref Ecmascript->Obj, args: array of ref Val): ref Val
587{
588	s := toString(ex, biarg(args, 0));
589	t := "";
590	for(i := 0; i < len s; i++){
591		c := s[i];
592		case c{
593		'A' to 'Z' or
594		'a' to 'z' or
595		'0' to '9' or
596		'@' or '*' or '_' or '+' or '-' or '.' or '/' =>
597			t[len t] = s[i];
598		* =>
599			e := "";
600			do{
601				d := c & 16rf;
602				e = "0123456789abcdef"[d:d+1] + e;
603				c >>= 4;
604			}while(c);
605			if(len e & 1)
606				e = "0" + e;
607			if(len e == 4)
608				e = "u" + e;
609			t += "%" + e;
610		}
611	}
612	return strval(t);
613}
614
615cunescape(ex: ref Exec, nil, nil: ref Ecmascript->Obj, args: array of ref Val): ref Val
616{
617	s := toString(ex, biarg(args, 0));
618	t := "";
619	for(i := 0; i < len s; i++){
620		c := s[i];
621		if(c == '%'){
622			if(i + 5 < len s && s[i+1] == 'u'){
623				(v, e) := str->toint(s[i+2:i+6], 16);
624				if(e == ""){
625					c = v;
626					i += 5;
627				}
628			}else if(i + 2 < len s){
629				(v, e) := str->toint(s[i+1:i+3], 16);
630				if(e == ""){
631					c = v;
632					i += 2;
633				}
634			}
635		}
636		t[len t] = c;
637	}
638	return strval(t);
639}
640
641cisNaN(ex: ref Exec, nil, nil: ref Ecmascript->Obj, args: array of ref Val): ref Val
642{
643	if(math->isnan(toNumber(ex, biarg(args, 0))))
644		return true;
645	return false;
646}
647
648cisFinite(ex: ref Exec, nil, nil: ref Ecmascript->Obj, args: array of ref Val): ref Val
649{
650	r := toNumber(ex, biarg(args, 0));
651	if(math->isnan(r) || r == +Infinity || r == -Infinity)
652		return false;
653	return true;
654}
655
656cobj(ex: ref Exec, f, nil: ref Ecmascript->Obj, args: array of ref Val): ref Val
657{
658	o: ref Obj;
659
660	v := biarg(args, 0);
661
662	if(isnull(v) || isundefined(v))
663		o = nobj(ex, f, args);
664	else
665		o = toObject(ex, v);
666	return objval(o);
667}
668
669nobj(ex: ref Exec, nil: ref Ecmascript->Obj, args: array of ref Val): ref Ecmascript->Obj
670{
671	o: ref Obj;
672
673	v := biarg(args, 0);
674
675	case v.ty{
676	TNull or TUndef =>
677		o = mkobj(ex.objproto, "Object");
678	TBool =>
679		o = mkobj(ex.boolproto, "Boolean");
680		o.val = v;
681	TStr =>
682		o = mkobj(ex.strproto, "String");
683		o.val = v;
684		varinstant(o, DontEnum|DontDelete|ReadOnly, "length", ref RefVal(numval(real len v.str)));
685	TNum =>
686		o = mkobj(ex.numproto, "Number");
687		o.val = v;
688	TObj =>
689		o = v.obj;
690	TRegExp =>
691		o = mkobj(ex.regexpproto, "RegExp");
692		o.val = v;
693		varinstant(o, DontEnum|DontDelete|ReadOnly, "length", ref RefVal(numval(real len v.rev.p)));
694		varinstant(o, DontEnum|DontDelete|ReadOnly, "source", ref RefVal(strval(v.rev.p)));
695		varinstant(o, DontEnum|DontDelete|ReadOnly, "global", ref RefVal(strhas(v.rev.f, 'g')));
696		varinstant(o, DontEnum|DontDelete|ReadOnly, "ignoreCase", ref RefVal(strhas(v.rev.f, 'i')));
697		varinstant(o, DontEnum|DontDelete|ReadOnly, "multiline", ref RefVal(strhas(v.rev.f, 'm')));
698		varinstant(o, DontEnum|DontDelete, "lastIndex", ref RefVal(numval(real v.rev.i)));
699
700	* =>
701		runtime(ex, ReferenceError, "unknown type in Object constructor");
702	}
703	return o;
704}
705
706cobjprototoString(nil: ref Exec, nil, this: ref Ecmascript->Obj, nil: array of ref Val): ref Val
707{
708	return strval("[object " + this.class + "]");
709}
710
711cobjprotovalueOf(nil: ref Exec, nil, this: ref Ecmascript->Obj, nil: array of ref Val): ref Val
712{
713	return objval(this);
714}
715
716cobjprotohasownprop(ex: ref Exec, nil, this: ref Ecmascript->Obj, args: array of ref Val): ref Val
717{
718	o := this;
719	s := toString(ex, biarg(args, 0));
720	p := o.prototype;
721	o.prototype = nil;
722	v := eshasproperty(ex, o, s, 0);
723	o.prototype = p;
724	return v;
725}
726
727cobjprotoisprotoof(nil: ref Exec, nil, this: ref Ecmascript->Obj, args: array of ref Val): ref Val
728{
729	o := this;
730	v := biarg(args, 0);
731	if(!isobj(v))
732		return false;
733	for(p := v.obj.prototype; p != nil; p = p.prototype)
734		if(p == o)
735			return true;
736	return false;
737}
738
739cobjprotopropisenum(ex: ref Exec, nil, this: ref Ecmascript->Obj, args: array of ref Val): ref Val
740{
741	return eshasenumprop(this, toString(ex, biarg(args, 0)));
742}
743
744nfunc(ex: ref Exec, nil: ref Ecmascript->Obj, args: array of ref Val): ref Ecmascript->Obj
745{
746	params := "";
747	body := "";
748	sep := "";
749	for(i := 0; i < len args - 1; i++){
750		params += sep + toString(ex, args[i]);
751		sep = ",";
752	}
753	if(i < len args)
754		body = toString(ex, args[i]);
755
756	p := mkparser(ex, "function anonymous("+params+"){"+body+"}");
757	fundecl(ex, p, 0);
758	if(p.errors)
759		runtime(ex, SyntaxError, ex.error);
760	if(p.code.vars[0].name != "anonymous")
761		runtime(ex, SyntaxError, "parse failure");
762	return p.code.vars[0].val.val.obj;
763}
764
765cfuncprototoString(ex: ref Exec, nil, this: ref Ecmascript->Obj, nil: array of ref Val): ref Val
766{
767	if(this.call == nil)
768		runtime(ex, TypeError, "Function.prototype.toString called for a non-Function object");
769	return strval(funcprint(ex, this));
770}
771
772nerr(ex: ref Exec, f: ref Ecmascript->Obj, args: array of ref Val, proto: ref Obj): ref Ecmascript->Obj
773{
774	msg := biarg(args, 0);
775	if(msg == undefined)
776		s := "";
777	else
778		s = toString(ex, msg);
779	o := mkobj(proto, f.val.str);
780	varinstant(o, DontEnum|DontDelete|ReadOnly, "length", ref RefVal(numval(real 1)));
781	varinstant(o, DontEnum|DontDelete, "name", ref RefVal(strval(f.val.str)));
782	varinstant(o, DontEnum|DontDelete, "message", ref RefVal(strval(s)));
783	return o;
784}
785
786cfuncprotoapply(ex: ref Exec, nil, this: ref Ecmascript->Obj, args: array of ref Val): ref Val
787{
788	ar: ref Obj;
789
790	if(this.call == nil || !isfuncobj(this))
791		runtime(ex, TypeError, "Function.prototype.apply called for a non-Function object");
792	v := biarg(args, 0);
793	if(v == null || v == undefined)
794		th := ex.global;
795	else
796		th = coerceToObj(ex, v).obj;
797	v = biarg(args, 1);
798	if(v == null || v == undefined)
799		l := 0;
800	else{
801		if(!isobj(v))
802			runtime(ex, TypeError, "Function.prototype.apply non-array argument");
803		ar = v.obj;
804		v = esget(ex, ar, "length", 0);
805		if(v == undefined)
806			runtime(ex, TypeError, "Function.prototype.apply non-array argument");
807		l = int toUint32(ex, v);
808	}
809	args = array[l] of ref Val;
810	for(i := 0; i < l; i++)
811		args[i] = esget(ex, ar, string i, 0);
812	return  getValue(ex, escall(ex, this, th, args, 0));
813}
814
815cfuncprotocall(ex: ref Exec, nil, this: ref Ecmascript->Obj, args: array of ref Val): ref Val
816{
817	if(this.call == nil || !isfuncobj(this))
818		runtime(ex, TypeError, "Function.prototype.call called for a non-Function object");
819	v := biarg(args, 0);
820	if(v == null || v == undefined)
821		th := ex.global;
822	else
823		th = coerceToObj(ex, v).obj;
824	return  getValue(ex, escall(ex, this, th, args[1: ], 0));
825}
826
827cerrprototoString(ex: ref Exec, nil, this: ref Ecmascript->Obj, nil: array of ref Val): ref Val
828{
829	return esget(ex, this, "message", 0);
830}
831
832narray(ex: ref Exec, nil: ref Ecmascript->Obj, args: array of ref Val): ref Ecmascript->Obj
833{
834	o := mkobj(ex.arrayproto, "Array");
835	length := big len args;
836	if(length == big 1 && isnum(coerceToVal(args[0]))){
837		length = toUint32(ex, args[0]);
838		varinstant(o, DontEnum|DontDelete, "length", ref RefVal(numval(real length)));
839	}else{
840		varinstant(o, DontEnum|DontDelete, "length", ref RefVal(numval(real length)));
841		for(i := 0; i < len args; i++)
842			esput(ex, o, string i, args[i], 0);
843	}
844
845	return o;
846}
847
848carrayprototoString(ex: ref Exec, nil, this: ref Ecmascript->Obj, nil: array of ref Val): ref Val
849{
850	return carrayprotojoin(ex, nil, this, nil);
851}
852
853carrayprotoconcat(ex: ref Exec, nil, this: ref Ecmascript->Obj, args: array of ref Val): ref Val
854{
855	v: ref Val;
856	e: ref Obj;
857
858	a := narray(ex, nil, nil);
859	n := 0;
860	nargs := len args;
861	for(i := -1; i < nargs; i++){
862		if(i < 0){
863			e = this;
864			v = objval(e);
865		}
866		else{
867			v = biarg(args, i);
868			if(isobj(v))
869				e = v.obj;
870			else
871				e = nil;
872		}
873		if(e != nil && isarray(e)){
874			leng := int toUint32(ex, esget(ex, e, "length", 0));
875			for(k := 0; k < leng; k++){
876				av := esget(ex, e, string k, 0);
877				if(v != undefined)
878					esput(ex, a, string n, av, 0);
879				n++;
880			}
881		}
882		else{
883			esput(ex, a, string n, v, 0);
884			n++;
885		}
886	}
887	esput(ex, a, "length", numval(real n), 0);
888	return objval(a);
889}
890
891carrayprotojoin(ex: ref Exec, nil, this: ref Ecmascript->Obj, args: array of ref Val): ref Val
892{
893	length := toUint32(ex, esget(ex, this, "length", 0));
894	sepv := biarg(args, 0);
895	sep := ",";
896	if(sepv != undefined)
897		sep = toString(ex, sepv);
898	s := "";
899	ss := "";
900	for(i := big 0; i < length; i++){
901		tv := esget(ex, this, string i, 0);
902		t := "";
903		if(tv != undefined && !isnull(tv))
904			t = toString(ex, tv);
905		s += ss + t;
906		ss = sep;
907	}
908	return strval(s);
909}
910
911carrayprotoreverse(ex: ref Exec, nil, this: ref Ecmascript->Obj, nil: array of ref Val): ref Val
912{
913	length := toUint32(ex, esget(ex, this, "length", 0));
914	mid := length / big 2;
915	for(i := big 0; i < mid; i++){
916		i1 := string i;
917		v1 := esget(ex, this, i1, 0);
918		i2 := string(length - i - big 1);
919		v2 := esget(ex, this, i2, 0);
920		if(v2 == undefined)
921			esdelete(ex, this, i1, 0);
922		else
923			esput(ex, this, i1, v2, 0);
924		if(v1 == undefined)
925			esdelete(ex, this, i2, 0);
926		else
927			esput(ex, this, i2, v1, 0);
928	}
929	return objval(this);
930}
931
932carrayprotopop(ex: ref Exec, nil, this: ref Ecmascript->Obj, nil: array of ref Val): ref Val
933{
934	leng := toUint32(ex, esget(ex, this, "length", 0));
935	if(leng == big 0){
936		esput(ex, this, "length", numval(0.), 0);
937		return undefined;
938	}
939	ind := string (leng-big 1);
940	v := esget(ex, this, ind, 0);
941	esdelete(ex, this, ind, 0);
942	esput(ex, this, "length", numval(real (leng-big 1)), 0);
943	return v;
944}
945
946carrayprotopush(ex: ref Exec, nil, this: ref Ecmascript->Obj, args: array of ref Val): ref Val
947{
948	leng := toUint32(ex, esget(ex, this, "length", 0));
949	nargs := len args;
950	for(i := 0; i < nargs; i++)
951		esput(ex, this, string (leng+big i), biarg(args, i), 0);
952	nv := numval(real (leng+big nargs));
953	esput(ex, this, "length", nv, 0);
954	return nv;
955}
956
957carrayprotoshift(ex: ref Exec, nil, this: ref Ecmascript->Obj, nil: array of ref Val): ref Val
958{
959	leng := int toUint32(ex, esget(ex, this, "length", 0));
960	if(leng == 0){
961		esput(ex, this, "length", numval(0.), 0);
962		return undefined;
963	}
964	v0 := esget(ex, this, "0", 0);
965	for(k := 1; k < leng; k++){
966		v := esget(ex, this, string k, 0);
967		if(v == undefined)
968			esdelete(ex, this, string (k-1), 0);
969		else
970			esput(ex, this, string (k-1), v, 0);
971	}
972	esdelete(ex, this, string (leng-1), 0);
973	esput(ex, this, "length", numval(real (leng-1)), 0);
974	return v0;
975}
976
977carrayprotounshift(ex: ref Exec, nil, this: ref Ecmascript->Obj, args: array of ref Val): ref Val
978{
979	leng := int toUint32(ex, esget(ex, this, "length", 0));
980	nargs := len args;
981	for(i := leng-1; i >= 0; i--){
982		v := esget(ex, this, string i, 0);
983		if(v == undefined)
984			esdelete(ex, this, string (i+nargs), 0);
985		else
986			esput(ex, this, string (i+nargs), v, 0);
987	}
988	for(i = 0; i < nargs; i++)
989		esput(ex, this, string i, biarg(args, i), 0);
990	nv := numval(real (leng+nargs));
991	esput(ex, this, "length", nv, 0);
992	return nv;
993}
994
995carrayprotoslice(ex: ref Exec, nil, this: ref Ecmascript->Obj, args: array of ref Val): ref Val
996{
997	a := narray(ex, nil, nil);
998	leng := int toUint32(ex, esget(ex, this, "length", 0));
999	start := toInt32(ex, biarg(args, 0));
1000	if(start < 0) start += leng;
1001	if(start < 0) start = 0;
1002	if(start > leng) start = leng;
1003	if(biarg(args, 1) == undefined)
1004		end := leng;
1005	else
1006		end = toInt32(ex, biarg(args, 1));
1007	if(end < 0) end += leng;
1008	if(end < 0) end = 0;
1009	if(end > leng) end = leng;
1010	n := 0;
1011	for(k := start; k < end; k++){
1012		v := esget(ex, this, string k, 0);
1013		if(v != undefined)
1014			esput(ex, a, string n, v, 0);
1015		n++;
1016	}
1017	esput(ex, a, "length", numval(real n), 0);
1018	return objval(a);
1019}
1020
1021carrayprotosplice(ex: ref Exec, nil, this: ref Ecmascript->Obj, args: array of ref Val): ref Val
1022{
1023	a := narray(ex, nil, nil);
1024	leng := int toUint32(ex, esget(ex, this, "length", 0));
1025	start := toInt32(ex, biarg(args, 0));
1026	if(start < 0) start += leng;
1027	if(start < 0) start = 0;
1028	if(start > leng) start = leng;
1029	delc := toInt32(ex, biarg(args, 1));
1030	if(delc < 0) delc = 0;
1031	if(start+delc > leng) delc = leng-start;
1032	for(k := 0; k < delc; k++){
1033		v := esget(ex, this, string (k+start), 0);
1034		if(v != undefined)
1035			esput(ex, a, string k, v, 0);
1036	}
1037	esput(ex, a, "length", numval(real delc), 0);
1038	nargs := len args - 2;
1039	if(nargs < delc){
1040		for(k = start; k < leng-delc; k++){
1041			v := esget(ex, this, string (k+delc), 0);
1042			if(v == undefined)
1043				esdelete(ex, this, string (k+nargs), 0);
1044			else
1045				esput(ex, this, string (k+nargs), v, 0);
1046		}
1047		for(k = leng; k > leng-delc+nargs; k--)
1048			esdelete(ex, this, string (k-1), 0);
1049	}
1050	else if(nargs > delc){
1051		for(k = leng-delc; k > start; k--){
1052			v := esget(ex, this, string (k+delc-1), 0);
1053			if(v == undefined)
1054				esdelete(ex, this, string (k+nargs-1), 0);
1055			else
1056				esput(ex, this, string (k+nargs-1), v, 0);
1057		}
1058	}
1059	for(k = start; k < start+nargs; k++)
1060		esput(ex, this, string k, biarg(args, k-start+2), 0);
1061	esput(ex, this, "length", numval(real (leng-delc+nargs)), 0);
1062	return objval(a);
1063}
1064
1065carrayprotosort(ex: ref Exec, nil, this: ref Ecmascript->Obj, args: array of ref Val): ref Val
1066{
1067	length := toUint32(ex, esget(ex, this, "length", 0));
1068	cmp := biarg(args, 0);
1069	if(cmp == undefined)
1070		cmp = nil;
1071	else if(!isobj(cmp) || cmp.obj.call == nil)
1072		runtime(ex, TypeError, "Array.prototype.sort argument is not a function");
1073
1074	#
1075	# shell sort
1076	#
1077	for(m := (length+big 3)/big 5; m > big 0; m = (m+big 1)/big 3){
1078		for(i := length-m; i-- != big 0;){
1079			v1, v2 : ref Val = nil;
1080			ji := big -1;
1081			for(j := i+m; j < length; j += m){
1082				if(v1 == nil)
1083					v1 = esget(ex, this, string(j-m), 0);
1084				v2 = esget(ex, this, string(j), 0);
1085				cr : real;
1086				if(v1 == undefined && v2 == undefined)
1087					cr = 0.;
1088				else if(v1 == undefined)
1089					cr = 1.;
1090				else if(v2 == undefined)
1091					cr = -1.;
1092				else if(cmp == nil){
1093					s1 := toString(ex, v1);
1094					s2 := toString(ex, v2);
1095					if(s1 < s2)
1096						cr = -1.;
1097					else if(s1 > s2)
1098						cr = 1.;
1099					else
1100						cr = 0.;
1101				}else{
1102					#
1103					# this value not specified by docs
1104					#
1105					cr = toNumber(ex, getValue(ex, escall(ex, cmp.obj, this, array[] of {v1, v2}, 0)));
1106				}
1107				if(cr <= 0.)
1108					break;
1109				if(v2 == undefined)
1110					esdelete(ex, this, string(j-m), 0);
1111				else
1112					esput(ex, this, string(j-m), v2, 0);
1113				ji = j;
1114			}
1115			if(ji != big -1){
1116				if(v1 == undefined)
1117					esdelete(ex, this, string(ji), 0);
1118				else
1119					esput(ex, this, string(ji), v1, 0);
1120			}
1121		}
1122	}
1123	return objval(this);
1124}
1125
1126cstr(ex: ref Exec, nil, nil: ref Ecmascript->Obj, args: array of ref Val): ref Val
1127{
1128	s := "";
1129	if(len args > 0)
1130		s = toString(ex, biarg(args, 0));
1131	return strval(s);
1132}
1133
1134cstrfromCharCode(ex: ref Exec, nil, nil: ref Ecmascript->Obj, args: array of ref Val): ref Val
1135{
1136	s := "";
1137	for(i := 0; i < len args; i++)
1138		s[i] = toUint16(ex, args[i]);
1139	return strval(s);
1140}
1141
1142cstrprototoString(ex: ref Exec, nil, this: ref Ecmascript->Obj, nil: array of ref Val): ref Val
1143{
1144	if(!isstrobj(this))
1145		runtime(ex, TypeError, "String.prototype.toString called on non-String object");
1146	return this.val;
1147}
1148
1149cstrprotocharAt(ex: ref Exec, nil, this: ref Ecmascript->Obj, args: array of ref Val): ref Val
1150{
1151	s := toString(ex, objval(this));
1152	rpos := toInteger(ex, biarg(args, 0));
1153	if(rpos < 0. || rpos >= real len s)
1154		s = "";
1155	else{
1156		pos := int rpos;
1157		s = s[pos: pos+1];
1158	}
1159	return strval(s);
1160}
1161
1162cstrprotocharCodeAt(ex: ref Exec, nil, this: ref Ecmascript->Obj, args: array of ref Val): ref Val
1163{
1164	s := toString(ex, objval(this));
1165	rpos := toInteger(ex, biarg(args, 0));
1166	if(rpos < 0. || rpos >= real len s)
1167		c := Math->NaN;
1168	else
1169		c = real s[int rpos];
1170	return numval(c);
1171}
1172
1173cstrprotoindexOf(ex: ref Exec, nil, this: ref Ecmascript->Obj, args: array of ref Val): ref Val
1174{
1175	s := toString(ex, objval(this));
1176	t := toString(ex, biarg(args, 0));
1177	rpos := toInteger(ex, biarg(args, 1));
1178	if(rpos < 0.)
1179		rpos = 0.;
1180	else if(rpos > real len s)
1181		rpos = real len s;
1182	lent := len t;
1183	stop := len s - lent;
1184	for(i := int rpos; i <= stop; i++)
1185		if(s[i:i+lent] == t)
1186			break;
1187	if(i > stop)
1188		i = -1;
1189	return numval(real i);
1190}
1191
1192cstrprotolastindexOf(ex: ref Exec, nil, this: ref Ecmascript->Obj, args: array of ref Val): ref Val
1193{
1194	s := toString(ex, objval(this));
1195	t := toString(ex, biarg(args, 0));
1196	v := biarg(args, 1);
1197	rpos := toNumber(ex, v);
1198	if(math->isnan(rpos))
1199		rpos = Math->Infinity;
1200	else
1201		rpos = toInteger(ex, v);
1202	if(rpos < 0.)
1203		rpos = 0.;
1204	else if(rpos > real len s)
1205		rpos = real len s;
1206	lent := len t;
1207	i := len s - lent;
1208	if(i > int rpos)
1209		i = int rpos;
1210	for(; i >= 0; i--)
1211		if(s[i:i+lent] == t)
1212			break;
1213	return numval(real i);
1214}
1215
1216cstrprotosplit(ex: ref Exec, nil, this: ref Ecmascript->Obj, args: array of ref Val): ref Val
1217{
1218	s := toString(ex, objval(this));
1219	a := narray(ex, nil, nil);
1220	tv := biarg(args, 0);
1221	ai := 0;
1222	if(tv == undefined)
1223		esput(ex, a, string ai, strval(s), 0);
1224	else{
1225		t := toString(ex, tv);
1226		lent := len t;
1227		stop := len s - lent;
1228		pos := 0;
1229		if(lent == 0){
1230			for(; pos < stop; pos++)
1231				esput(ex, a, string ai++, strval(s[pos:pos+1]), 0);
1232		}else{
1233			for(k := pos; k <= stop; k++){
1234				if(s[k:k+lent] == t){
1235					esput(ex, a, string ai++, strval(s[pos:k]), 0);
1236					pos = k + lent;
1237					k = pos - 1;
1238				}
1239			}
1240			esput(ex, a, string ai, strval(s[pos:k]), 0);
1241		}
1242	}
1243	return objval(a);
1244}
1245
1246cstrprotosubstring(ex: ref Exec, nil, this: ref Ecmascript->Obj, args: array of ref Val): ref Val
1247{
1248	s := toString(ex, objval(this));
1249	rstart := toInteger(ex, biarg(args, 0));
1250	lens := real len s;
1251	rend := lens;
1252	if(len args >= 2)
1253		rend = toInteger(ex, biarg(args, 1));
1254	if(rstart < 0.)
1255		rstart = 0.;
1256	else if(rstart > lens)
1257		rstart = lens;
1258	if(rend < 0.)
1259		rend = 0.;
1260	else if(rend > lens)
1261		rend = lens;
1262	if(rstart > rend){
1263		lens = rstart;
1264		rstart = rend;
1265		rend = lens;
1266	}
1267	return strval(s[int rstart: int rend]);
1268}
1269
1270cstrprotosubstr(ex: ref Exec, nil, this: ref Ecmascript->Obj, args: array of ref Val): ref Val
1271{
1272	s := toString(ex, objval(this));
1273	ls := len s;
1274	start := toInt32(ex, biarg(args, 0));
1275	if(biarg(args, 1) == undefined)
1276		leng := ls;
1277	else
1278		leng = toInt32(ex, biarg(args, 1));
1279	if(start < 0)
1280		start += ls;
1281	if(start < 0)
1282		start = 0;
1283	if(leng < 0)
1284		leng = 0;
1285	if(start+leng > ls)
1286		leng = ls-start;
1287	if(leng <= 0)
1288		s = "";
1289	else
1290		s = s[start: start+leng];
1291	return strval(s);
1292}
1293
1294cstrprotoslice(ex: ref Exec, nil, this: ref Ecmascript->Obj, args: array of ref Val): ref Val
1295{
1296	s := toString(ex, objval(this));
1297	ls := len s;
1298	start := toInt32(ex, biarg(args, 0));
1299	if(biarg(args, 1) == undefined)
1300		end := ls;
1301	else
1302		end = toInt32(ex, biarg(args, 1));
1303	if(start < 0)
1304		start += ls;
1305	if(start < 0)
1306		start = 0;
1307	if(start > ls)
1308		start = ls;
1309	if(end < 0)
1310		end += ls;
1311	if(end < 0)
1312		end = 0;
1313	if(end > ls)
1314		end = ls;
1315	leng := end-start;
1316	if(leng < 0)
1317		leng = 0;
1318	return strval(s[start: start+leng]);
1319}
1320
1321cstrprotocmp(ex: ref Exec, nil, this: ref Ecmascript->Obj, args: array of ref Val): ref Val
1322{
1323	s := toString(ex, objval(this));
1324	t := toString(ex, biarg(args, 0));
1325	r := 0;
1326	if(s < t)
1327		r = -1;
1328	else if(s > t)
1329		r = 1;
1330	return numval(real r);
1331}
1332
1333cstrprotoconcat(ex: ref Exec, nil, this: ref Ecmascript->Obj, args: array of ref Val): ref Val
1334{
1335	s := toString(ex, objval(this));
1336	n := len args;
1337	for(i := 0; i < n; i++)
1338		s += toString(ex, biarg(args, i));
1339	return strval(s);
1340}
1341
1342# this doesn't use unicode tolower
1343cstrprototoLowerCase(ex: ref Exec, nil, this: ref Ecmascript->Obj, nil: array of ref Val): ref Val
1344{
1345	s := toString(ex, objval(this));
1346	for(i := 0; i < len s; i++)
1347		s[i] = tolower(s[i]);
1348	return strval(s);
1349}
1350
1351#this doesn't use unicode toupper
1352cstrprototoUpperCase(ex: ref Exec, nil, this: ref Ecmascript->Obj, nil: array of ref Val): ref Val
1353{
1354	s := toString(ex, objval(this));
1355	for(i := 0; i < len s; i++)
1356		s[i] = toupper(s[i]);
1357	return strval(s);
1358}
1359
1360cbool(ex: ref Exec, nil, nil: ref Ecmascript->Obj, args: array of ref Val): ref Val
1361{
1362	return toBoolean(ex, biarg(args, 0));
1363}
1364
1365tolower(c: int): int
1366{
1367	if(c >= 'A' && c <= 'Z')
1368		return c - 'A' + 'a';
1369	return c;
1370}
1371
1372toupper(c: int): int
1373{
1374	if(c >= 'a' && c <= 'z')
1375		return c - 'a' + 'A';
1376	return c;
1377}
1378
1379cboolprototoString(ex: ref Exec, nil, this: ref Ecmascript->Obj, nil: array of ref Val): ref Val
1380{
1381	if(!isboolobj(this))
1382		runtime(ex, TypeError, "Boolean.prototype.toString called on non-Boolean object");
1383	return strval(toString(ex, this.val));
1384}
1385
1386cboolprotovalueOf(ex: ref Exec, nil, this: ref Ecmascript->Obj, nil: array of ref Val): ref Val
1387{
1388	if(!isboolobj(this))
1389		runtime(ex, TypeError, "Boolean.prototype.valueOf called on non-Boolean object");
1390	return this.val;
1391}
1392
1393cnum(ex: ref Exec, nil, nil: ref Ecmascript->Obj, args: array of ref Val): ref Val
1394{
1395	r := 0.;
1396	if(len args > 0)
1397		r = toNumber(ex, biarg(args, 0));
1398	return numval(r);
1399}
1400
1401cnumprototoString(ex: ref Exec, nil, this: ref Ecmascript->Obj, nil: array of ref Val): ref Val
1402{
1403	if(!isnumobj(this))
1404		runtime(ex, TypeError, "Number.prototype.toString called on non-Number object");
1405	return this.val;
1406}
1407
1408cnumprotovalueOf(ex: ref Exec, nil, this: ref Ecmascript->Obj, nil: array of ref Val): ref Val
1409{
1410	if(!isnumobj(this))
1411		runtime(ex, TypeError, "Number.prototype.valueOf called on non-Number object");
1412	return strval(toString(ex, this.val));
1413}
1414
1415cnumprotofix(ex: ref Exec, nil, this: ref Ecmascript->Obj, args: array of ref Val): ref Val
1416{
1417	if(!isnumobj(this))
1418		runtime(ex, TypeError, "Number.prototype.toFixed called on non-Number object");
1419	v := biarg(args, 0);
1420	if(v == undefined)
1421		f := 0;
1422	else
1423		f = toInt32(ex, v);
1424	if(f < 0 || f > 20)
1425		runtime(ex, RangeError, "fraction digits out of range");
1426	x := toNumber(ex, this.val);
1427	if(isnan(x) || x == Infinity || x == -Infinity)
1428		s := toString(ex, this.val);
1429	else
1430		s = sys->sprint("%.*f", f, x);
1431	return strval(s);
1432}
1433
1434cnumprotoexp(ex: ref Exec, nil, this: ref Ecmascript->Obj, args: array of ref Val): ref Val
1435{
1436	if(!isnumobj(this))
1437		runtime(ex, TypeError, "Number.prototype.toExponential called on non-Number object");
1438	v := biarg(args, 0);
1439	if(v == undefined)
1440		f := 6;
1441	else
1442		f = toInt32(ex, v);
1443	if(f < 0 || f > 20)
1444		runtime(ex, RangeError, "fraction digits out of range");
1445	x := toNumber(ex, this.val);
1446	if(isnan(x) || x == Infinity || x == -Infinity)
1447		s := toString(ex, this.val);
1448	else
1449		s = sys->sprint("%.*e", f, x);
1450	return strval(s);
1451}
1452
1453cnumprotoprec(ex: ref Exec, nil, this: ref Ecmascript->Obj, args: array of ref Val): ref Val
1454{
1455	if(!isnumobj(this))
1456		runtime(ex, TypeError, "Number.prototype.toPrecision called on non-Number object");
1457	v := biarg(args, 0);
1458	if(v == undefined)
1459		return strval(toString(ex, this.val));
1460	p := toInt32(ex, v);
1461	if(p < 1 || p > 21)
1462		runtime(ex, RangeError, "fraction digits out of range");
1463	x := toNumber(ex, this.val);
1464	if(isnan(x) || x == Infinity || x == -Infinity)
1465		s := toString(ex, this.val);
1466	else{
1467		y := x;
1468		if(y < 0.0)
1469			y = -y;
1470		er := math->log10(y);
1471		(e, ef) := math->modf(er);
1472		if(ef < 0.0)
1473			e--;
1474		if(e < -6 || e >=p)
1475			s = sys->sprint("%.*e", p-1, x);
1476		else
1477			s = sys->sprint("%.*f", p-1, x);
1478	}
1479	return strval(s);
1480}
1481