diff options
| author | Charles.Forsyth <devnull@localhost> | 2006-12-22 17:07:39 +0000 |
|---|---|---|
| committer | Charles.Forsyth <devnull@localhost> | 2006-12-22 17:07:39 +0000 |
| commit | 37da2899f40661e3e9631e497da8dc59b971cbd0 (patch) | |
| tree | cbc6d4680e347d906f5fa7fca73214418741df72 /appl/lib/ecmascript/pprint.b | |
| parent | 54bc8ff236ac10b3eaa928fd6bcfc0cdb2ba46ae (diff) | |
20060303a
Diffstat (limited to 'appl/lib/ecmascript/pprint.b')
| -rw-r--r-- | appl/lib/ecmascript/pprint.b | 378 |
1 files changed, 378 insertions, 0 deletions
diff --git a/appl/lib/ecmascript/pprint.b b/appl/lib/ecmascript/pprint.b new file mode 100644 index 00000000..01fd0640 --- /dev/null +++ b/appl/lib/ecmascript/pprint.b @@ -0,0 +1,378 @@ +PPrint: adt +{ + ex: ref Exec; + code: ref Code; + stack: array of string; + sp: int; +}; + +mkpprint(ex: ref Exec, code: ref Code): ref PPrint +{ + return ref PPrint(ex, code, array[4] of string, 0); +} + +funcprint(ex: ref Exec, func: ref Ecmascript->Obj): string +{ + params := func.call.params; + (nil, name) := str->splitr(func.val.str, "."); + s := "function " + name + "("; + sep := ""; + for(i := 0; i < len params; i++){ + s += sep + params[i]; + sep = ", "; + } + s += "){"; + if(func.host != nil) + s += "[host code]"; + else + s += "\n" + pprint(ex, func.call.code, " "); + s += "}"; + return s; +} + +pprint(ex: ref Exec, code: ref Code, indent: string): string +{ + pp := ref PPrint(ex, code, array[4] of string, 0); +#for(i:=0; i < code.npc; i++) sys->print("%d: %d\n", i, int code.ops[i]); + s := pstmt(pp, 0, code.npc, indent); + + if(pp.sp != 0) + fatal(ex, "pprint stack not balanced"); + + return s; +} + +pstmt(pp: ref PPrint, pc, epc: int, indent: string): string +{ + e, e1, e2: string; + c, apc: int; + + code := pp.code; + s := ""; + while(pc < epc){ + op := int code.ops[pc++]; + while(op == Llabel){ + (pc, c) = getconst(code.ops, pc); + s += code.strs[c] + ":\n"; + op = int code.ops[pc++]; + } + s += indent; + case op{ + Lbreak or + Lcontinue or + Lreturn => + s += tokname(op); + if(op == Lreturn){ + (pc, e) = pexp(pp, pc, code.npc); + s += " " + e; + } + s += ";\n"; + Lbreaklab or + Lcontinuelab => + s += tokname(op); + (pc, c) = getconst(code.ops, pc); + s += " " + code.strs[c] + ";\n"; + '{' => + (pc, apc) = getjmp(code.ops, pc); + s += "{\n" + pstmt(pp, pc, apc, indent+" ") + indent + "}\n"; + pc = apc; + Lif or + Lwith or + Lwhile => + (pc, apc) = getjmp(code.ops, pc); + (pc, e) = pexp(pp, pc, apc); + (pc, apc) = getjmp(code.ops, pc); + s += tokname(op) + "(" + e + "){\n"; + s += pstmt(pp, pc, apc, indent+" "); + if(op == Lif){ + (pc, apc) = getjmp(code.ops, apc); + if(pc != apc) + s += indent + "}else{\n"; + s += pstmt(pp, pc, apc, indent+" "); + } + s += indent + "}\n"; + pc = apc; + Ldo => + (pc, apc) = getjmp(code.ops, pc); + e = pstmt(pp, pc, apc, indent+" "); + (pc, apc) = getjmp(code.ops, apc); + (pc, e1) = pexp(pp, pc, apc); + s += "do{\n" + e + indent + "}(while(" + e1 + ");\n"; + pc = apc; + Lfor or + Lforvar or + Lforin or + Lforvarin => + (pc, apc) = getjmp(code.ops, pc); + (pc, e) = pexp(pp, pc, apc); + (pc, apc) = getjmp(code.ops, pc); + (pc, e1) = pexp(pp, pc, apc); + s += "for("; + if(op == Lforvar || op == Lforvarin) + s += "var "; + s += e; + if(op == Lfor || op == Lforvar){ + (pc, apc) = getjmp(code.ops, pc); + (pc, e2) = pexp(pp, pc, apc); + s += "; " + e1 + "; " + e2; + }else + s += " in " + e1; + s += "){\n"; + (pc, apc) = getjmp(code.ops, pc); + s += pstmt(pp, pc, apc, indent+" "); + s += indent + "}\n"; + pc = apc; + ';' => + s += ";\n"; + Lvar => + (pc, apc) = getjmp(code.ops, pc); + (pc, e) = pexp(pp, pc, apc); + s += "var " + e + ";\n"; + Lswitch => + (pc, apc) = getjmp(code.ops, pc); + (pc, e) = pexp(pp, pc, apc); + s += "switch (" + e + ") {\n"; + (pc, apc) = getjmp(code.ops, pc); + (pc, e) = pcaseblk(pp, pc, apc, indent); + s += e + indent + "}\n"; + pc = apc; + Lthrow => + (pc, e) = pexp(pp, pc, code.npc); + s += "throw " + e + "\n"; + Ltry => + s += "try\n"; + (pc, apc) = getjmp(code.ops, pc); + s += pstmt(pp, pc, apc, indent+" "); + (pc, apc) = getjmp(code.ops, apc); + if(pc != apc){ + (pc, c) = getconst(code.ops, ++pc); + s += "catch(" + code.strs[c] + ")\n"; + s += pstmt(pp, pc, apc, indent+" "); + } + (pc, apc) = getjmp(code.ops, apc); + if(pc != apc){ + s += "finally\n"; + s += pstmt(pp, pc, apc, indent+" "); + } + pc = apc; + * => + (pc, e) = pexp(pp, pc-1, code.npc); + s += e + ";\n"; + } + } + return s; +} + +pexp(pp: ref PPrint, pc, epc: int): (int, string) +{ + c, apc: int; + s, f, a, a1, a2: string; + + code := pp.code; + savesp := pp.sp; +out: while(pc < epc){ + case op := int code.ops[pc++]{ + Lthis => + s = "this"; + Lid or + Lnum or + Lstr or + Lregexp => + (pc, c) = getconst(code.ops, pc); + if(op == Lnum) + s = string code.nums[c]; + else{ + s = code.strs[c]; + if(op == Lstr) + s = "\""+escstr(code.strs[c])+"\""; + } + '*' or + '/' or + '%' or + '+' or + '-' or + Llsh or + Lrsh or + Lrshu or + '<' or + '>' or + Lleq or + Lgeq or + Lin or + Linstanceof or + Leq or + Lneq or + Lseq or + Lsne or + '&' or + '^' or + '|' or + '=' or + '.' or + ',' or + '[' => + a2 = ppop(pp); + a1 = ppop(pp); + s = tokname(op); + if(a1[0] == '='){ + s += "="; + a1 = a1[1:]; + } + if(op == '[') + s = a1 + "[" + a2 + "]"; + else{ + if(op != '.'){ + if(op != ',') + s = " " + s; + s = s + " "; + } + s = a1 + s + a2; + } + Ltypeof or + Ldelete or + Lvoid or + Lnew or + Linc or + Ldec or + Lpreadd or + Lpresub or + '~' or + '!' or + Lpostinc or + Lpostdec => + a = ppop(pp); + s = tokname(op); + if(op == Lpostinc || op == Lpostdec) + s = a + s; + else{ + if(op == Ltypeof || op == Ldelete || op == Lvoid || op == Lnew) + s += " "; + s += a; + } + '(' => + s = "("; + ')' => + s = ppop(pp); + if(ppop(pp) != "(") + fatal(pp.ex, "unbalanced () in pexp"); + s = "(" + s + ")"; + Lgetval or + Las => + continue; + Lasop => + s = "=" + ppop(pp); + Lcall or + Lnewcall => + (pc, c) = getconst(code.ops, pc); + a = ""; + sep := ""; + for(sp := pp.sp-c; sp < pp.sp; sp++){ + a += sep + pp.stack[sp]; + sep = ", "; + } + pp.sp -= c; + f = ppop(pp); + if(op == Lnewcall) + f = "new " + f; + s = f + "(" + a + ")"; + ';' => + break out; + Landand or + Loror or + '?' => + s = ppop(pp); + (pc, apc) = getjmp(code.ops, pc); + (pc, a1) = pexp(pp, pc, apc); + s += " " + tokname(op) + " " + a1; + if(op == '?'){ + (pc, apc) = getjmp(code.ops, pc); + (pc, a2) = pexp(pp, pc, apc); + s += " : "+ a2; + } + * => + fatal(pp.ex, "pexp: unknown op " + tokname(op)); + } + ppush(pp, s); + } + + if(savesp == pp.sp) + return (pc, ""); + + if(savesp != pp.sp-1) + fatal(pp.ex, "unbalanced stack in pexp"); + return (pc, ppop(pp)); +} + +pcaseblk(pp: ref PPrint, pc, epc: int, indent: string): (int, string) +{ + code := pp.code; + defpc, clausepc, nextpc, apc: int; + s, a: string; + + (pc, defpc) = getjmp(code.ops, pc); + clausepc = pc; + (pc, nextpc) = getjmp(code.ops, pc); + for (; pc < epc; (clausepc, (pc, nextpc)) = (nextpc, getjmp(code.ops, nextpc))) { + if (clausepc == defpc) { + s += indent + "default:\n"; + } else { + (pc, apc) = getjmp(code.ops, pc); + (pc, a) = pexp(pp, pc, apc); + s += indent + "case " + a + ":\n"; + } + s += pstmt(pp, pc, nextpc, indent+"\t"); + } + return (epc, s); +} + +ppush(pp: ref PPrint, s: string) +{ + if(pp.sp >= len pp.stack){ + st := array[2 * len pp.stack] of string; + st[:] = pp.stack; + pp.stack = st; + } + pp.stack[pp.sp++] = s; +} + +ppop(pp: ref PPrint): string +{ + if(pp.sp == 0) + fatal(pp.ex, "popping too far off the pstack"); + return pp.stack[--pp.sp]; +} + +unescmap := array[128] of +{ + '\'' => byte '\'', + '"' => byte '"', + '\\' => byte '\\', + '\b' => byte 'b', + '\u000c' => byte 'f', + '\n' => byte 'n', + '\r' => byte 'r', + '\t' => byte 't', + + * => byte 0 +}; + +escstr(s: string): string +{ + n := len s; + sb := ""; + for(i := 0; i < n; i++){ + c := s[i]; + if(c < 128 && (e := int unescmap[c])){ + sb[len sb] = '\\'; + sb[len sb] = e; + }else if(c > 128 || c < 32){ + sb += "\\u0000"; + for(j := 1; j <= 4; j++){ + sb[len sb - j] = "0123456789abcdef"[c & 16rf]; + c >>= 4; + } + }else + sb[len sb] = c; + } + return sb; +} |
