github.com/amarpal/go-tools@v0.0.0-20240422043104-40142f59f616/go/ir/lvalue.go (about) 1 // Copyright 2013 The Go Authors. All rights reserved. 2 // Use of this source code is governed by a BSD-style 3 // license that can be found in the LICENSE file. 4 5 package ir 6 7 // lvalues are the union of addressable expressions and map-index 8 // expressions. 9 10 import ( 11 "go/ast" 12 "go/types" 13 ) 14 15 // An lvalue represents an assignable location that may appear on the 16 // left-hand side of an assignment. This is a generalization of a 17 // pointer to permit updates to elements of maps. 18 type lvalue interface { 19 store(fn *Function, v Value, source ast.Node) // stores v into the location 20 load(fn *Function, source ast.Node) Value // loads the contents of the location 21 address(fn *Function) Value // address of the location 22 typ() types.Type // returns the type of the location 23 } 24 25 // An address is an lvalue represented by a true pointer. 26 type address struct { 27 addr Value 28 expr ast.Expr // source syntax of the value (not address) [debug mode] 29 } 30 31 func (a *address) load(fn *Function, source ast.Node) Value { 32 return emitLoad(fn, a.addr, source) 33 } 34 35 func (a *address) store(fn *Function, v Value, source ast.Node) { 36 store := emitStore(fn, a.addr, v, source) 37 if a.expr != nil { 38 // store.Val is v, converted for assignability. 39 emitDebugRef(fn, a.expr, store.Val, false) 40 } 41 } 42 43 func (a *address) address(fn *Function) Value { 44 if a.expr != nil { 45 emitDebugRef(fn, a.expr, a.addr, true) 46 } 47 return a.addr 48 } 49 50 func (a *address) typ() types.Type { 51 return deref(a.addr.Type()) 52 } 53 54 type compositeElement struct { 55 cv *CompositeValue 56 idx int 57 t types.Type 58 expr ast.Expr 59 } 60 61 func (ce *compositeElement) load(fn *Function, source ast.Node) Value { 62 panic("not implemented") 63 } 64 65 func (ce *compositeElement) store(fn *Function, v Value, source ast.Node) { 66 v = emitConv(fn, v, ce.t, source) 67 ce.cv.Values[ce.idx] = v 68 if ce.expr != nil { 69 // store.Val is v, converted for assignability. 70 emitDebugRef(fn, ce.expr, v, false) 71 } 72 } 73 74 func (ce *compositeElement) address(fn *Function) Value { 75 panic("not implemented") 76 } 77 78 func (ce *compositeElement) typ() types.Type { 79 return ce.t 80 } 81 82 // An element is an lvalue represented by m[k], the location of an 83 // element of a map. These locations are not addressable 84 // since pointers cannot be formed from them, but they do support 85 // load() and store(). 86 type element struct { 87 m, k Value // map 88 t types.Type // map element type 89 } 90 91 func (e *element) load(fn *Function, source ast.Node) Value { 92 l := &MapLookup{ 93 X: e.m, 94 Index: e.k, 95 } 96 l.setType(e.t) 97 return fn.emit(l, source) 98 } 99 100 func (e *element) store(fn *Function, v Value, source ast.Node) { 101 up := &MapUpdate{ 102 Map: e.m, 103 Key: e.k, 104 Value: emitConv(fn, v, e.t, source), 105 } 106 fn.emit(up, source) 107 } 108 109 func (e *element) address(fn *Function) Value { 110 panic("map elements are not addressable") 111 } 112 113 func (e *element) typ() types.Type { 114 return e.t 115 } 116 117 // A lazyAddress is an lvalue whose address is the result of an instruction. 118 // These work like an *address except a new address.address() Value 119 // is created on each load, store and address call. 120 // A lazyAddress can be used to control when a side effect (nil pointer 121 // dereference, index out of bounds) of using a location happens. 122 type lazyAddress struct { 123 addr func(fn *Function) Value // emit to fn the computation of the address 124 t types.Type // type of the location 125 expr ast.Expr // source syntax of the value (not address) [debug mode] 126 } 127 128 func (l *lazyAddress) load(fn *Function, source ast.Node) Value { 129 load := emitLoad(fn, l.addr(fn), source) 130 return load 131 } 132 133 func (l *lazyAddress) store(fn *Function, v Value, source ast.Node) { 134 store := emitStore(fn, l.addr(fn), v, source) 135 if l.expr != nil { 136 // store.Val is v, converted for assignability. 137 emitDebugRef(fn, l.expr, store.Val, false) 138 } 139 } 140 141 func (l *lazyAddress) address(fn *Function) Value { 142 addr := l.addr(fn) 143 if l.expr != nil { 144 emitDebugRef(fn, l.expr, addr, true) 145 } 146 return addr 147 } 148 149 func (l *lazyAddress) typ() types.Type { return l.t } 150 151 // A blank is a dummy variable whose name is "_". 152 // It is not reified: loads are illegal and stores are ignored. 153 type blank struct{} 154 155 func (bl blank) load(fn *Function, source ast.Node) Value { 156 panic("blank.load is illegal") 157 } 158 159 func (bl blank) store(fn *Function, v Value, source ast.Node) { 160 s := &BlankStore{ 161 Val: v, 162 } 163 fn.emit(s, source) 164 } 165 166 func (bl blank) address(fn *Function) Value { 167 panic("blank var is not addressable") 168 } 169 170 func (bl blank) typ() types.Type { 171 // This should be the type of the blank Ident; the typechecker 172 // doesn't provide this yet, but fortunately, we don't need it 173 // yet either. 174 panic("blank.typ is unimplemented") 175 }