blob: d246b5883f3e1e4f8461014f4d1b4fd6f0a3aefd [file] [log] [blame]
package main
import (
"bytes"
"io"
)
type Var interface {
Value
Append(*Evaluator, string) Var
Flavor() string
Origin() string
IsDefined() bool
}
type SimpleVar struct {
// TODO(ukai): []byte -> Value (literal or so?)
value []byte
origin string
}
func (v SimpleVar) Flavor() string { return "simple" }
func (v SimpleVar) Origin() string { return v.origin }
func (v SimpleVar) IsDefined() bool { return true }
func (v SimpleVar) String() string { return string(v.value) }
func (v SimpleVar) Eval(w io.Writer, ev *Evaluator) {
w.Write(v.value)
}
func (v SimpleVar) Append(ev *Evaluator, s string) Var {
val, _, err := parseExpr([]byte(s), nil)
if err != nil {
panic(err)
}
buf := bytes.NewBuffer(v.value)
buf.WriteByte(' ')
val.Eval(buf, ev)
v.value = buf.Bytes()
return v
}
type RecursiveVar struct {
expr Value
origin string
}
func (v RecursiveVar) Flavor() string { return "recursive" }
func (v RecursiveVar) Origin() string { return v.origin }
func (v RecursiveVar) IsDefined() bool { return true }
func (v RecursiveVar) String() string { return v.expr.String() }
func (v RecursiveVar) Eval(w io.Writer, ev *Evaluator) {
v.expr.Eval(w, ev)
}
func (v RecursiveVar) Append(_ *Evaluator, s string) Var {
var buf bytes.Buffer
buf.WriteString(v.expr.String())
buf.WriteByte(' ')
buf.WriteString(s)
e, _, err := parseExpr(buf.Bytes(), nil)
if err != nil {
panic(err)
}
v.expr = e
return v
}
type UndefinedVar struct{}
func (_ UndefinedVar) Flavor() string { return "undefined" }
func (_ UndefinedVar) Origin() string { return "undefined" }
func (_ UndefinedVar) IsDefined() bool { return false }
func (_ UndefinedVar) String() string { return "" }
func (_ UndefinedVar) Eval(_ io.Writer, _ *Evaluator) {
}
func (_ UndefinedVar) Append(*Evaluator, string) Var {
return UndefinedVar{}
}
type Vars map[string]Var
func (vt Vars) Lookup(name string) Var {
if v, ok := vt[name]; ok {
return v
}
return UndefinedVar{}
}
func (vt Vars) Assign(name string, v Var) {
switch v.Origin() {
case "override", "environment override":
default:
ov := vt.Lookup(name)
if ov.Origin() == "command line" {
return
}
}
vt[name] = v
}
func NewVars(vt Vars) Vars {
r := make(Vars)
r.Merge(vt)
return r
}
func (vt Vars) Merge(vt2 Vars) {
for k, v := range vt2 {
vt[k] = v
}
}
type oldVar struct {
name string
value Var
}
func newOldVar(vars Vars, name string) oldVar {
return oldVar{
name: name,
value: vars.Lookup(name),
}
}
func (old oldVar) restore(vars Vars) {
if old.value.IsDefined() {
vars[old.name] = old.value
return
}
delete(vars, old.name)
}