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  }