// 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) } }