github.com/hirochachacha/plua@v0.0.0-20170217012138-c82f520cc725/object/print.go (about) 1 package object 2 3 import ( 4 "fmt" 5 "io" 6 "os" 7 8 "github.com/hirochachacha/plua/internal/strconv" 9 "github.com/hirochachacha/plua/internal/version" 10 "github.com/hirochachacha/plua/opcode" 11 ) 12 13 func PrintError(err error) error { 14 return FprintError(os.Stderr, err) 15 } 16 17 func FprintError(w io.Writer, err error) error { 18 return fprintError(w, err) 19 } 20 21 type errWriter struct { 22 w io.Writer 23 err error 24 } 25 26 func (w *errWriter) Write(p []byte) (n int, err error) { 27 if w.err == nil { 28 n, w.err = w.w.Write(p) 29 } 30 return n, w.err 31 } 32 33 func fprintError(w io.Writer, err error) error { 34 ew := &errWriter{w: w} 35 if rerr, ok := err.(*RuntimeError); ok { 36 fmt.Fprintln(ew, rerr) 37 fmt.Fprint(ew, "stack traceback:") 38 tb := rerr.Traceback 39 if len(tb) <= 22 { 40 for _, st := range tb { 41 printStackTrace(ew, st) 42 } 43 } else { 44 for _, st := range tb[:10] { 45 printStackTrace(ew, st) 46 } 47 fmt.Fprint(ew, "\n\t") 48 fmt.Fprint(ew, "...") 49 for _, st := range tb[len(tb)-11:] { 50 printStackTrace(ew, st) 51 } 52 } 53 fmt.Fprintln(ew) 54 } else { 55 fmt.Fprintln(ew, err) 56 } 57 return ew.err 58 } 59 60 func printStackTrace(w io.Writer, st *StackTrace) { 61 fmt.Fprint(w, "\n\t") 62 63 var write bool 64 65 if st.Source != "" { 66 fmt.Fprint(w, st.Source) 67 fmt.Fprint(w, ":") 68 write = true 69 } 70 71 if st.Line > 0 { 72 fmt.Fprint(w, st.Line) 73 fmt.Fprint(w, ":") 74 write = true 75 } 76 77 if write { 78 fmt.Fprint(w, " in ") 79 } 80 81 fmt.Fprint(w, st.Signature) 82 83 if st.IsTailCall { 84 fmt.Fprint(w, "\n\t") 85 fmt.Fprint(w, "(...tail calls...)") 86 } 87 } 88 89 func PrintProto(p *Proto) error { 90 return FprintProto(os.Stdout, p) 91 } 92 93 func FprintProto(w io.Writer, p *Proto) error { 94 pr := &printer{w: w} 95 pr.printFunc(p) 96 return pr.err 97 } 98 99 type printer struct { 100 w io.Writer 101 err error 102 } 103 104 func (pr *printer) Write(p []byte) (n int, err error) { 105 if pr.err == nil { 106 n, pr.err = pr.w.Write(p) 107 } 108 return n, pr.err 109 } 110 111 func (pr *printer) printf(s string, args ...interface{}) { 112 fmt.Fprintf(pr, s, args...) 113 } 114 115 func (pr *printer) print(args ...interface{}) { 116 fmt.Fprint(pr, args...) 117 } 118 119 func (pr *printer) println(args ...interface{}) { 120 fmt.Fprintln(pr, args...) 121 } 122 123 func (pr *printer) printFunc(p *Proto) { 124 pr.printHeader(p) 125 pr.printCode(p) 126 pr.printConstants(p) 127 pr.printLocals(p) 128 pr.printUpvalues(p) 129 pr.printProtos(p) 130 } 131 132 func (pr *printer) printHeader(p *Proto) { 133 s := "=?" 134 if len(p.Source) != 0 { 135 s = string(p.Source) 136 } 137 138 if s[0] == '@' || s[0] == '=' { 139 s = s[1:] 140 } else if s[:len(version.LUA_SIGNATURE)] == version.LUA_SIGNATURE { 141 s = "(bstring)" 142 } else { 143 s = "(string)" 144 } 145 146 var typ string 147 if p.LineDefined == 0 { 148 typ = "main" 149 } else { 150 typ = "function" 151 } 152 153 pr.printf( 154 "\n%s <%s:%d,%d> (%d instructions at %p)\n", 155 typ, s, p.LineDefined, p.LastLineDefined, len(p.Code), p, 156 ) 157 158 var vararg string 159 if p.IsVararg { 160 vararg = "+" 161 } 162 163 pr.printf( 164 "%d%s params, %d slots, %d upvalues, ", 165 p.NParams, vararg, p.MaxStackSize, len(p.Upvalues), 166 ) 167 168 pr.printf( 169 "%d locals, %d constants, %d functions\n", 170 len(p.LocVars), len(p.Constants), len(p.Protos), 171 ) 172 } 173 174 func (pr *printer) printValue(val Value) { 175 if val, ok := val.(String); ok { 176 pr.print(strconv.Quote(string(val))) 177 178 return 179 } 180 181 pr.print(val) 182 } 183 184 func (pr *printer) printCode(p *Proto) { 185 for pc, code := range p.Code { 186 a := code.A() 187 b := code.B() 188 c := code.C() 189 bx := code.Bx() 190 ax := code.Ax() 191 sbx := code.SBx() 192 193 pr.printf("\t%d\t", pc+1) 194 195 if p.LineInfo != nil { 196 pr.printf("[%d]\t", p.LineInfo[pc]) 197 } else { 198 pr.printf("[-]\t") 199 } 200 201 pr.printf("%-9s\t", code.OpName()) 202 203 switch code.OpMode() { 204 case opcode.IABC: 205 pr.printf("%d", a) 206 if code.BMode() != opcode.OpArgN { 207 if b&opcode.BitRK != 0 { 208 pr.printf(" %d", -1-(b & ^opcode.BitRK)) 209 } else { 210 pr.printf(" %d", b) 211 } 212 } 213 if code.CMode() != opcode.OpArgN { 214 if c&opcode.BitRK != 0 { 215 pr.printf(" %d", -1-(c & ^opcode.BitRK)) 216 } else { 217 pr.printf(" %d", c) 218 } 219 } 220 case opcode.IABx: 221 pr.printf("%d", a) 222 switch code.BMode() { 223 case opcode.OpArgK: 224 pr.printf(" %d", -1-bx) 225 case opcode.OpArgU: 226 pr.printf(" %d", bx) 227 } 228 case opcode.IAsBx: 229 pr.printf("%d %d", a, sbx) 230 case opcode.IAx: 231 pr.printf("%d", -1-ax) 232 default: 233 panic("unreachable") 234 } 235 236 switch code.OpCode() { 237 case opcode.LOADK: 238 pr.print("\t; ") 239 pr.printValue(p.Constants[bx]) 240 case opcode.GETUPVAL, opcode.SETUPVAL: 241 pr.print("\t; ") 242 pr.print(upvalName(p, b)) 243 case opcode.GETTABUP: 244 pr.print("\t; ") 245 pr.print(upvalName(p, b)) 246 if c&opcode.BitRK != 0 { 247 pr.print(" ") 248 pr.printValue(p.Constants[c & ^opcode.BitRK]) 249 } 250 case opcode.SETTABUP: 251 pr.print("\t; ") 252 pr.print(upvalName(p, a)) 253 if b&opcode.BitRK != 0 { 254 pr.print(" ") 255 pr.printValue(p.Constants[b & ^opcode.BitRK]) 256 } 257 if c&opcode.BitRK != 0 { 258 pr.print(" ") 259 pr.printValue(p.Constants[c & ^opcode.BitRK]) 260 } 261 case opcode.GETTABLE, opcode.SELF: 262 if c&opcode.BitRK != 0 { 263 pr.print("\t; ") 264 pr.printValue(p.Constants[c & ^opcode.BitRK]) 265 } 266 case opcode.SETTABLE, opcode.ADD, opcode.SUB, opcode.MUL, 267 opcode.POW, opcode.DIV, opcode.IDIV, opcode.BAND, 268 opcode.BOR, opcode.BXOR, opcode.SHL, opcode.SHR, 269 opcode.EQ, opcode.LT, opcode.LE: 270 if b&opcode.BitRK != 0 || c&opcode.BitRK != 0 { 271 pr.print("\t; ") 272 if b&opcode.BitRK != 0 { 273 pr.printValue(p.Constants[b & ^opcode.BitRK]) 274 } else { 275 pr.print("-") 276 } 277 278 pr.print(" ") 279 280 if c&opcode.BitRK != 0 { 281 pr.printValue(p.Constants[c & ^opcode.BitRK]) 282 } else { 283 pr.print("-") 284 } 285 } 286 case opcode.JMP, opcode.FORLOOP, opcode.FORPREP, opcode.TFORLOOP: 287 pr.printf("\t; to %d", sbx+pc+2) 288 case opcode.CLOSURE: 289 pr.printf("\t; %p", p.Protos[bx]) 290 case opcode.SETLIST: 291 if c == 0 { 292 pc++ 293 pr.printf("\t; %d", p.Code[pc]) 294 } else { 295 pr.printf("\t; %d", c) 296 } 297 } 298 299 pr.print("\n") 300 } 301 } 302 303 func (pr *printer) printConstants(p *Proto) { 304 pr.printf("constants (%d) for %p: \n", len(p.Constants), p) 305 for i, c := range p.Constants { 306 pr.printf("\t%d\t", i+1) 307 pr.printValue(c) 308 pr.println() 309 } 310 } 311 312 func (pr *printer) printLocals(p *Proto) { 313 pr.printf("locals (%d) for %p: \n", len(p.LocVars), p) 314 for i, locvar := range p.LocVars { 315 pr.printf("\t%d\t%s\t%d\t%d\n", i, locvar.Name, locvar.StartPC, locvar.EndPC) 316 } 317 } 318 319 func (pr *printer) printUpvalues(p *Proto) { 320 pr.printf("upvalues (%d) for %p: \n", len(p.Upvalues), p) 321 for i, upval := range p.Upvalues { 322 pr.printf("\t%d\t%s\t%t\t%d\n", i, upval.Name, upval.Instack, upval.Index) 323 } 324 } 325 326 func (pr *printer) printProtos(p *Proto) { 327 for _, f := range p.Protos { 328 pr.printFunc(f) 329 } 330 } 331 332 func upvalName(p *Proto, r int) (name string) { 333 name = string(p.Upvalues[r].Name) 334 if len(name) == 0 { 335 name = "-" 336 } 337 return 338 }