github.com/arnodel/golua@v0.0.0-20230215163904-e0b5347eaaa1/ir/context.go (about) 1 package ir 2 3 import "fmt" 4 5 type lexicalScope struct { 6 reg map[Name]taggedReg // maps variable names to registers 7 label map[Name]labelWithLine // maps label names to labels 8 height int // This is the height of the close stack in this scope 9 } 10 11 func (s lexicalScope) getLabel(name Name) (label Label, line int, ok bool) { 12 ll, ok := s.label[name] 13 if ok { 14 label = ll.Label 15 line = ll.line 16 } 17 return 18 } 19 20 type taggedReg struct { 21 reg Register 22 tags uint 23 } 24 25 type labelWithLine struct { 26 Label 27 line int 28 } 29 30 // A lexicalContext maintains nested mappings of names to registers and jump 31 // labels corresponding to nested lexical scopes. It facilitates accessing the 32 // register of label associated with a given name at a given point in the code. 33 type lexicalContext []lexicalScope 34 35 // getRegister returns the register associated with the given name if it exists 36 // in one of the accessible lexical scopes. Otherwise it sets ok to false. 37 // TODO: explain tags. 38 func (c lexicalContext) getRegister(name Name, tags uint) (reg Register, ok bool) { 39 for i := len(c) - 1; i >= 0; i-- { 40 var tr taggedReg 41 tr, ok = c[i].reg[name] 42 if ok { 43 reg = tr.reg 44 if tags != 0 { 45 tr.tags |= tags 46 c[i].reg[name] = tr 47 } 48 break 49 } 50 } 51 return 52 } 53 54 // getLabel returns the label associated with the given name if it has been 55 // defined in one of the accessible scopes, in which case ok is true, otherwise 56 // ok is false. 57 func (c lexicalContext) getLabel(name Name) (label Label, line int, ok bool) { 58 for i := len(c) - 1; i >= 0; i-- { 59 label, line, ok = c[i].getLabel(name) 60 if ok { 61 return 62 } 63 } 64 return 65 } 66 67 // addToRoot adds name => reg mapping to the root lexical scope of this context. 68 func (c lexicalContext) addToRoot(name Name, reg Register) (ok bool) { 69 ok = len(c) > 0 70 if ok { 71 c[0].reg[name] = taggedReg{reg, 0} 72 } 73 return 74 } 75 76 // addToTop adds name => reg mapping to the topmost lexical scope in this 77 // context. 78 func (c lexicalContext) addToTop(name Name, reg Register) (ok bool) { 79 ok = len(c) > 0 80 if ok { 81 c[len(c)-1].reg[name] = taggedReg{reg, 0} 82 } 83 return 84 } 85 86 // addLabel adds a name => label mapping to the topmost lexical scope in this 87 // context. 88 func (c lexicalContext) addLabel(name Name, label Label, line int) (ok bool) { 89 ok = len(c) > 0 90 if ok { 91 c[len(c)-1].label[name] = labelWithLine{ 92 Label: label, 93 line: line, 94 } 95 } 96 return 97 } 98 99 // addHeight increases the height of the topmost lexical scope in this context. 100 func (c lexicalContext) addHeight(h int) (ok bool) { 101 ok = len(c) > 0 102 if ok { 103 c[len(c)-1].height += h 104 } 105 return ok 106 } 107 108 func (c lexicalContext) getHeight() int { 109 if len(c) > 0 { 110 return c[len(c)-1].height 111 } 112 return 0 113 } 114 115 // pushNew returns a new LexicalContext that extends the receive with a new 116 // blank lexical scope. 117 func (c lexicalContext) pushNew() lexicalContext { 118 return append(c, lexicalScope{ 119 reg: make(map[Name]taggedReg), 120 label: make(map[Name]labelWithLine), 121 height: c.top().height, 122 }) 123 } 124 125 // pop returns a new LexicalContext that has the topmost lexical scope missing, 126 // and also returns that topmost scope. 127 func (c lexicalContext) pop() (lexicalContext, lexicalScope) { 128 if len(c) == 0 { 129 return c, lexicalScope{} 130 } 131 return c[:len(c)-1], c[len(c)-1] 132 } 133 134 // top returns the topmost lexical scope in the context. 135 func (c lexicalContext) top() lexicalScope { 136 if len(c) > 0 { 137 return c[len(c)-1] 138 } 139 return lexicalScope{} 140 } 141 142 func (c lexicalContext) dump() { 143 for i, ns := range c { 144 fmt.Printf("NS %d:\n", i) 145 for name, tr := range ns.reg { 146 fmt.Printf(" %s: %s\n", name, tr.reg) 147 } 148 // TODO: dump labels 149 } 150 }