First pass variable support.

This allows blocked scoped variables to be set and retrieved as values using the $ prefix.
e.g. foo = 22; bar = $foo

Also supports env variables being used as variables and will properly parse to the correct type.
This commit is contained in:
Derek Collison
2016-05-22 10:21:00 -07:00
parent 68e8b83fcd
commit 832bac98be
4 changed files with 139 additions and 2 deletions

View File

@@ -16,6 +16,7 @@ package conf
import (
"fmt"
"os"
"strconv"
"time"
)
@@ -157,11 +158,50 @@ func (p *parser) processItem(it item) error {
array := p.ctx
p.popContext()
p.setValue(array)
case itemVariable:
if value, ok := p.lookupVariable(it.val); ok {
p.setValue(value)
} else {
return fmt.Errorf("Variable reference for '%s' on line %d can not be found.",
it.val, it.line)
}
}
return nil
}
// Used to map an environment value into a temporary map to pass to secondary Parse call.
const pkey = "pk"
// lookupVariable will lookup a variable reference. It will use block scoping on keys
// it has seen before, with the top level scoping being the environment variables. We
// ignore array contexts and only process the map contexts..
//
// Returns true for ok if it finds something, similar to map.
func (p *parser) lookupVariable(varReference string) (interface{}, bool) {
// Loop through contexts currently on the stack.
for i := len(p.ctxs) - 1; i >= 0; i -= 1 {
ctx := p.ctxs[i]
// Process if it is a map context
if m, ok := ctx.(map[string]interface{}); ok {
if v, ok := m[varReference]; ok {
return v, ok
}
}
}
// If we are here, we have exhausted our context maps and still not found anything.
// Parse from the environment.
if vStr, ok := os.LookupEnv(varReference); ok {
// Everything we get here will be a string value, so we need to process as a parser would.
if vmap, err := Parse(fmt.Sprintf("%s=%s", pkey, vStr)); err == nil {
v, ok := vmap[pkey]
return v, ok
}
}
return nil, false
}
func (p *parser) setValue(val interface{}) {
// Test to see if we are on an array or a map