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