diff options
Diffstat (limited to 'golang/kati/var.go')
| -rw-r--r-- | golang/kati/var.go | 371 |
1 files changed, 371 insertions, 0 deletions
diff --git a/golang/kati/var.go b/golang/kati/var.go new file mode 100644 index 0000000..5e7e996 --- /dev/null +++ b/golang/kati/var.go @@ -0,0 +1,371 @@ +// Copyright 2015 Google Inc. All rights reserved +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package kati + +import ( + "bytes" + "fmt" + "io" + "strings" +) + +// Var is an interface of make variable. +type Var interface { + Value + Append(*Evaluator, string) (Var, error) + AppendVar(*Evaluator, Value) (Var, error) + Flavor() string + Origin() string + IsDefined() bool +} + +type targetSpecificVar struct { + v Var + op string +} + +func (v *targetSpecificVar) Append(ev *Evaluator, s string) (Var, error) { + nv, err := v.v.Append(ev, s) + if err != nil { + return nil, err + } + return &targetSpecificVar{ + v: nv, + op: v.op, + }, nil +} +func (v *targetSpecificVar) AppendVar(ev *Evaluator, v2 Value) (Var, error) { + nv, err := v.v.AppendVar(ev, v2) + if err != nil { + return nil, err + } + return &targetSpecificVar{ + v: nv, + op: v.op, + }, nil +} +func (v *targetSpecificVar) Flavor() string { + return v.v.Flavor() +} +func (v *targetSpecificVar) Origin() string { + return v.v.Origin() +} +func (v *targetSpecificVar) IsDefined() bool { + return v.v.IsDefined() +} +func (v *targetSpecificVar) String() string { + // TODO: If we add the info of |op| a test starts + // failing. Shouldn't we use this only for debugging? + return v.v.String() + // return v.v.String() + " (op=" + v.op + ")" +} +func (v *targetSpecificVar) Eval(w evalWriter, ev *Evaluator) error { + return v.v.Eval(w, ev) +} + +func (v *targetSpecificVar) serialize() serializableVar { + return serializableVar{ + Type: v.op, + Children: []serializableVar{v.v.serialize()}, + } +} + +func (v *targetSpecificVar) dump(d *dumpbuf) { + d.Byte(valueTypeTSV) + d.Str(v.op) + v.v.dump(d) +} + +type simpleVar struct { + // space separated. note that each string may contain spaces, so + // it is not word list. + value []string + 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 strings.Join(v.value, " ") } +func (v *simpleVar) Eval(w evalWriter, ev *Evaluator) error { + space := false + for _, v := range v.value { + if space { + writeByte(w, ' ') + } + io.WriteString(w, v) + space = true + } + return nil +} +func (v *simpleVar) serialize() serializableVar { + return serializableVar{ + Type: "simple", + V: v.String(), + Origin: v.origin, + } +} +func (v *simpleVar) dump(d *dumpbuf) { + d.Byte(valueTypeSimple) + d.Int(len(v.value)) + for _, v := range v.value { + d.Str(v) + } + d.Str(v.origin) +} + +func (v *simpleVar) Append(ev *Evaluator, s string) (Var, error) { + val, _, err := parseExpr([]byte(s), nil, parseOp{}) + if err != nil { + return nil, err + } + abuf := newEbuf() + err = val.Eval(abuf, ev) + if err != nil { + return nil, err + } + v.value = append(v.value, abuf.String()) + abuf.release() + return v, nil +} + +func (v *simpleVar) AppendVar(ev *Evaluator, val Value) (Var, error) { + abuf := newEbuf() + err := val.Eval(abuf, ev) + if err != nil { + return nil, err + } + v.value = append(v.value, abuf.String()) + abuf.release() + return v, nil +} + +type automaticVar struct { + value []byte +} + +func (v *automaticVar) Flavor() string { return "simple" } +func (v *automaticVar) Origin() string { return "automatic" } +func (v *automaticVar) IsDefined() bool { return true } + +func (v *automaticVar) String() string { return string(v.value) } +func (v *automaticVar) Eval(w evalWriter, ev *Evaluator) error { + w.Write(v.value) + return nil +} +func (v *automaticVar) serialize() serializableVar { + return serializableVar{Type: ""} +} +func (v *automaticVar) dump(d *dumpbuf) { + d.err = fmt.Errorf("cannnot dump automatic var:%s", v.value) +} + +func (v *automaticVar) Append(ev *Evaluator, s string) (Var, error) { + val, _, err := parseExpr([]byte(s), nil, parseOp{}) + if err != nil { + return nil, err + } + abuf := newEbuf() + err = val.Eval(abuf, ev) + if err != nil { + return nil, err + } + value := []string{string(v.value), abuf.String()} + abuf.release() + return &simpleVar{ + value: value, + origin: "file", + }, nil +} + +func (v *automaticVar) AppendVar(ev *Evaluator, val Value) (Var, error) { + abuf := newEbuf() + err := val.Eval(abuf, ev) + if err != nil { + return nil, err + } + value := []string{string(v.value), abuf.String()} + abuf.release() + return &simpleVar{ + value: value, + origin: "file", + }, nil +} + +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 evalWriter, ev *Evaluator) error { + v.expr.Eval(w, ev) + return nil +} +func (v *recursiveVar) serialize() serializableVar { + return serializableVar{ + Type: "recursive", + Children: []serializableVar{v.expr.serialize()}, + Origin: v.origin, + } +} +func (v *recursiveVar) dump(d *dumpbuf) { + d.Byte(valueTypeRecursive) + v.expr.dump(d) + d.Str(v.origin) +} + +func (v *recursiveVar) Append(_ *Evaluator, s string) (Var, error) { + var exp expr + if e, ok := v.expr.(expr); ok { + exp = append(e, literal(" ")) + } else { + exp = expr{v.expr, literal(" ")} + } + sv, _, err := parseExpr([]byte(s), nil, parseOp{alloc: true}) + if err != nil { + return nil, err + } + if aexpr, ok := sv.(expr); ok { + exp = append(exp, aexpr...) + } else { + exp = append(exp, sv) + } + v.expr = exp + return v, nil +} + +func (v *recursiveVar) AppendVar(ev *Evaluator, val Value) (Var, error) { + var buf bytes.Buffer + buf.WriteString(v.expr.String()) + buf.WriteByte(' ') + buf.WriteString(val.String()) + e, _, err := parseExpr(buf.Bytes(), nil, parseOp{alloc: true}) + if err != nil { + return nil, err + } + v.expr = e + return v, nil +} + +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(_ evalWriter, _ *Evaluator) error { + return nil +} +func (undefinedVar) serialize() serializableVar { + return serializableVar{Type: "undefined"} +} +func (undefinedVar) dump(d *dumpbuf) { + d.Byte(valueTypeUndefined) +} + +func (undefinedVar) Append(*Evaluator, string) (Var, error) { + return undefinedVar{}, nil +} + +func (undefinedVar) AppendVar(_ *Evaluator, val Value) (Var, error) { + return undefinedVar{}, nil +} + +// Vars is a map for make variables. +type Vars map[string]Var + +// usedEnvs tracks what environment variables are used. +var usedEnvs = map[string]bool{} + +// Lookup looks up named make variable. +func (vt Vars) Lookup(name string) Var { + if v, ok := vt[name]; ok { + if strings.HasPrefix(v.Origin(), "environment") { + usedEnvs[name] = true + } + return v + } + return undefinedVar{} +} + +// origin precedence +// override / environment override +// command line +// file +// environment +// default +// TODO(ukai): is this correct order? +var originPrecedence = map[string]int{ + "override": 4, + "environment override": 4, + "command line": 3, + "file": 2, + "environment": 2, + "default": 1, + "undefined": 0, + "automatic": 0, +} + +// Assign assigns v to name. +func (vt Vars) Assign(name string, v Var) { + vo := v.Origin() + // assign automatic always win. + // assign new value to automatic always win. + if vo != "automatic" { + vp := originPrecedence[v.Origin()] + var op int + if ov, ok := vt[name]; ok { + op = originPrecedence[ov.Origin()] + } + if op > vp { + return + } + } + vt[name] = v +} + +// NewVars creates new Vars. +func NewVars(vt Vars) Vars { + r := make(Vars) + r.Merge(vt) + return r +} + +// Merge merges vt2 into vt. +func (vt Vars) Merge(vt2 Vars) { + for k, v := range vt2 { + vt[k] = v + } +} + +// save saves value of the variable named name. +// calling returned value will restore to the old value at the time +// when save called. +func (vt Vars) save(name string) func() { + if v, ok := vt[name]; ok { + return func() { + vt[name] = v + } + } + return func() { + delete(vt, name) + } +} |
