package eval
import (
)
type varRef struct {
scope varScope
index int
subNames []string
}
type varScope int
const (
localScope varScope = 1 + iota
captureScope
builtinScope
envScope
externalScope
)
type scopeSearcher interface {
searchLocal(k string) int
searchCapture(k string) int
searchBuiltin(k string, r diag.Ranger) int
}
func ( scopeSearcher, string, diag.Ranger) *varRef {
= strings.TrimPrefix(, ":")
if := resolveVarRefLocal(, ); != nil {
return
}
if := resolveVarRefCapture(, ); != nil {
return
}
if := resolveVarRefBuiltin(, , ); != nil {
return
}
return nil
}
func ( scopeSearcher, string) *varRef {
, := SplitQName()
:= .searchLocal()
if != -1 {
return &varRef{scope: localScope, index: , subNames: SplitQNameSegs()}
}
return nil
}
func ( scopeSearcher, string) *varRef {
, := SplitQName()
if := .searchCapture(); != -1 {
return &varRef{scope: captureScope, index: , subNames: SplitQNameSegs()}
}
return nil
}
func ( scopeSearcher, string, diag.Ranger) *varRef {
, := SplitQName()
if != "" {
switch {
case "local:":
return resolveVarRefLocal(, )
case "up:":
return resolveVarRefCapture(, )
case "e:":
if strings.HasSuffix(, FnSuffix) {
return &varRef{scope: externalScope, subNames: []string{[:len()-1]}}
}
case "E:":
return &varRef{scope: envScope, subNames: []string{}}
}
}
if := .searchBuiltin(, ); != -1 {
return &varRef{scope: builtinScope, index: , subNames: SplitQNameSegs()}
}
return nil
}
func ( scopeSearcher, string, diag.Ranger) (compileBuiltin, *varRef) {
, := builtinSpecials[]
if {
return , nil
}
, := SplitSigil()
if == "" {
:= + FnSuffix
:= resolveVarRef(, , )
if != nil {
return nil,
}
}
return nil, nil
}
func ( *Frame, *varRef) vars.Var {
, := derefBase(, )
for , := range {
, := .Get().(*Ns)
if ! {
return nil
}
= .IndexName()
if == nil {
return nil
}
}
return
}
func ( *Frame, *varRef) (vars.Var, []string) {
switch .scope {
case localScope:
return .local.slots[.index], .subNames
case captureScope:
return .up.slots[.index], .subNames
case builtinScope:
return .Evaler.Builtin().slots[.index], .subNames
case envScope:
return vars.FromEnv(.subNames[0]), nil
case externalScope:
return vars.NewReadOnly(NewExternalCmd(.subNames[0])), nil
default:
return nil, nil
}
}
func ( *compiler) ( string) int {
return .thisScope().lookup()
}
func ( *compiler) ( string) int {
for := len(.scopes) - 2; >= 0; -- {
:= .scopes[].lookup()
if != -1 {
= .captures[+1].add(, true, )
for := + 2; < len(.scopes); ++ {
= .captures[].add(, false, )
}
return
}
}
return -1
}
func ( *compiler) ( string, diag.Ranger) int {
:= .builtin.lookup()
if != -1 {
.checkDeprecatedBuiltin(, )
}
return
}
func ( *Frame) ( string) int {
return .local.lookup()
}
func ( *Frame) ( string) int {
return .up.lookup()
}
func ( *Frame) ( string, diag.Ranger) int {
return .Evaler.Builtin().lookup()
}