1exec(ex: ref Exec, code: ref Code): Completion 2{ 3 ssp := ex.sp; 4 5 r := estmt(ex, code, 0, code.npc); 6 7 if(r.kind == CThrow) 8 ex.sp = ssp; 9 10 if(ssp != ex.sp) 11 runtime(ex, InternalError, "internal error: exec stack not balanced"); 12 13 if(r.lab != nil) 14 runtime(ex, InternalError, "internal error: label out of stack"); 15 return r; 16} 17 18estmt(ex: ref Exec, code: ref Code, pc, epc: int): Completion 19{ 20 e: ref Ref; 21 ev: ref Val; 22 k, apc, pc2, apc2, pc3, apc3, c: int; 23 lab: string; 24 labs: list of string; 25 26 osp := ex.sp; 27 28{ 29 v : ref Val = nil; 30 k1 := CNormal; 31 while(pc < epc){ 32 v1 : ref Val = nil; 33 34 labs = nil; 35 op := int code.ops[pc++]; 36 while(op == Llabel){ 37 (pc, c) = getconst(code.ops, pc); 38 labs = code.strs[c] :: labs; 39 op = int code.ops[pc++]; 40 } 41 if(debug['e'] > 1) 42 print("estmt(pc %d, sp %d) %s\n", pc-1, ex.sp, tokname(op)); 43 case op { 44 Lbreak => 45 return (CBreak, v, nil); 46 Lcontinue => 47 return (CContinue, v, nil); 48 Lbreaklab => 49 (pc, c) = getconst(code.ops, pc); 50 return (CBreak, v, code.strs[c]); 51 Lcontinuelab => 52 (pc, c) = getconst(code.ops, pc); 53 return (CContinue, v, code.strs[c]); 54 Lreturn => 55 (pc, v) = eexpval(ex, code, pc, code.npc); 56 return (CReturn, v, nil); 57 '{' => 58 (pc, apc) = getjmp(code.ops, pc); 59 (k1, v1, lab) = estmt(ex, code, pc, apc); 60 pc = apc; 61 Lif => 62 (pc, apc) = getjmp(code.ops, pc); 63 (pc, ev) = eexpval(ex, code, pc, apc); 64 (pc, apc) = getjmp(code.ops, pc); 65 (pc2, apc2) = getjmp(code.ops, apc); 66 if(toBoolean(ex, ev) != false) 67 (k1, v1, lab) = estmt(ex, code, pc, apc); 68 else if(pc2 != apc2) 69 (k1, v1, lab) = estmt(ex, code, pc2, apc2); 70 pc = apc2; 71 Lwhile => 72 (pc, apc) = getjmp(code.ops, pc); 73 (pc2, apc2) = getjmp(code.ops, apc); 74 for(;;){ 75 (nil, ev) = eexpval(ex, code, pc, apc); 76 if(toBoolean(ex, ev) == false) 77 break; 78 (k, v1, lab) = estmt(ex, code, pc2, apc2); 79 if(v1 != nil) 80 v = v1; 81 if(k == CBreak || k == CContinue){ 82 if(initlabs(lab, labs)){ 83 if(k == CBreak) 84 break; 85 else 86 continue; 87 } 88 else 89 return (k, v1, lab); 90 } 91 if(k == CReturn || k == CThrow) 92 return (k, v1, nil); 93 } 94 pc = apc2; 95 Ldo => 96 (pc, apc) = getjmp(code.ops, pc); 97 (pc2, apc2) = getjmp(code.ops, apc); 98 for(;;){ 99 (k, v1, lab) = estmt(ex, code, pc, apc); 100 if(v1 != nil) 101 v = v1; 102 if(k == CBreak || k == CContinue){ 103 if(initlabs(lab, labs)){ 104 if(k == CBreak) 105 break; 106 else 107 continue; 108 } 109 else 110 return (k, v1, lab); 111 } 112 if(k == CReturn || k == CThrow) 113 return (k, v1, nil); 114 (nil, ev) = eexpval(ex, code, pc2, apc2); 115 if(toBoolean(ex, ev) == false) 116 break; 117 } 118 pc = apc2; 119 Lfor or 120 Lforvar => 121 (pc, apc) = getjmp(code.ops, pc); 122 (pc, nil) = eexpval(ex, code, pc, apc); 123 (pc, apc) = getjmp(code.ops, pc); 124 (pc2, apc2) = getjmp(code.ops, apc); 125 (pc3, apc3) = getjmp(code.ops, apc2); 126 for(;;){ 127 (nil, e) = eexp(ex, code, pc, apc); 128 if(e != nil && toBoolean(ex, getValue(ex, e)) == false) 129 break; 130 (k, v1, lab) = estmt(ex, code, pc3, apc3); 131 if(v1 != nil) 132 v = v1; 133 if(k == CBreak || k == CContinue){ 134 if(initlabs(lab, labs)){ 135 if(k == CBreak) 136 break; 137 else 138 continue; 139 } 140 else 141 return (k, v1, lab); 142 } 143 if(k == CReturn || k == CThrow) 144 return (k, v1, nil); 145 eexpval(ex, code, pc2, apc2); 146 } 147 pc = apc3; 148 Lforin or 149 Lforvarin => 150 (pc, apc) = getjmp(code.ops, pc); 151 (pc2, apc2) = getjmp(code.ops, apc); 152 (pc3, apc3) = getjmp(code.ops, apc2); 153 if(op == Lforvarin){ 154 (nil, nil) = eexp(ex, code, pc, apc); 155 # during for only evaluate the id, not the initializer 156 apc = pc + 1; 157 } 158 (nil, ev) = eexpval(ex, code, pc2, apc2); 159 bo := toObject(ex, ev); 160 161 # 162 # note this won't enumerate host properties 163 # 164 enum: 165 for(o := bo; o != nil; o = o.prototype){ 166 if(o.host != nil && o.host != me) 167 continue; 168 for(i := 0; i < len o.props; i++){ 169 if(o.props[i] == nil 170 || (o.props[i].attr & DontEnum) 171 || propshadowed(bo, o, o.props[i].name)) 172 continue; 173 (nil, e) = eexp(ex, code, pc, apc); 174 putValue(ex, e, strval(o.props[i].name)); 175 (k, v1, lab) = estmt(ex, code, pc3, apc3); 176 if(v1 != nil) 177 v = v1; 178 if(k == CBreak || k == CContinue){ 179 if(initlabs(lab, labs)){ 180 if(k == CBreak) 181 break enum; 182 else 183 continue enum; 184 } 185 else 186 return (k, v1, lab); 187 } 188 if(k == CReturn || k == CThrow) 189 return (k, v1, nil); 190 } 191 } 192 pc = apc3; 193 Lwith => 194 (pc, apc) = getjmp(code.ops, pc); 195 (pc, ev) = eexpval(ex, code, pc, apc); 196 pushscope(ex, toObject(ex, ev)); 197 (pc, apc) = getjmp(code.ops, pc); 198 (k1, v1, lab) = estmt(ex, code, pc, apc); 199 popscope(ex); 200 pc = apc; 201 ';' => 202 ; 203 Lvar => 204 (pc, apc) = getjmp(code.ops, pc); 205 (pc, nil) = eexp(ex, code, pc, apc); 206 Lswitch => 207 (pc, apc) = getjmp(code.ops, pc); 208 (pc, ev) = eexpval(ex, code, pc, apc); 209 (pc, apc) = getjmp(code.ops, pc); 210 (k1, v1, lab) = ecaseblk(ex, code, ev, pc, apc, labs); 211 pc = apc; 212 Lthrow => 213 (pc, v) = eexpval(ex, code, pc, code.npc); 214 ex.error = toString(ex, v); 215 return (CThrow, v, nil); 216 Lprint => 217 (pc, v1) = eexpval(ex, code, pc, code.npc); 218 print("%s\n", toString(ex, v1)); 219 Ltry => 220 (pc, apc) = getjmp(code.ops, pc); 221 (k1, v1, lab) = estmt(ex, code, pc, apc); 222 (kc, vc) := (k1, v1); 223 (pc, apc) = getjmp(code.ops, apc); 224 if(pc != apc){ 225 (pc, c) = getconst(code.ops, ++pc); 226 if(k1 == CThrow){ 227 o := mkobj(ex.objproto, "Object"); 228 valinstant(o, DontDelete, code.strs[c], v1); 229 pushscope(ex, o); 230 (k1, v1, lab) = estmt(ex, code, pc, apc); 231 popscope(ex); 232 if(k1 != CNormal) 233 (kc, vc) = (k1, v1); 234 } 235 } 236 (pc, apc) = getjmp(code.ops, apc); 237 if(pc != apc){ 238 (k, v, lab) = estmt(ex, code, pc, apc); 239 if(k == CNormal) 240 (k1, v1) = (kc, vc); 241 else 242 (k1, v1) = (k, v); 243 } 244 pc = apc; 245 * => 246 (pc, e) = eexp(ex, code, pc-1, code.npc); 247 if(e != nil) 248 v1 = getValue(ex, e); 249 if(debug['v']) 250 print("%s\n", toString(ex, v1)); 251 } 252 253 if(v1 != nil) 254 v = v1; 255 if(k1 == CBreak && lab != nil && inlabs(lab, labs)) 256 (k1, lab) = (CNormal, nil); 257 if(k1 != CNormal) 258 return (k1, v, lab); 259 } 260 return (CNormal, v, nil); 261} 262exception{ 263 "throw" => 264 ex.sp = osp; 265 return (CThrow, ex.errval, nil); 266} 267} 268 269ecaseblk(ex : ref Exec, code : ref Code, sv : ref Val, pc, epc : int, labs: list of string) : Completion 270{ defpc, nextpc, clausepc, apc : int; 271 ev : ref Val; 272 lab: string; 273 274 k := CNormal; 275 v := undefined; 276 matched := 0; 277 278 (pc, defpc) = getjmp(code.ops, pc); 279 clausepc = pc; 280 (pc, nextpc) = getjmp(code.ops, pc); 281 for (; pc <= epc; (clausepc, (pc, nextpc)) = (nextpc, getjmp(code.ops, nextpc))) { 282 if (nextpc == epc) { 283 if (matched || defpc == epc) 284 break; 285 # do the default 286 matched = 1; 287 nextpc = defpc; 288 continue; 289 } 290 if (!matched && clausepc == defpc) 291 # skip default case - still scanning guards 292 continue; 293 if (clausepc != defpc) { 294 # only case clauses have guard exprs 295 (pc, apc) = getjmp(code.ops, pc); 296 if (matched) 297 pc = apc; 298 else { 299 (pc, ev) = eexpval(ex, code, pc, apc); 300 if (identical(sv, ev)) 301 matched = 1; 302 else 303 continue; 304 } 305 } 306 (k, v, lab) = estmt(ex, code, pc, nextpc); 307 if(k == CBreak && initlabs(lab, labs)) 308 return (CNormal, v, nil); 309 if(k == CBreak || k == CContinue || k == CReturn || k == CThrow) 310 return (k, v, lab); 311 } 312 return (k, v, lab); 313} 314 315identical(v1, v2 : ref Val) : int 316{ 317 if (v1.ty != v2.ty) 318 return 0; 319 ret := 0; 320 case v1.ty{ 321 TUndef or 322 TNull => 323 ret = 1; 324 TNum => 325 if(v1.num == v2.num) 326 ret = 1; 327 TBool => 328 if(v1 == v2) 329 ret = 1; 330 TStr => 331 if(v1.str == v2.str) 332 ret = 1; 333 TObj => 334 if(v1.obj == v2.obj) 335 ret = 1; 336 TRegExp => 337 if(v1.rev == v2.rev) 338 ret = 1; 339 } 340 return ret; 341} 342 343eexpval(ex: ref Exec, code: ref Code, pc, epc: int): (int, ref Val) 344{ 345 e: ref Ref; 346 347 (pc, e) = eexp(ex, code, pc, epc); 348 if(e == nil) 349 v := undefined; 350 else 351 v = getValue(ex, e); 352 return (pc, v); 353} 354 355eexp(ex: ref Exec, code: ref Code, pc, epc: int): (int, ref Ref) 356{ 357 o, th: ref Obj; 358 a1: ref Ref; 359 v, v1, v2: ref Val; 360 s: string; 361 r1, r2: real; 362 c, apc, i1, i2: int; 363 364 savesp := ex.sp; 365out: while(pc < epc){ 366 op := int code.ops[pc++]; 367 if(debug['e'] > 1){ 368 case op{ 369 Lid or 370 Lstr or 371 Lregexp => 372 (nil, c) = getconst(code.ops, pc); 373 print("eexp(pc %d, sp %d) %s '%s'\n", pc-1, ex.sp, tokname(op), code.strs[c]); 374 Lnum => 375 (nil, c) = getconst(code.ops, pc); 376 print("eexp(pc %d, sp %d) %s '%g'\n", pc-1, ex.sp, tokname(op), code.nums[c]); 377 * => 378 print("eexp(pc %d, sp %d) %s\n", pc-1, ex.sp, tokname(op)); 379 } 380 } 381 case op{ 382 Lthis => 383 v1 = objval(ex.this); 384 Lnum => 385 (pc, c) = getconst(code.ops, pc); 386 v1 = numval(code.nums[c]); 387 Lstr => 388 (pc, c) = getconst(code.ops, pc); 389 v1 = strval(code.strs[c]); 390 Lregexp => 391 (pc, c) = getconst(code.ops, pc); 392 (p, f) := rsplit(code.strs[c]); 393 o = nregexp(ex, nil, array[] of { strval(p), strval(f) }); 394 v1 = objval(o); 395 # v1 = regexpval(p, f, 0); 396 Lid => 397 (pc, c) = getconst(code.ops, pc); 398 epush(ex, esprimid(ex, code.strs[c])); 399 continue; 400 Lnoval => 401 v1 = undefined; 402 '.' => 403 a1 = epop(ex); 404 v1 = epopval(ex); 405 epush(ex, ref Ref(1, nil, toObject(ex, v1), a1.name)); 406 continue; 407 '[' => 408 v2 = epopval(ex); 409 v1 = epopval(ex); 410 epush(ex, ref Ref(1, nil, toObject(ex, v1), toString(ex, v2))); 411 continue; 412 Lpostinc or 413 Lpostdec => 414 a1 = epop(ex); 415 r1 = toNumber(ex, getValue(ex, a1)); 416 v1 = numval(r1); 417 if(op == Lpostinc) 418 r1++; 419 else 420 r1--; 421 putValue(ex, a1, numval(r1)); 422 Linc or 423 Ldec or 424 Lpreadd or 425 Lpresub => 426 a1 = epop(ex); 427 r1 = toNumber(ex, getValue(ex, a1)); 428 case op{ 429 Linc => 430 r1++; 431 Ldec => 432 r1--; 433 Lpresub => 434 r1 = -r1; 435 } 436 v1 = numval(r1); 437 if(op == Linc || op == Ldec) 438 putValue(ex, a1, v1); 439 '~' => 440 v = epopval(ex); 441 i1 = toInt32(ex, v); 442 i1 = ~i1; 443 v1 = numval(real i1); 444 '!' => 445 v = epopval(ex); 446 v1 = toBoolean(ex, v); 447 if(v1 == true) 448 v1 = false; 449 else 450 v1 = true; 451 Ltypeof => 452 a1 = epop(ex); 453 if(a1.isref && getBase(ex, a1) == nil) 454 s = "undefined"; 455 else case (v1 = getValue(ex, a1)).ty{ 456 TUndef => 457 s = "undefined"; 458 TNull => 459 s = "object"; 460 TBool => 461 s = "boolean"; 462 TNum => 463 s = "number"; 464 TStr => 465 s = "string"; 466 TObj => 467 if(v1.obj.call != nil) 468 s = "function"; 469 else 470 s = "object"; 471 TRegExp => 472 s = "regexp"; 473 } 474 v1 = strval(s); 475 Ldelete => 476 a1 = epop(ex); 477 o = getBase(ex, a1); 478 s = getPropertyName(ex, a1); 479 if(o != nil) 480 esdelete(ex, o, s, 0); 481 v1 = undefined; 482 Lvoid => 483 epopval(ex); 484 v = undefined; 485 '*' or 486 '/' or 487 '%' or 488 '-' => 489 v2 = epopval(ex); 490 a1 = epop(ex); 491 r1 = toNumber(ex, getValue(ex, a1)); 492 r2 = toNumber(ex, v2); 493 case op{ 494 '*' => 495 r1 = r1 * r2; 496 '/' => 497 r1 = r1 / r2; 498 '%' => 499 r1 = fmod(r1, r2); 500 '-' => 501 r1 = r1 - r2; 502 } 503 v1 = numval(r1); 504 '+' => 505 v2 = epopval(ex); 506 a1 = epop(ex); 507 v1 = toPrimitive(ex, getValue(ex, a1), NoHint); 508 v2 = toPrimitive(ex, v2, NoHint); 509 if(v1.ty == TStr || v2.ty == TStr) 510 v1 = strval(toString(ex, v1)+toString(ex, v2)); 511 else 512 v1 = numval(toNumber(ex, v1)+toNumber(ex, v2)); 513 Llsh or 514 Lrsh or 515 Lrshu or 516 '&' or 517 '^' or 518 '|' => 519 v2 = epopval(ex); 520 a1 = epop(ex); 521 i1 = toInt32(ex, getValue(ex, a1)); 522 i2 = toInt32(ex, v2); 523 case op{ 524 Llsh => 525 i1 <<= i2 & 16r1f; 526 Lrsh => 527 i1 >>= i2 & 16r1f; 528 Lrshu => 529 i1 = int (((big i1) & 16rffffffff) >> (i2 & 16r1f)); 530 '&' => 531 i1 &= i2; 532 '|' => 533 i1 |= i2; 534 '^' => 535 i1 ^= i2; 536 } 537 v1 = numval(real i1); 538 '=' or 539 Las => 540 v1 = epopval(ex); 541 a1 = epop(ex); 542 putValue(ex, a1, v1); 543 '<' or 544 '>' or 545 Lleq or 546 Lgeq => 547 v2 = epopval(ex); 548 v1 = epopval(ex); 549 if(op == '>' || op == Lleq){ 550 v = v1; 551 v1 = v2; 552 v2 = v; 553 } 554 v1 = toPrimitive(ex, v1, TNum); 555 v2 = toPrimitive(ex, v2, TNum); 556 if(v1.ty == TStr && v2.ty == TStr){ 557 if(v1.str < v2.str) 558 v1 = true; 559 else 560 v1 = false; 561 }else{ 562 r1 = toNumber(ex, v1); 563 r2 = toNumber(ex, v2); 564 if(isnan(r1) || isnan(r2)) 565 v1 = undefined; 566 else if(r1 < r2) 567 v1 = true; 568 else 569 v1 = false; 570 } 571 if(op == Lgeq || op == Lleq){ 572 if(v1 == false) 573 v1 = true; 574 else 575 v1 = false; 576 } 577 Lin => 578 v2 = epopval(ex); 579 v1 = epopval(ex); 580 if(v2.ty != TObj) 581 runtime(ex, TypeError, "rhs of 'in' not an object"); 582 s = toString(ex, v1); 583 v1 = eshasproperty(ex, v2.obj, s, 0); 584 Linstanceof => 585 v2 = epopval(ex); 586 v1 = epopval(ex); 587 if(v2.ty != TObj) 588 runtime(ex, TypeError, "rhs of 'instanceof' not an object"); 589 if(!isfuncobj(v2.obj)) 590 runtime(ex, TypeError, "rhs of 'instanceof' not a function"); 591 if(v1.ty != TObj) 592 v1 = false; 593 else{ 594 v2 = esget(ex, v2.obj, "prototype", 0); 595 if(v2.ty != TObj) 596 runtime(ex, TypeError, "prototype value not an object"); 597 o = v2.obj; 598 for(p := v1.obj.prototype; p != nil; p = p.prototype){ 599 if(p == o){ 600 v1 = true; 601 break; 602 } 603 } 604 if(p == nil) 605 v1 = false; 606 } 607 Leq or 608 Lneq or 609 Lseq or 610 Lsne => 611 strict := op == Lseq || op == Lsne; 612 v2 = epopval(ex); 613 v1 = epopval(ex); 614 v = false; 615 while(v1.ty != v2.ty){ 616 if(strict) 617 break; 618 if(isnull(v1) && v2 == undefined 619 || v1 == undefined && isnull(v2)) 620 v1 = v2; 621 else if(v1.ty == TNum && v2.ty == TStr) 622 v2 = numval(toNumber(ex, v2)); 623 else if(v1.ty == TStr && v2.ty == TNum) 624 v1 = numval(toNumber(ex, v1)); 625 else if(v1.ty == TBool) 626 v1 = numval(toNumber(ex, v1)); 627 else if(v2.ty == TBool) 628 v2 = numval(toNumber(ex, v2)); 629 else if(v2.ty == TObj && (v1.ty == TStr || v1.ty == TNum)) 630 v2 = toPrimitive(ex, v2, NoHint); 631 else if(v1.ty == TObj && (v2.ty == TStr || v2.ty == TNum)) 632 v1 = toPrimitive(ex, v1, NoHint); 633 else{ 634 v1 = true; 635 v2 = false; 636 } 637 } 638 if(v1.ty != v2.ty) 639 v = false; 640 else{ 641 case v1.ty{ 642 TUndef or 643 TNull => 644 v = true; 645 TNum => 646 if(v1.num == v2.num) 647 v = true; 648 TBool => 649 if(v1 == v2) 650 v = true; 651 TStr => 652 if(v1.str == v2.str) 653 v = true; 654 TObj => 655 if(v1.obj == v2.obj) 656 v = true; 657 TRegExp => 658 if(v1.rev.p == v2.rev.p && v1.rev.f == v2.rev.f) 659 v = true; 660 } 661 } 662 if(op == Lneq || op == Lsne){ 663 if(v == false) 664 v = true; 665 else 666 v = false; 667 } 668 v1 = v; 669 Landand => 670 v1 = epopval(ex); 671 (pc, apc) = getjmp(code.ops, pc); 672 if(toBoolean(ex, v1) != false){ 673 (pc, a1) = eexp(ex, code, pc, apc); 674 v1 = getValue(ex, a1); 675 } 676 pc = apc; 677 Loror => 678 v1 = epopval(ex); 679 (pc, apc) = getjmp(code.ops, pc); 680 if(toBoolean(ex, v1) != true){ 681 (pc, a1) = eexp(ex, code, pc, apc); 682 v1 = getValue(ex, a1); 683 } 684 pc = apc; 685 '?' => 686 v1 = epopval(ex); 687 (pc, apc) = getjmp(code.ops, pc); 688 v1 = toBoolean(ex, v1); 689 if(v1 == true) 690 (pc, a1) = eexp(ex, code, pc, apc); 691 pc = apc; 692 (pc, apc) = getjmp(code.ops, pc); 693 if(v1 != true) 694 (pc, a1) = eexp(ex, code, pc, apc); 695 pc = apc; 696 v1 = getValue(ex, a1); 697 Lasop => 698 a1 = epop(ex); 699 epush(ex, a1); 700 v1 = getValue(ex, a1); 701 Lgetval => 702 v1 = epopval(ex); 703 ',' => 704 v1 = epopval(ex); 705 epop(ex); 706 # a1's value already gotten by Lgetval 707 '(' or 708 ')' => 709 continue; 710 Larrinit => 711 o = narray(ex, nil, nil); 712 (pc, c) = getconst(code.ops, pc); 713 esput(ex, o, "length", numval(real c), 0); 714 c = ex.sp-c; 715 for(sp := c; sp < ex.sp; sp++){ 716 v = getValue(ex, ex.stack[sp]); 717 if(v != undefined) 718 esput(ex, o, string (sp-c), v, 0); 719 } 720 ex.sp = c; 721 v1 = objval(o); 722 Lobjinit => 723 o = nobj(ex, nil, nil); 724 (pc, c) = getconst(code.ops, pc); 725 c = ex.sp-2*c; 726 for(sp := c; sp < ex.sp; sp += 2){ 727 v = getValue(ex, ex.stack[sp]); 728 if(isnum(v) || isstr(v)) 729 p := toString(ex, v); 730 else 731 p = ex.stack[sp].name; 732 v = getValue(ex, ex.stack[sp+1]); 733 esput(ex, o, p, v, 0); 734 } 735 ex.sp = c; 736 v1 = objval(o); 737 Lcall or 738 Lnewcall => 739 (pc, c) = getconst(code.ops, pc); 740 args := array[c] of ref Val; 741 c = ex.sp - c; 742 for(sp := c; sp < ex.sp; sp++) 743 args[sp-c] = getValue(ex, ex.stack[sp]); 744 ex.sp = c; 745 a1 = epop(ex); 746 v = getValue(ex, a1); 747 o = getobj(v); 748 if(op == Lcall){ 749 if(o == nil || o.call == nil) 750 runtime(ex, TypeError, "can only call function objects ("+a1.name+")"); 751 th = nil; 752 if(a1.isref){ 753 th = getBase(ex, a1); 754 if(th != nil && isactobj(th)) 755 th = nil; 756 } 757 758 # have to execute functions in the same context as they 759 # were defined, but need to use current stack. 760 if (o.call.ex == nil) 761 a1 = escall(ex, v.obj, th, args, 0); 762 else { 763 fnex := ref *o.call.ex; 764 fnex.stack = ex.stack; 765 fnex.sp = ex.sp; 766 fnex.scopechain = fnex.global :: nil; 767 # drop ref to stack to avoid array duplication should stack grow 768 ex.stack = nil; 769 osp := ex.sp; 770 # can get an exception here that corrupts ex etc. 771#aardvark:=99; 772#test:=99; 773# zebra:=99; 774 { 775 a1 = escall(fnex, v.obj, th, args, 0); 776 } 777 exception e{ 778 "throw" => 779 # copy up error so as it gets reported properly 780 ex.error = fnex.error; 781 ex.errval = fnex.errval; 782 ex.stack = fnex.stack; 783 ex.sp = osp; 784# raise e; 785 raise "throw"; 786 } 787 # restore stack, sp is OK as escall() ensures that stack is balanced 788 ex.stack = fnex.stack; 789 } 790 }else{ 791 if(o == nil || o.construct == nil) 792 runtime(ex, TypeError, "new must be given a constructor object"); 793 a1 = valref(objval(esconstruct(ex, o, args))); 794 } 795 epush(ex, a1); 796 args = nil; 797 continue; 798 Lnew => 799 v = epopval(ex); 800 o = getobj(v); 801 if(o == nil || o.construct == nil) 802 runtime(ex, TypeError, "new must be given a constructor object"); 803 v1 = objval(esconstruct(ex, o, nil)); 804 Lfunction => 805 (pc, c) = getconst(code.ops, pc); 806 v1 = objval(code.fexps[c]); 807 ';' => 808 break out; 809 * => 810 fatal(ex, sprint("eexp: unknown op %s\n", tokname(op))); 811 } 812 epushval(ex, v1); 813 } 814 815 if(savesp == ex.sp) 816 return (pc, nil); 817 818 if(savesp != ex.sp-1) 819 print("unbalanced stack in eexp: %d %d\n", savesp, ex.sp); 820 return (pc, epop(ex)); 821} 822 823epushval(ex: ref Exec, v: ref Val) 824{ 825 epush(ex, valref(v)); 826} 827 828epush(ex: ref Exec, r: ref Ref) 829{ 830 if(ex.sp >= len ex.stack){ 831 st := array[2 * len ex.stack] of ref Ref; 832 st[:] = ex.stack; 833 ex.stack = st; 834 } 835 ex.stack[ex.sp++] = r; 836} 837 838epop(ex: ref Exec): ref Ref 839{ 840 if(ex.sp == 0) 841 fatal(ex, "popping too far off the estack\n"); 842 return ex.stack[--ex.sp]; 843} 844 845epopval(ex: ref Exec): ref Val 846{ 847 if(ex.sp == 0) 848 fatal(ex, "popping too far off the estack\n"); 849 return getValue(ex, ex.stack[--ex.sp]); 850} 851 852inlabs(lab: string, labs: list of string): int 853{ 854 for(l := labs; l != nil; l = tl l) 855 if(hd l == lab) 856 return 1; 857 return 0; 858} 859 860initlabs(lab: string, labs: list of string): int 861{ 862 return lab == nil || inlabs(lab, labs); 863} 864