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