# # utility functions # biinst(o: ref Obj, bi: Builtin, p: ref Obj, h: ESHostobj): ref Obj { bo := mkobj(p, "Function"); bo.call = mkcall(nil, bi.params); bo.val = strval(bi.val); bo.host = h; varinstant(bo, DontEnum|DontDelete|ReadOnly, "length", ref RefVal(numval(real bi.length))); varinstant(o, DontEnum, bi.name, ref RefVal(objval(bo))); return bo; } biminst(o: ref Obj, bis: array of Builtin, p: ref Obj, h: ESHostobj) { for(i := 0; i < len bis; i++) biinst(o, bis[i], p, h); } biarg(args: array of ref Val, i: int): ref Val { if(i < len args) return args[i]; return undefined; } # # interface to builtin objects # get(ex: ref Ecmascript->Exec, o: ref Ecmascript->Obj, property: string): ref Ecmascript->Val { return esget(ex, o, property, 1); } put(ex: ref Ecmascript->Exec, o: ref Ecmascript->Obj, property: string, val: ref Ecmascript->Val) { return esput(ex, o, property, val, 1); } canput(ex: ref Ecmascript->Exec, o: ref Ecmascript->Obj, property: string): ref Ecmascript->Val { return escanput(ex, o, property, 1); } hasproperty(ex: ref Ecmascript->Exec, o: ref Ecmascript->Obj, property: string): ref Ecmascript->Val { return eshasproperty(ex, o, property, 1); } delete(ex: ref Ecmascript->Exec, o: ref Ecmascript->Obj, property: string) { return esdelete(ex, o, property, 1); } defaultval(ex: ref Ecmascript->Exec, o: ref Ecmascript->Obj, tyhint: int): ref Ecmascript->Val { return esdefaultval(ex, o, tyhint, 1); } call(ex: ref Ecmascript->Exec, f, this: ref Ecmascript->Obj, args: array of ref Ecmascript->Val): ref Ecmascript->Ref { x, y: real; v: ref Val; if(this == nil) this = ex.global; if(f.host != me) return escall(ex, f, this, args); case f.val.str{ "eval" => v = ceval(ex, f, this, args); "parseInt" => v = cparseInt(ex, f, this, args); "parseFloat" => v = cparseFloat(ex, f, this, args); "escape" => v = cescape(ex, f, this, args); "unescape" => v = cunescape(ex, f, this, args); "isNaN" => v = cisNaN(ex, f, this, args); "isFinite" => v = cisFinite(ex, f, this, args); "Object" => v = cobj(ex, f, this, args); "Object.prototype.toString" => v = cobjprototoString(ex, f, this, args); "Object.prototype.valueOf" => v = cobjprotovalueOf(ex, f, this, args); "Function" => v = objval(nfunc(ex, f, args)); "Function.Prototype" => v = undefined; "Function.prototype.toString" => v = cfuncprototoString(ex, f, this, args); "Array" => v = objval(narray(ex, f, args)); "Array.prototype.toString" => v = carrayprototoString(ex, f, this, args); "Array.prototype.join" => v = carrayprotojoin(ex, f, this, args); "Array.prototype.reverse" => v = carrayprotoreverse(ex, f, this, args); "Array.prototype.sort" => v = carrayprotosort(ex, f, this, args); "String" => v = cstr(ex, f, this, args); "String.fromCharCode" => v = cstrfromCharCode(ex, f, this, args); "String.prototype.toString" => v = cstrprototoString(ex, f, this, args); "String.prototype.valueOf" => v = cstrprototoString(ex, f, this, args); "String.prototype.charAt" => v = cstrprotocharAt(ex, f, this, args); "String.prototype.charCodeAt" => v = cstrprotocharCodeAt(ex, f, this, args); "String.prototype.indexOf" => v = cstrprotoindexOf(ex, f, this, args); "String.prototype.lastIndexOf" => v = cstrprotolastindexOf(ex, f, this, args); "String.prototype.split" => v = cstrprotosplit(ex, f, this, args); "String.prototype.substring" => v = cstrprotosubstring(ex, f, this, args); "String.prototype.toLowerCase" => v = cstrprototoLowerCase(ex, f, this, args); "String.prototype.toUpperCase" => v = cstrprototoUpperCase(ex, f, this, args); # JavaScript 1.0 "String.prototype.anchor" or "String.prototype.big" or "String.prototype.blink" or "String.prototype.bold" or "String.prototype.fixed" or "String.prototype.fontcolor" or "String.prototype.fontsize" or "String.prototype.italics" or "String.prototype.link" or "String.prototype.small" or "String.prototype.strike" or "String.prototype.sub" or "String.prototype.sup" => s := toString(ex, objval(this)); arg := toString(ex, biarg(args, 0)); tag, endtag: string; case f.val.str{ "String.prototype.anchor" => tag = ""; endtag = ""; "String.prototype.big" => tag = ""; endtag = ""; "String.prototype.blink" => tag = ""; endtag = ""; "String.prototype.bold" => tag = ""; endtag = ""; "String.prototype.fixed" => tag = ""; endtag = ""; "String.prototype.fontcolor" => tag = ""; endtag = ""; "String.prototype.fontsize" => tag = ""; endtag = ""; "String.prototype.italics" => tag = ""; endtag = ""; "String.prototype.link" => tag = ""; endtag = ""; "String.prototype.small" => tag = ""; endtag = ""; "String.prototype.strike" => tag = ""; endtag = ""; "String.prototype.sub" => tag = ""; endtag = ""; "String.prototype.sup" => tag = ""; endtag = ""; } v = strval(tag + s + endtag); "Boolean" => v = cbool(ex, f, this, args); "Boolean.prototype.toString" => v = cboolprototoString(ex, f, this, args); "Boolean.prototype.valueOf" => v = cboolprotovalueOf(ex, f, this, args); "Number" => v = cnum(ex, f, this, args); "Number.prototype.toString" => v = cnumprototoString(ex, f, this, args); "Number.prototype.valueOf" => v = cnumprotovalueOf(ex, f, this, args); "Math.abs" or "Math.acos" or "Math.asin" or "Math.atan" or "Math.ceil" or "Math.cos" or "Math.exp" or "Math.floor" or "Math.log" or "Math.round" or "Math.sin" or "Math.sqrt" or "Math.tan" => x = toNumber(ex, biarg(args, 0)); case f.val.str{ "Math.abs" => if(x < 0.) x = -x; else if(x == 0.) x = 0.; "Math.acos" => x = math->acos(x); "Math.asin" => x = math->asin(x); "Math.atan" => x = math->atan(x); "Math.ceil" => x = math->ceil(x); "Math.cos" => x = math->cos(x); "Math.exp" => x = math->exp(x); "Math.floor" => x = math->floor(x); "Math.log" => x = math->log(x); "Math.round" => if((x == .0 && copysign(1., x) == -1.) || (x < .0 && x >= -0.5)) x = -0.; else x = math->floor(x+.5); "Math.sin" => x = math->sin(x); "Math.sqrt" => x = math->sqrt(x); "Math.tan" => x = math->tan(x); } v = numval(x); "Math.random" => range := big 16r7fffffffffffffff; v = numval(real bigrand(range)/ real range); "Math.atan2" or "Math.max" or "Math.min" or "Math.pow" => x = toNumber(ex, biarg(args, 0)); y = toNumber(ex, biarg(args, 1)); case f.val.str{ "Math.atan2" => x = math->atan2(x, y); "Math.max" => if(x > y) ; else if(x < y) x = y; else if(x == y){ if(x == 0. && copysign(1., x) == -1. && copysign(1., y) == 1.) x = y; }else x = Math->NaN; "Math.min" => if(x < y) ; else if(x > y) x = y; else if(x == y){ if(x == 0. && copysign(1., x) == 1. && copysign(1., y) == -1.) x = y; }else x = Math->NaN; "Math.pow" => x = math->pow(x, y); } v = numval(x); "Date" => v = cdate(ex, f, this, args); "Date.parse" => v = cdateparse(ex, f, this, args); "Date.UTC" => v = cdateUTC(ex, f, this, args); "Date.prototype.toString" or "Date.prototype.toLocaleString" => v = cdateprototoString(ex, f, this, args); "Date.prototype.valueOf" or "Date.prototype.getTime" => v = cdateprotovalueOf(ex, f, this, args); "Date.prototype.getYear" or "Date.prototype.getFullYear" or "Date.prototype.getMonth" or "Date.prototype.getDate" or "Date.prototype.getDay" or "Date.prototype.getHours" or "Date.prototype.getMinutes" or "Date.prototype.getSeconds" => v = cdateprotoget(ex, f, this, args, !UTC); "Date.prototype.getUTCFullYear" or "Date.prototype.getUTCMonth" or "Date.prototype.getUTCDate" or "Date.prototype.getUTCDay" or "Date.prototype.getUTCHours" or "Date.prototype.getUTCMinutes" or "Date.prototype.getUTCSeconds" => v = cdateprotoget(ex, f, this, args, UTC); "Date.prototype.getMilliseconds" or "Date.prototype.getUTCMilliseconds" => v = cdateprotogetMilliseconds(ex, f, this, args); "Date.prototype.getTimezoneOffset" => v = cdateprotogetTimezoneOffset(ex, f, this, args); "Date.prototype.setTime" => v = cdateprotosetTime(ex, f, this, args); "Date.prototype.setMilliseconds" => v = cdateprotosetMilliseconds(ex, f, this, args, !UTC); "Date.prototype.setUTCMilliseconds" => v = cdateprotosetMilliseconds(ex, f, this, args, UTC); "Date.prototype.setSeconds" => v = cdateprotosetSeconds(ex, f, this, args, !UTC); "Date.prototype.setUTCSeconds" => v = cdateprotosetSeconds(ex, f, this, args, UTC); "Date.prototype.setMinutes" => v = cdateprotosetMinutes(ex, f, this, args, !UTC); "Date.prototype.setUTCMinutes" => v = cdateprotosetMinutes(ex, f, this, args, UTC); "Date.prototype.setHours" => v = cdateprotosetHours(ex, f, this, args, !UTC); "Date.prototype.setUTCHours" => v = cdateprotosetHours(ex, f, this, args, UTC); "Date.prototype.setDate" => v = cdateprotosetDate(ex, f, this, args, !UTC); "Date.prototype.setUTCDate" => v = cdateprotosetDate(ex, f, this, args, UTC); "Date.prototype.setMonth" => v = cdateprotosetMonth(ex, f, this, args, !UTC); "Date.prototype.setUTCMonth" => v = cdateprotosetMonth(ex, f, this, args, UTC); "Date.prototype.setFullYear" => v = cdateprotosetFullYear(ex, f, this, args, !UTC); "Date.prototype.setUTCFullYear" => v = cdateprotosetFullYear(ex, f, this, args, UTC); "Date.prototype.setYear" => v = cdateprotosetYear(ex, f, this, args); "Date.prototype.toUTCString" or "Date.prototype.toGMTString" => v = cdateprototoUTCString(ex, f, this, args); * => v = nil; } if(v == nil) runtime(ex, "unknown function "+f.val.str+" in builtin call"); return valref(v); } rsalt := big 12345678; randinit(seed: big) { rsalt = big seed; bigrand(big 1); bigrand(big 1); } RANDMASK: con (big 1<<63)-(big 1); bigrand(modulus: big): big { rsalt = rsalt * big 1103515245 + big 12345; if(modulus <= big 0) return big 0; return ((rsalt&RANDMASK)>>10) % modulus; } construct(ex: ref Ecmascript->Exec, f: ref Ecmascript->Obj, args: array of ref Ecmascript->Val): ref Ecmascript->Obj { if(f.host != me) runtime(ex, "ecmascript builtin called incorrectly"); case f.val.str{ "Object" => return nobj(ex, f, args); "Function" => return nfunc(ex, f, args); "Array" => return narray(ex, f, args); "String" or "Boolean" or "Number" => return coerceToObj(ex, call(ex, f, nil, args).val).obj; "Date" => return ndate(ex, f, args); } runtime(ex, "unknown constructor "+f.val.str+" in builtin construct"); return nil; } ceval(ex: ref Exec, nil, nil: ref Ecmascript->Obj, args: array of ref Val): ref Val { if(len args < 1) return undefined; vs := coerceToVal(args[0]); if(!isstr(vs)) return args[0]; (k, v) := eval(ex, vs.str); if(k != CNormal || v == nil) v = undefined; return v; } cparseInt(ex: ref Exec, nil, nil: ref Ecmascript->Obj, args: array of ref Val): ref Val { sv := biarg(args, 0); s := toString(ex, sv); neg := 0; i := 0; if(len s > i){ if(s[i] == '-'){ neg = 1; i++; }else if(s[i] == '+') i++; } rv := biarg(args, 1); if(rv == undefined) r := big 0; else r = big toInt32(ex, rv); if(r == big 0){ if(len s > i && s[i] == '0'){ r = big 8; if(len s >= i+2 && (s[i+1] == 'x' || s[i+1] == 'X')) r = big 16; }else r = big 10; }else if(r < big 0 || r > big 36) return numval(Math->NaN); if(r == big 16 && len s >= i+2 && s[i] == '0' && (s[i+1] == 'x' || s[i+1] == 'X')) i += 2; ok := 0; n := big 0; for(; i < len s; i++) { c := s[i]; v := r; case c { 'a' to 'z' => v = big(c - 'a' + 10); 'A' to 'Z' => v = big(c - 'A' + 10); '0' to '9' => v = big(c - '0'); } if(v >= r) break; ok = 1; n = n * r + v; } if(!ok) return numval(Math->NaN); if(neg) n = -n; return numval(real n); } cparseFloat(ex: ref Exec, nil, nil: ref Ecmascript->Obj, args: array of ref Val): ref Val { s := toString(ex, biarg(args, 0)); (nil, r) := parsenum(ex, s, 0, ParseReal|ParseTrim); return numval(r); } cescape(ex: ref Exec, nil, nil: ref Ecmascript->Obj, args: array of ref Val): ref Val { s := toString(ex, biarg(args, 0)); t := ""; for(i := 0; i < len s; i++){ c := s[i]; case c{ 'A' to 'Z' or 'a' to 'z' or '0' to '9' or '@' or '*' or '_' or '+' or '-' or '.' or '/' => t[len t] = s[i]; * => e := ""; do{ d := c & 16rf; e = "0123456789abcdef"[d:d+1] + e; c >>= 4; }while(c); if(len e & 1) e = "0" + e; if(len e == 4) e = "u" + e; t += "%" + e; } } return strval(t); } cunescape(ex: ref Exec, nil, nil: ref Ecmascript->Obj, args: array of ref Val): ref Val { s := toString(ex, biarg(args, 0)); t := ""; for(i := 0; i < len s; i++){ c := s[i]; if(c == '%'){ if(i + 5 < len s && s[i+1] == 'u'){ (v, e) := str->toint(s[i+2:i+6], 16); if(e == ""){ c = v; i += 5; } }else if(i + 2 < len s){ (v, e) := str->toint(s[i+1:i+3], 16); if(e == ""){ c = v; i += 2; } } } t[len t] = c; } return strval(t); } cisNaN(ex: ref Exec, nil, nil: ref Ecmascript->Obj, args: array of ref Val): ref Val { if(math->isnan(toNumber(ex, biarg(args, 0)))) return true; return false; } cisFinite(ex: ref Exec, nil, nil: ref Ecmascript->Obj, args: array of ref Val): ref Val { r := toNumber(ex, biarg(args, 0)); if(math->isnan(r) || r == +Infinity || r == -Infinity) return false; return true; } cobj(ex: ref Exec, f, nil: ref Ecmascript->Obj, args: array of ref Val): ref Val { o: ref Obj; v := biarg(args, 0); if(isnull(v) || isundefined(v)) o = nobj(ex, f, args); else o = toObject(ex, v); return objval(o); } nobj(ex: ref Exec, nil: ref Ecmascript->Obj, args: array of ref Val): ref Ecmascript->Obj { o: ref Obj; TUndef, TNull, TBool, TNum, TStr, TObj, NoHint: con iota; v := biarg(args, 0); case v.ty{ TNull or TUndef => o = mkobj(ex.objproto, "Object"); TBool => o = mkobj(ex.boolproto, "Boolean"); o.val = v; TStr => o = mkobj(ex.strproto, "String"); o.val = v; varinstant(o, DontEnum|DontDelete|ReadOnly, "length", ref RefVal(numval(real len v.str))); TNum => o = mkobj(ex.numproto, "Number"); o.val = v; TObj => o = v.obj; * => runtime(ex, "unknown type in Object constructor"); } return o; } cobjprototoString(nil: ref Exec, nil, this: ref Ecmascript->Obj, nil: array of ref Val): ref Val { return strval("[object " + this.class + "]"); } cobjprotovalueOf(nil: ref Exec, nil, this: ref Ecmascript->Obj, nil: array of ref Val): ref Val { return objval(this); } nfunc(ex: ref Exec, nil: ref Ecmascript->Obj, args: array of ref Val): ref Ecmascript->Obj { params := ""; body := ""; sep := ""; for(i := 0; i < len args - 1; i++){ params += sep + toString(ex, args[i]); sep = ","; } if(i < len args) body = toString(ex, args[i]); p := mkparser(ex, "function anonymous("+params+"){"+body+"}"); fundecl(ex, p); if(p.errors) runtime(ex, ex.error); if(p.code.vars[0].name != "anonymous") runtime(ex, "parse failure"); return p.code.vars[0].val.val.obj; } cfuncprototoString(ex: ref Exec, nil, this: ref Ecmascript->Obj, nil: array of ref Val): ref Val { if(this.call == nil) runtime(ex, "Function.prototype.toString called for a non-Function object"); return strval(funcprint(ex, this)); } narray(ex: ref Exec, nil: ref Ecmascript->Obj, args: array of ref Val): ref Ecmascript->Obj { o := mkobj(ex.arrayproto, "Array"); length := big len args; if(length == big 1 && isnum(coerceToVal(args[0]))){ length = toUint32(ex, args[0]); varinstant(o, DontEnum|DontDelete, "length", ref RefVal(numval(real length))); }else{ varinstant(o, DontEnum|DontDelete, "length", ref RefVal(numval(real length))); for(i := 0; i < len args; i++) esput(ex, o, string i, args[i], 0); } return o; } carrayprototoString(ex: ref Exec, nil, this: ref Ecmascript->Obj, nil: array of ref Val): ref Val { return carrayprotojoin(ex, nil, this, nil); } carrayprotojoin(ex: ref Exec, nil, this: ref Ecmascript->Obj, args: array of ref Val): ref Val { length := toUint32(ex, esget(ex, this, "length", 0)); sepv := biarg(args, 0); sep := ","; if(sepv != undefined) sep = toString(ex, sepv); s := ""; ss := ""; for(i := big 0; i < length; i++){ tv := esget(ex, this, string i, 0); t := ""; if(tv != undefined && tv != null) t = toString(ex, tv); s += ss + t; ss = sep; } return strval(s); } carrayprotoreverse(ex: ref Exec, nil, this: ref Ecmascript->Obj, nil: array of ref Val): ref Val { length := toUint32(ex, esget(ex, this, "length", 0)); mid := length / big 2; for(i := big 0; i < mid; i++){ i1 := string i; v1 := esget(ex, this, i1, 0); i2 := string(length - i - big 1); v2 := esget(ex, this, i2, 0); if(v2 == undefined) esdelete(ex, this, i1, 0); else esput(ex, this, i1, v2, 0); if(v1 == undefined) esdelete(ex, this, i2, 0); else esput(ex, this, i2, v1, 0); } return objval(this); } carrayprotosort(ex: ref Exec, nil, this: ref Ecmascript->Obj, args: array of ref Val): ref Val { length := toUint32(ex, esget(ex, this, "length", 0)); cmp := biarg(args, 0); if(cmp == undefined) cmp = nil; else if(!isobj(cmp) || cmp.obj.call == nil) runtime(ex, "Array.prototype.sort argument is not a function"); # # shell sort # for(m := (length+big 3)/big 5; m > big 0; m = (m+big 1)/big 3){ for(i := length-m; i-- != big 0;){ v1, v2 : ref Val = nil; ji := big -1; for(j := i+m; j < length; j += m){ if(v1 == nil) v1 = esget(ex, this, string(j-m), 0); v2 = esget(ex, this, string(j), 0); cr : real; if(v1 == undefined && v2 == undefined) cr = 0.; else if(v1 == undefined) cr = 1.; else if(v2 == undefined) cr = -1.; else if(cmp == nil){ s1 := toString(ex, v1); s2 := toString(ex, v2); if(s1 < s2) cr = -1.; else if(s1 > s2) cr = 1.; else cr = 0.; }else{ # # this value not specified by docs # cr = toNumber(ex, getValue(ex, escall(ex, cmp.obj, this, array[] of {v1, v2}))); } if(cr <= 0.) break; if(v2 == undefined) esdelete(ex, this, string(j-m), 0); else esput(ex, this, string(j-m), v2, 0); ji = j; } if(ji != big -1){ if(v1 == undefined) esdelete(ex, this, string(ji), 0); else esput(ex, this, string(ji), v1, 0); } } } return objval(this); } cstr(ex: ref Exec, nil, nil: ref Ecmascript->Obj, args: array of ref Val): ref Val { s := ""; if(len args > 0) s = toString(ex, biarg(args, 0)); return strval(s); } cstrfromCharCode(ex: ref Exec, nil, nil: ref Ecmascript->Obj, args: array of ref Val): ref Val { s := ""; for(i := 0; i < len args; i++) s[i] = toUint16(ex, args[i]); return strval(s); } cstrprototoString(ex: ref Exec, nil, this: ref Ecmascript->Obj, nil: array of ref Val): ref Val { if(!isstrobj(this)) runtime(ex, "String.prototype.toString called on non-String object"); return this.val; } cstrprotocharAt(ex: ref Exec, nil, this: ref Ecmascript->Obj, args: array of ref Val): ref Val { s := toString(ex, objval(this)); rpos := toInteger(ex, biarg(args, 0)); if(rpos < 0. || rpos >= real len s) s = ""; else{ pos := int rpos; s = s[pos: pos+1]; } return strval(s); } cstrprotocharCodeAt(ex: ref Exec, nil, this: ref Ecmascript->Obj, args: array of ref Val): ref Val { s := toString(ex, objval(this)); rpos := toInteger(ex, biarg(args, 0)); if(rpos < 0. || rpos >= real len s) c := Math->NaN; else c = real s[int rpos]; return numval(c); } cstrprotoindexOf(ex: ref Exec, nil, this: ref Ecmascript->Obj, args: array of ref Val): ref Val { s := toString(ex, objval(this)); t := toString(ex, biarg(args, 0)); rpos := toInteger(ex, biarg(args, 1)); if(rpos < 0.) rpos = 0.; else if(rpos > real len s) rpos = real len s; lent := len t; stop := len s - lent; for(i := int rpos; i <= stop; i++) if(s[i:i+lent] == t) break; if(i > stop) i = -1; return numval(real i); } cstrprotolastindexOf(ex: ref Exec, nil, this: ref Ecmascript->Obj, args: array of ref Val): ref Val { s := toString(ex, objval(this)); t := toString(ex, biarg(args, 0)); v := biarg(args, 1); rpos := toNumber(ex, v); if(math->isnan(rpos)) rpos = Math->Infinity; else rpos = toInteger(ex, v); if(rpos < 0.) rpos = 0.; else if(rpos > real len s) rpos = real len s; lent := len t; i := len s - lent; if(i > int rpos) i = int rpos; for(; i >= 0; i--) if(s[i:i+lent] == t) break; return numval(real i); } cstrprotosplit(ex: ref Exec, nil, this: ref Ecmascript->Obj, args: array of ref Val): ref Val { s := toString(ex, objval(this)); a := narray(ex, nil, nil); tv := biarg(args, 0); ai := 0; if(tv == undefined) esput(ex, a, string ai, strval(s), 0); else{ t := toString(ex, tv); lent := len t; stop := len s - lent; pos := 0; if(lent == 0){ for(; pos < stop; pos++) esput(ex, a, string ai++, strval(s[pos:pos+1]), 0); }else{ for(k := pos; k <= stop; k++){ if(s[k:k+lent] == t){ esput(ex, a, string ai++, strval(s[pos:k]), 0); pos = k + lent; k = pos - 1; } } esput(ex, a, string ai, strval(s[pos:k]), 0); } } return objval(a); } cstrprotosubstring(ex: ref Exec, nil, this: ref Ecmascript->Obj, args: array of ref Val): ref Val { s := toString(ex, objval(this)); rstart := toInteger(ex, biarg(args, 0)); lens := real len s; rend := lens; if(len args >= 2) rend = toInteger(ex, biarg(args, 1)); if(rstart < 0.) rstart = 0.; else if(rstart > lens) rstart = lens; if(rend < 0.) rend = 0.; else if(rend > lens) rend = lens; if(rstart > rend){ lens = rstart; rstart = rend; rend = lens; } return strval(s[int rstart: int rend]); } # this doesn't use unicode tolower cstrprototoLowerCase(ex: ref Exec, nil, this: ref Ecmascript->Obj, nil: array of ref Val): ref Val { s := toString(ex, objval(this)); for(i := 0; i < len s; i++) s[i] = tolower(s[i]); return strval(s); } #this doesn't use unicode toupper cstrprototoUpperCase(ex: ref Exec, nil, this: ref Ecmascript->Obj, nil: array of ref Val): ref Val { s := toString(ex, objval(this)); for(i := 0; i < len s; i++) s[i] = toupper(s[i]); return strval(s); } cbool(ex: ref Exec, nil, nil: ref Ecmascript->Obj, args: array of ref Val): ref Val { return toBoolean(ex, biarg(args, 0)); } tolower(c: int): int { if(c >= 'A' && c <= 'Z') return c - 'A' + 'a'; return c; } toupper(c: int): int { if(c >= 'a' && c <= 'a') return c - 'a' + 'A'; return c; } cboolprototoString(ex: ref Exec, nil, this: ref Ecmascript->Obj, nil: array of ref Val): ref Val { if(!isboolobj(this)) runtime(ex, "Boolean.prototype.toString called on non-Boolean object"); return strval(toString(ex, this.val)); } cboolprotovalueOf(ex: ref Exec, nil, this: ref Ecmascript->Obj, nil: array of ref Val): ref Val { if(!isboolobj(this)) runtime(ex, "Boolean.prototype.valueOf called on non-Boolean object"); return this.val; } cnum(ex: ref Exec, nil, nil: ref Ecmascript->Obj, args: array of ref Val): ref Val { r := 0.; if(len args > 0) r = toNumber(ex, biarg(args, 0)); return numval(r); } cnumprototoString(ex: ref Exec, nil, this: ref Ecmascript->Obj, nil: array of ref Val): ref Val { if(!isnumobj(this)) runtime(ex, "Number.prototype.toString called on non-Number object"); return this.val; } cnumprotovalueOf(ex: ref Exec, nil, this: ref Ecmascript->Obj, nil: array of ref Val): ref Val { if(!isnumobj(this)) runtime(ex, "Number.prototype.valueOf called on non-Number object"); return strval(toString(ex, this.val)); }