2020-06-29 13:45:27 +00:00
|
|
|
package compiler
|
|
|
|
|
2021-02-05 13:15:26 +00:00
|
|
|
import (
|
2021-05-25 13:02:28 +00:00
|
|
|
"go/ast"
|
2021-02-05 13:15:26 +00:00
|
|
|
)
|
|
|
|
|
2020-06-29 13:45:27 +00:00
|
|
|
type varScope struct {
|
|
|
|
localsCnt int
|
|
|
|
arguments map[string]int
|
2021-02-04 13:26:33 +00:00
|
|
|
locals []map[string]varInfo
|
|
|
|
}
|
|
|
|
|
2021-05-25 13:02:28 +00:00
|
|
|
type varContext struct {
|
|
|
|
importMap map[string]string
|
|
|
|
expr ast.Expr
|
|
|
|
scope []map[string]varInfo
|
|
|
|
}
|
|
|
|
|
2021-02-04 13:26:33 +00:00
|
|
|
type varInfo struct {
|
|
|
|
refType varType
|
|
|
|
index int
|
2021-05-25 13:02:28 +00:00
|
|
|
// ctx is set for inline arguments and contains
|
|
|
|
// context for expression traversal.
|
|
|
|
ctx *varContext
|
2020-06-29 13:45:27 +00:00
|
|
|
}
|
|
|
|
|
2021-02-05 13:15:26 +00:00
|
|
|
const unspecifiedVarIndex = -1
|
|
|
|
|
2020-06-29 13:45:27 +00:00
|
|
|
func newVarScope() varScope {
|
|
|
|
return varScope{
|
|
|
|
arguments: make(map[string]int),
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
func (c *varScope) newScope() {
|
2021-02-04 13:26:33 +00:00
|
|
|
c.locals = append(c.locals, map[string]varInfo{})
|
2020-06-29 13:45:27 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
func (c *varScope) dropScope() {
|
|
|
|
c.locals = c.locals[:len(c.locals)-1]
|
|
|
|
}
|
|
|
|
|
2021-05-25 13:02:28 +00:00
|
|
|
func (c *varScope) addAlias(name string, vt varType, index int, ctx *varContext) {
|
2021-02-04 13:26:33 +00:00
|
|
|
c.locals[len(c.locals)-1][name] = varInfo{
|
|
|
|
refType: vt,
|
|
|
|
index: index,
|
2021-05-25 13:02:28 +00:00
|
|
|
ctx: ctx,
|
2021-02-04 13:26:33 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-02-05 13:15:26 +00:00
|
|
|
func (c *varScope) getVarInfo(name string) *varInfo {
|
2020-06-29 13:45:27 +00:00
|
|
|
for i := len(c.locals) - 1; i >= 0; i-- {
|
2021-02-04 13:26:33 +00:00
|
|
|
if vi, ok := c.locals[i][name]; ok {
|
2021-02-05 13:15:26 +00:00
|
|
|
return &vi
|
2020-06-29 13:45:27 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
if i, ok := c.arguments[name]; ok {
|
2021-02-05 13:15:26 +00:00
|
|
|
return &varInfo{
|
|
|
|
refType: varArgument,
|
|
|
|
index: i,
|
|
|
|
}
|
2020-06-29 13:45:27 +00:00
|
|
|
}
|
2021-02-05 13:15:26 +00:00
|
|
|
return nil
|
2020-06-29 13:45:27 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// newVariable creates a new local variable or argument in the scope of the function.
|
|
|
|
func (c *varScope) newVariable(t varType, name string) int {
|
|
|
|
var n int
|
|
|
|
switch t {
|
|
|
|
case varLocal:
|
|
|
|
return c.newLocal(name)
|
|
|
|
case varArgument:
|
|
|
|
_, ok := c.arguments[name]
|
|
|
|
if ok {
|
|
|
|
panic("argument is already allocated")
|
|
|
|
}
|
|
|
|
n = len(c.arguments)
|
|
|
|
c.arguments[name] = n
|
|
|
|
default:
|
|
|
|
panic("invalid type")
|
|
|
|
}
|
|
|
|
return n
|
|
|
|
}
|
|
|
|
|
|
|
|
// newLocal creates a new local variable in the current scope.
|
|
|
|
func (c *varScope) newLocal(name string) int {
|
|
|
|
idx := len(c.locals) - 1
|
|
|
|
m := c.locals[idx]
|
2021-02-04 13:26:33 +00:00
|
|
|
m[name] = varInfo{
|
|
|
|
refType: varLocal,
|
|
|
|
index: c.localsCnt,
|
|
|
|
}
|
2020-06-29 13:45:27 +00:00
|
|
|
c.localsCnt++
|
|
|
|
c.locals[idx] = m
|
|
|
|
return c.localsCnt - 1
|
|
|
|
}
|