1
0
mirror of https://github.com/go-task/task.git synced 2024-12-16 10:59:23 +02:00
task/vendor/mvdan.cc/sh/v3/interp/vars.go

329 lines
6.8 KiB
Go
Raw Normal View History

2018-01-03 19:12:40 +02:00
// Copyright (c) 2017, Daniel Martí <mvdan@mvdan.cc>
// See LICENSE for licensing information
package interp
import (
2018-12-15 19:44:17 +02:00
"os"
2018-01-03 19:12:40 +02:00
"runtime"
2018-12-15 19:44:17 +02:00
"strconv"
2018-01-03 19:12:40 +02:00
"strings"
2019-09-27 00:04:09 +02:00
"mvdan.cc/sh/v3/expand"
"mvdan.cc/sh/v3/syntax"
2018-01-03 19:12:40 +02:00
)
2018-12-15 19:44:17 +02:00
type overlayEnviron struct {
parent expand.Environ
values map[string]expand.Variable
2018-04-28 20:35:15 +02:00
}
2018-12-15 19:44:17 +02:00
func (o overlayEnviron) Get(name string) expand.Variable {
if vr, ok := o.values[name]; ok {
return vr
}
return o.parent.Get(name)
2018-04-28 20:35:15 +02:00
}
2018-12-15 19:44:17 +02:00
func (o overlayEnviron) Set(name string, vr expand.Variable) {
o.values[name] = vr
2018-04-28 20:35:15 +02:00
}
2018-12-15 19:44:17 +02:00
func (o overlayEnviron) Each(f func(name string, vr expand.Variable) bool) {
o.parent.Each(f)
for name, vr := range o.values {
if !f(name, vr) {
2018-04-28 20:35:15 +02:00
return
}
}
}
2018-12-15 19:44:17 +02:00
func execEnv(env expand.Environ) []string {
2019-09-27 00:04:09 +02:00
list := make([]string, 0, 64)
2018-12-15 19:44:17 +02:00
env.Each(func(name string, vr expand.Variable) bool {
if vr.Exported {
list = append(list, name+"="+vr.String())
}
return true
})
2018-04-28 20:35:15 +02:00
return list
}
2018-12-15 19:44:17 +02:00
func (r *Runner) lookupVar(name string) expand.Variable {
if name == "" {
panic("variable name must not be empty")
}
2019-09-27 00:04:09 +02:00
var vr expand.Variable
2018-12-15 19:44:17 +02:00
switch name {
case "#":
2019-09-27 00:04:09 +02:00
vr.Kind, vr.Str = expand.String, strconv.Itoa(len(r.Params))
2018-12-15 19:44:17 +02:00
case "@", "*":
2019-09-27 00:04:09 +02:00
vr.Kind, vr.List = expand.Indexed, r.Params
2018-12-15 19:44:17 +02:00
case "?":
2019-09-27 00:04:09 +02:00
vr.Kind, vr.Str = expand.String, strconv.Itoa(r.exit)
2018-12-15 19:44:17 +02:00
case "$":
2019-09-27 00:04:09 +02:00
vr.Kind, vr.Str = expand.String, strconv.Itoa(os.Getpid())
2018-12-15 19:44:17 +02:00
case "PPID":
2019-09-27 00:04:09 +02:00
vr.Kind, vr.Str = expand.String, strconv.Itoa(os.Getppid())
2018-12-15 19:44:17 +02:00
case "DIRSTACK":
2019-09-27 00:04:09 +02:00
vr.Kind, vr.List = expand.Indexed, r.dirStack
2018-12-15 19:44:17 +02:00
case "0":
2019-09-27 00:04:09 +02:00
vr.Kind = expand.String
2018-12-15 19:44:17 +02:00
if r.filename != "" {
2019-09-27 00:04:09 +02:00
vr.Str = r.filename
2018-12-15 19:44:17 +02:00
} else {
2019-09-27 00:04:09 +02:00
vr.Str = "gosh"
2018-04-28 20:35:15 +02:00
}
2018-12-15 19:44:17 +02:00
case "1", "2", "3", "4", "5", "6", "7", "8", "9":
2019-09-27 00:04:09 +02:00
vr.Kind = expand.String
2018-12-15 19:44:17 +02:00
i := int(name[0] - '1')
if i < len(r.Params) {
2019-09-27 00:04:09 +02:00
vr.Str = r.Params[i]
2018-12-15 19:44:17 +02:00
} else {
2019-09-27 00:04:09 +02:00
vr.Str = ""
2018-04-28 20:35:15 +02:00
}
}
2019-09-27 00:04:09 +02:00
if vr.IsSet() {
return vr
2018-01-03 19:12:40 +02:00
}
2018-12-15 19:44:17 +02:00
if value, e := r.cmdVars[name]; e {
2019-09-27 00:04:09 +02:00
return expand.Variable{Kind: expand.String, Str: value}
2018-01-03 19:12:40 +02:00
}
if vr, e := r.funcVars[name]; e {
2018-12-15 19:44:17 +02:00
vr.Local = true
return vr
2018-01-03 19:12:40 +02:00
}
if vr, e := r.Vars[name]; e {
2018-12-15 19:44:17 +02:00
return vr
2018-01-03 19:12:40 +02:00
}
2018-12-15 19:44:17 +02:00
if vr := r.Env.Get(name); vr.IsSet() {
return vr
2018-01-03 19:12:40 +02:00
}
if runtime.GOOS == "windows" {
upper := strings.ToUpper(name)
2018-12-15 19:44:17 +02:00
if vr := r.Env.Get(upper); vr.IsSet() {
return vr
2018-01-03 19:12:40 +02:00
}
}
2018-04-28 20:35:15 +02:00
if r.opts[optNoUnset] {
2018-01-03 19:12:40 +02:00
r.errf("%s: unbound variable\n", name)
2018-09-01 16:00:49 +02:00
r.setErr(ShellExitStatus(1))
2018-01-03 19:12:40 +02:00
}
2018-12-15 19:44:17 +02:00
return expand.Variable{}
2018-01-03 19:12:40 +02:00
}
2018-12-15 19:44:17 +02:00
func (r *Runner) envGet(name string) string {
return r.lookupVar(name).String()
2018-01-03 19:12:40 +02:00
}
func (r *Runner) delVar(name string) {
2018-12-15 19:44:17 +02:00
vr := r.lookupVar(name)
if vr.ReadOnly {
2018-01-03 19:12:40 +02:00
r.errf("%s: readonly variable\n", name)
r.exit = 1
return
}
2018-12-15 19:44:17 +02:00
if vr.Local {
// don't overwrite a non-local var with the same name
r.funcVars[name] = expand.Variable{}
} else {
r.Vars[name] = expand.Variable{} // to not query r.Env
2018-01-03 19:12:40 +02:00
}
}
2018-12-15 19:44:17 +02:00
func (r *Runner) setVarString(name, value string) {
2019-09-27 00:04:09 +02:00
r.setVar(name, nil, expand.Variable{Kind: expand.String, Str: value})
2018-01-03 19:12:40 +02:00
}
2018-12-15 19:44:17 +02:00
func (r *Runner) setVarInternal(name string, vr expand.Variable) {
2019-09-27 00:04:09 +02:00
if vr.Kind == expand.String {
2018-04-28 20:35:15 +02:00
if r.opts[optAllExport] {
2018-01-03 19:12:40 +02:00
vr.Exported = true
}
} else {
vr.Exported = false
}
if vr.Local {
if r.funcVars == nil {
2018-12-15 19:44:17 +02:00
r.funcVars = make(map[string]expand.Variable)
2018-01-03 19:12:40 +02:00
}
r.funcVars[name] = vr
} else {
r.Vars[name] = vr
}
}
2018-12-15 19:44:17 +02:00
func (r *Runner) setVar(name string, index syntax.ArithmExpr, vr expand.Variable) {
cur := r.lookupVar(name)
2018-01-03 19:12:40 +02:00
if cur.ReadOnly {
r.errf("%s: readonly variable\n", name)
r.exit = 1
return
}
2018-12-15 19:44:17 +02:00
if name2, var2 := cur.Resolve(r.Env); name2 != "" {
name = name2
cur = var2
}
2018-01-03 19:12:40 +02:00
2019-09-27 00:04:09 +02:00
if vr.Kind == expand.String && index == nil {
2018-01-03 19:12:40 +02:00
// When assigning a string to an array, fall back to the
// zero value for the index.
2019-09-27 00:04:09 +02:00
switch cur.Kind {
case expand.Indexed:
2018-01-03 19:12:40 +02:00
index = &syntax.Word{Parts: []syntax.WordPart{
&syntax.Lit{Value: "0"},
}}
2019-09-27 00:04:09 +02:00
case expand.Associative:
2018-01-03 19:12:40 +02:00
index = &syntax.Word{Parts: []syntax.WordPart{
&syntax.DblQuoted{},
}}
}
}
if index == nil {
r.setVarInternal(name, vr)
return
}
2018-12-15 19:44:17 +02:00
// from the syntax package, we know that value must be a string if index
// is non-nil; nested arrays are forbidden.
2019-09-27 00:04:09 +02:00
valStr := vr.Str
2018-01-03 19:12:40 +02:00
2019-09-27 00:04:09 +02:00
var list []string
switch cur.Kind {
case expand.String:
list = append(list, cur.Str)
case expand.Indexed:
list = cur.List
case expand.Associative:
// if the existing variable is already an AssocArray, try our
// best to convert the key to a string
2018-01-03 19:12:40 +02:00
w, ok := index.(*syntax.Word)
if !ok {
return
}
2018-12-15 19:44:17 +02:00
k := r.literal(w)
2019-09-27 00:04:09 +02:00
cur.Map[k] = valStr
2018-01-03 19:12:40 +02:00
r.setVarInternal(name, cur)
return
}
2018-12-15 19:44:17 +02:00
k := r.arithm(index)
2018-01-03 19:12:40 +02:00
for len(list) < k+1 {
list = append(list, "")
}
list[k] = valStr
2019-09-27 00:04:09 +02:00
cur.Kind = expand.Indexed
cur.List = list
2018-01-03 19:12:40 +02:00
r.setVarInternal(name, cur)
}
func (r *Runner) setFunc(name string, body *syntax.Stmt) {
if r.Funcs == nil {
r.Funcs = make(map[string]*syntax.Stmt, 4)
}
r.Funcs[name] = body
}
func stringIndex(index syntax.ArithmExpr) bool {
w, ok := index.(*syntax.Word)
if !ok || len(w.Parts) != 1 {
return false
}
2018-01-21 13:39:15 +02:00
switch w.Parts[0].(type) {
case *syntax.DblQuoted, *syntax.SglQuoted:
return true
}
return false
2018-01-03 19:12:40 +02:00
}
2019-09-27 00:04:09 +02:00
func (r *Runner) assignVal(as *syntax.Assign, valType string) expand.Variable {
2018-12-15 19:44:17 +02:00
prev := r.lookupVar(as.Name.Value)
2018-01-03 19:12:40 +02:00
if as.Naked {
2019-09-27 00:04:09 +02:00
return prev
2018-01-03 19:12:40 +02:00
}
if as.Value != nil {
2018-12-15 19:44:17 +02:00
s := r.literal(as.Value)
if !as.Append || !prev.IsSet() {
2019-09-27 00:04:09 +02:00
prev.Kind = expand.String
if valType == "-n" {
prev.Kind = expand.NameRef
}
prev.Str = s
return prev
2018-01-03 19:12:40 +02:00
}
2019-09-27 00:04:09 +02:00
switch prev.Kind {
case expand.String:
prev.Str += s
case expand.Indexed:
if len(prev.List) == 0 {
prev.List = append(prev.List, "")
2018-01-03 19:12:40 +02:00
}
2019-09-27 00:04:09 +02:00
prev.List[0] += s
case expand.Associative:
2018-01-03 19:12:40 +02:00
// TODO
}
2019-09-27 00:04:09 +02:00
return prev
2018-01-03 19:12:40 +02:00
}
if as.Array == nil {
2019-09-27 00:04:09 +02:00
// don't return the zero value, as that's an unset variable
prev.Kind = expand.String
if valType == "-n" {
prev.Kind = expand.NameRef
}
prev.Str = ""
return prev
2018-01-03 19:12:40 +02:00
}
elems := as.Array.Elems
if valType == "" {
2019-09-27 00:04:09 +02:00
valType = "-a" // indexed
if len(elems) > 0 && stringIndex(elems[0].Index) {
2018-01-03 19:12:40 +02:00
valType = "-A" // associative
}
}
if valType == "-A" {
2018-12-15 19:44:17 +02:00
amap := make(map[string]string, len(elems))
2018-01-03 19:12:40 +02:00
for _, elem := range elems {
2018-12-15 19:44:17 +02:00
k := r.literal(elem.Index.(*syntax.Word))
amap[k] = r.literal(elem.Value)
2018-01-03 19:12:40 +02:00
}
2019-09-27 00:04:09 +02:00
if !as.Append {
prev.Kind = expand.Associative
prev.Map = amap
return prev
2018-01-03 19:12:40 +02:00
}
// TODO
2019-09-27 00:04:09 +02:00
return prev
2018-01-03 19:12:40 +02:00
}
maxIndex := len(elems) - 1
indexes := make([]int, len(elems))
for i, elem := range elems {
if elem.Index == nil {
indexes[i] = i
continue
}
2018-12-15 19:44:17 +02:00
k := r.arithm(elem.Index)
2018-01-03 19:12:40 +02:00
indexes[i] = k
if k > maxIndex {
maxIndex = k
}
}
strs := make([]string, maxIndex+1)
for i, elem := range elems {
2018-12-15 19:44:17 +02:00
strs[indexes[i]] = r.literal(elem.Value)
2018-01-03 19:12:40 +02:00
}
2019-09-27 00:04:09 +02:00
if !as.Append {
prev.Kind = expand.Indexed
prev.List = strs
return prev
}
switch prev.Kind {
case expand.String:
prev.Kind = expand.Indexed
prev.List = append([]string{prev.Str}, strs...)
case expand.Indexed:
prev.List = append(prev.List, strs...)
case expand.Associative:
2018-01-03 19:12:40 +02:00
// TODO
}
2019-09-27 00:04:09 +02:00
return prev
2018-01-21 13:39:15 +02:00
}