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  }