github.com/arnodel/golua@v0.0.0-20230215163904-e0b5347eaaa1/code/unit.go (about) 1 package code 2 3 import ( 4 "fmt" 5 "io" 6 ) 7 8 // A Unit is a chunk of code with associated constants. 9 type Unit struct { 10 Source string // Shows were the unit comes from (e.g. a filename) - only for information. 11 Code []Opcode // The code 12 Lines []int32 // Optional: source code line for the corresponding opcode 13 Constants []Constant // All the constants required for running the code 14 } 15 16 // Disassemble outputs the disassembly of the unit code into the given 17 // io.Writer. 18 func (u *Unit) Disassemble(w io.Writer) { 19 newUnitDisassembler(u).disassemble(w) 20 } 21 22 type unitDisassembler struct { 23 unit *Unit 24 labels map[int]string 25 spans map[int]string 26 } 27 28 var _ OpcodeDisassembler = (*unitDisassembler)(nil) 29 30 func newUnitDisassembler(unit *Unit) *unitDisassembler { 31 return &unitDisassembler{ 32 unit: unit, 33 labels: make(map[int]string), 34 spans: make(map[int]string), 35 } 36 } 37 38 func (d *unitDisassembler) disassemble(w io.Writer) { 39 fmt.Fprintf(w, "==CONSTANTS==\n\n") 40 for i, k := range d.unit.Constants { 41 fmt.Fprintf(w, "K%d = %s\n", i, k.ShortString()) 42 if sg, ok := k.(spanGetter); ok { 43 d.setSpan(sg.GetSpan()) 44 } 45 } 46 disCode := make([]string, len(d.unit.Code)) 47 maxSpanLen := 10 48 for i, opcode := range d.unit.Code { 49 disCode[i] = opcode.Disassemble(d, i) 50 if l := len(d.spans[i]); l > maxSpanLen { 51 maxSpanLen = l 52 } 53 } 54 fmt.Fprintf(w, "\n==CODE==\n\n") 55 for i, dis := range disCode { 56 fmt.Fprintf(w, "%6d %-6s %-*s %6d %08x %s\n", d.unit.Lines[i], d.labels[i], maxSpanLen, d.spans[i], i, d.unit.Code[i], dis) 57 } 58 } 59 60 func (d *unitDisassembler) GetLabel(offset int) string { 61 lbl, ok := d.labels[offset] 62 if !ok { 63 lbl = fmt.Sprintf("L%d", len(d.labels)) 64 d.labels[offset] = lbl 65 } 66 return lbl 67 } 68 69 func (d *unitDisassembler) setSpan(name string, startOffset, endOffset int) { 70 d.spans[startOffset] = name 71 for { 72 startOffset++ 73 d.spans[startOffset] = " |" 74 if startOffset == endOffset { 75 d.spans[endOffset] = ` \` 76 return 77 } 78 } 79 } 80 81 func (d *unitDisassembler) ShortKString(ki KIndex) string { 82 k := d.unit.Constants[ki] 83 return k.ShortString() 84 } 85 86 // Interface for constants that contain code to notify the disassemble of where 87 // this code is (and how to label it). 88 type spanGetter interface { 89 GetSpan() (string, int, int) 90 }