1PPrint: adt 2{ 3 ex: ref Exec; 4 code: ref Code; 5 stack: array of string; 6 sp: int; 7}; 8 9mkpprint(ex: ref Exec, code: ref Code): ref PPrint 10{ 11 return ref PPrint(ex, code, array[4] of string, 0); 12} 13 14funcprint(ex: ref Exec, func: ref Ecmascript->Obj): string 15{ 16 params := func.call.params; 17 (nil, name) := str->splitr(func.val.str, "."); 18 s := "function " + name + "("; 19 sep := ""; 20 for(i := 0; i < len params; i++){ 21 s += sep + params[i]; 22 sep = ", "; 23 } 24 s += "){"; 25 if(func.host != nil) 26 s += "[host code]"; 27 else 28 s += "\n" + pprint(ex, func.call.code, " "); 29 s += "}"; 30 return s; 31} 32 33pprint(ex: ref Exec, code: ref Code, indent: string): string 34{ 35 pp := ref PPrint(ex, code, array[4] of string, 0); 36#for(i:=0; i < code.npc; i++) sys->print("%d: %d\n", i, int code.ops[i]); 37 s := pstmt(pp, 0, code.npc, indent); 38 39 if(pp.sp != 0) 40 fatal(ex, "pprint stack not balanced"); 41 42 return s; 43} 44 45pstmt(pp: ref PPrint, pc, epc: int, indent: string): string 46{ 47 e, e1, e2: string; 48 c, apc: int; 49 50 code := pp.code; 51 s := ""; 52 while(pc < epc){ 53 op := int code.ops[pc++]; 54 while(op == Llabel){ 55 (pc, c) = getconst(code.ops, pc); 56 s += code.strs[c] + ":\n"; 57 op = int code.ops[pc++]; 58 } 59 s += indent; 60 case op{ 61 Lbreak or 62 Lcontinue or 63 Lreturn => 64 s += tokname(op); 65 if(op == Lreturn){ 66 (pc, e) = pexp(pp, pc, code.npc); 67 s += " " + e; 68 } 69 s += ";\n"; 70 Lbreaklab or 71 Lcontinuelab => 72 s += tokname(op); 73 (pc, c) = getconst(code.ops, pc); 74 s += " " + code.strs[c] + ";\n"; 75 '{' => 76 (pc, apc) = getjmp(code.ops, pc); 77 s += "{\n" + pstmt(pp, pc, apc, indent+" ") + indent + "}\n"; 78 pc = apc; 79 Lif or 80 Lwith or 81 Lwhile => 82 (pc, apc) = getjmp(code.ops, pc); 83 (pc, e) = pexp(pp, pc, apc); 84 (pc, apc) = getjmp(code.ops, pc); 85 s += tokname(op) + "(" + e + "){\n"; 86 s += pstmt(pp, pc, apc, indent+" "); 87 if(op == Lif){ 88 (pc, apc) = getjmp(code.ops, apc); 89 if(pc != apc) 90 s += indent + "}else{\n"; 91 s += pstmt(pp, pc, apc, indent+" "); 92 } 93 s += indent + "}\n"; 94 pc = apc; 95 Ldo => 96 (pc, apc) = getjmp(code.ops, pc); 97 e = pstmt(pp, pc, apc, indent+" "); 98 (pc, apc) = getjmp(code.ops, apc); 99 (pc, e1) = pexp(pp, pc, apc); 100 s += "do{\n" + e + indent + "}(while(" + e1 + ");\n"; 101 pc = apc; 102 Lfor or 103 Lforvar or 104 Lforin or 105 Lforvarin => 106 (pc, apc) = getjmp(code.ops, pc); 107 (pc, e) = pexp(pp, pc, apc); 108 (pc, apc) = getjmp(code.ops, pc); 109 (pc, e1) = pexp(pp, pc, apc); 110 s += "for("; 111 if(op == Lforvar || op == Lforvarin) 112 s += "var "; 113 s += e; 114 if(op == Lfor || op == Lforvar){ 115 (pc, apc) = getjmp(code.ops, pc); 116 (pc, e2) = pexp(pp, pc, apc); 117 s += "; " + e1 + "; " + e2; 118 }else 119 s += " in " + e1; 120 s += "){\n"; 121 (pc, apc) = getjmp(code.ops, pc); 122 s += pstmt(pp, pc, apc, indent+" "); 123 s += indent + "}\n"; 124 pc = apc; 125 ';' => 126 s += ";\n"; 127 Lvar => 128 (pc, apc) = getjmp(code.ops, pc); 129 (pc, e) = pexp(pp, pc, apc); 130 s += "var " + e + ";\n"; 131 Lswitch => 132 (pc, apc) = getjmp(code.ops, pc); 133 (pc, e) = pexp(pp, pc, apc); 134 s += "switch (" + e + ") {\n"; 135 (pc, apc) = getjmp(code.ops, pc); 136 (pc, e) = pcaseblk(pp, pc, apc, indent); 137 s += e + indent + "}\n"; 138 pc = apc; 139 Lthrow => 140 (pc, e) = pexp(pp, pc, code.npc); 141 s += "throw " + e + "\n"; 142 Ltry => 143 s += "try\n"; 144 (pc, apc) = getjmp(code.ops, pc); 145 s += pstmt(pp, pc, apc, indent+" "); 146 (pc, apc) = getjmp(code.ops, apc); 147 if(pc != apc){ 148 (pc, c) = getconst(code.ops, ++pc); 149 s += "catch(" + code.strs[c] + ")\n"; 150 s += pstmt(pp, pc, apc, indent+" "); 151 } 152 (pc, apc) = getjmp(code.ops, apc); 153 if(pc != apc){ 154 s += "finally\n"; 155 s += pstmt(pp, pc, apc, indent+" "); 156 } 157 pc = apc; 158 * => 159 (pc, e) = pexp(pp, pc-1, code.npc); 160 s += e + ";\n"; 161 } 162 } 163 return s; 164} 165 166pexp(pp: ref PPrint, pc, epc: int): (int, string) 167{ 168 c, apc: int; 169 s, f, a, a1, a2: string; 170 171 code := pp.code; 172 savesp := pp.sp; 173out: while(pc < epc){ 174 case op := int code.ops[pc++]{ 175 Lthis => 176 s = "this"; 177 Lid or 178 Lnum or 179 Lstr or 180 Lregexp => 181 (pc, c) = getconst(code.ops, pc); 182 if(op == Lnum) 183 s = string code.nums[c]; 184 else{ 185 s = code.strs[c]; 186 if(op == Lstr) 187 s = "\""+escstr(code.strs[c])+"\""; 188 } 189 '*' or 190 '/' or 191 '%' or 192 '+' or 193 '-' or 194 Llsh or 195 Lrsh or 196 Lrshu or 197 '<' or 198 '>' or 199 Lleq or 200 Lgeq or 201 Lin or 202 Linstanceof or 203 Leq or 204 Lneq or 205 Lseq or 206 Lsne or 207 '&' or 208 '^' or 209 '|' or 210 '=' or 211 '.' or 212 ',' or 213 '[' => 214 a2 = ppop(pp); 215 a1 = ppop(pp); 216 s = tokname(op); 217 if(a1[0] == '='){ 218 s += "="; 219 a1 = a1[1:]; 220 } 221 if(op == '[') 222 s = a1 + "[" + a2 + "]"; 223 else{ 224 if(op != '.'){ 225 if(op != ',') 226 s = " " + s; 227 s = s + " "; 228 } 229 s = a1 + s + a2; 230 } 231 Ltypeof or 232 Ldelete or 233 Lvoid or 234 Lnew or 235 Linc or 236 Ldec or 237 Lpreadd or 238 Lpresub or 239 '~' or 240 '!' or 241 Lpostinc or 242 Lpostdec => 243 a = ppop(pp); 244 s = tokname(op); 245 if(op == Lpostinc || op == Lpostdec) 246 s = a + s; 247 else{ 248 if(op == Ltypeof || op == Ldelete || op == Lvoid || op == Lnew) 249 s += " "; 250 s += a; 251 } 252 '(' => 253 s = "("; 254 ')' => 255 s = ppop(pp); 256 if(ppop(pp) != "(") 257 fatal(pp.ex, "unbalanced () in pexp"); 258 s = "(" + s + ")"; 259 Lgetval or 260 Las => 261 continue; 262 Lasop => 263 s = "=" + ppop(pp); 264 Lcall or 265 Lnewcall => 266 (pc, c) = getconst(code.ops, pc); 267 a = ""; 268 sep := ""; 269 for(sp := pp.sp-c; sp < pp.sp; sp++){ 270 a += sep + pp.stack[sp]; 271 sep = ", "; 272 } 273 pp.sp -= c; 274 f = ppop(pp); 275 if(op == Lnewcall) 276 f = "new " + f; 277 s = f + "(" + a + ")"; 278 ';' => 279 break out; 280 Landand or 281 Loror or 282 '?' => 283 s = ppop(pp); 284 (pc, apc) = getjmp(code.ops, pc); 285 (pc, a1) = pexp(pp, pc, apc); 286 s += " " + tokname(op) + " " + a1; 287 if(op == '?'){ 288 (pc, apc) = getjmp(code.ops, pc); 289 (pc, a2) = pexp(pp, pc, apc); 290 s += " : "+ a2; 291 } 292 * => 293 fatal(pp.ex, "pexp: unknown op " + tokname(op)); 294 } 295 ppush(pp, s); 296 } 297 298 if(savesp == pp.sp) 299 return (pc, ""); 300 301 if(savesp != pp.sp-1) 302 fatal(pp.ex, "unbalanced stack in pexp"); 303 return (pc, ppop(pp)); 304} 305 306pcaseblk(pp: ref PPrint, pc, epc: int, indent: string): (int, string) 307{ 308 code := pp.code; 309 defpc, clausepc, nextpc, apc: int; 310 s, a: string; 311 312 (pc, defpc) = getjmp(code.ops, pc); 313 clausepc = pc; 314 (pc, nextpc) = getjmp(code.ops, pc); 315 for (; pc < epc; (clausepc, (pc, nextpc)) = (nextpc, getjmp(code.ops, nextpc))) { 316 if (clausepc == defpc) { 317 s += indent + "default:\n"; 318 } else { 319 (pc, apc) = getjmp(code.ops, pc); 320 (pc, a) = pexp(pp, pc, apc); 321 s += indent + "case " + a + ":\n"; 322 } 323 s += pstmt(pp, pc, nextpc, indent+"\t"); 324 } 325 return (epc, s); 326} 327 328ppush(pp: ref PPrint, s: string) 329{ 330 if(pp.sp >= len pp.stack){ 331 st := array[2 * len pp.stack] of string; 332 st[:] = pp.stack; 333 pp.stack = st; 334 } 335 pp.stack[pp.sp++] = s; 336} 337 338ppop(pp: ref PPrint): string 339{ 340 if(pp.sp == 0) 341 fatal(pp.ex, "popping too far off the pstack"); 342 return pp.stack[--pp.sp]; 343} 344 345unescmap := array[128] of 346{ 347 '\'' => byte '\'', 348 '"' => byte '"', 349 '\\' => byte '\\', 350 '\b' => byte 'b', 351 '\u000c' => byte 'f', 352 '\n' => byte 'n', 353 '\r' => byte 'r', 354 '\t' => byte 't', 355 356 * => byte 0 357}; 358 359escstr(s: string): string 360{ 361 n := len s; 362 sb := ""; 363 for(i := 0; i < n; i++){ 364 c := s[i]; 365 if(c < 128 && (e := int unescmap[c])){ 366 sb[len sb] = '\\'; 367 sb[len sb] = e; 368 }else if(c > 128 || c < 32){ 369 sb += "\\u0000"; 370 for(j := 1; j <= 4; j++){ 371 sb[len sb - j] = "0123456789abcdef"[c & 16rf]; 372 c >>= 4; 373 } 374 }else 375 sb[len sb] = c; 376 } 377 return sb; 378} 379