func Eval(expr *Node, settings map[string]string) (bool, error) {
	if expr == nil {
		return true, nil
	}
	switch expr.Code {
	case PARSE_NOT:
		r, err := Eval(expr.Right, settings)
		if err != nil {
			return false, err
		}
		return !r, nil
	case PARSE_EQUALS:
		return evalEquals(expr.Left, expr.Right, settings)
	case PARSE_NOT_EQUALS:
		v, err := evalEquals(expr.Left, expr.Right, settings)
		if err != nil {
			return false, err
		}
		return !v, nil
	case PARSE_LT:
		l, r, err := coerceTwoInts(expr.Left, expr.Right, settings, "<")
		if err != nil {
			return false, err
		}
		return l < r, nil
	case PARSE_LTE:
		l, r, err := coerceTwoInts(expr.Left, expr.Right, settings, "<=")
		if err != nil {
			return false, err
		}
		return l <= r, nil
	case PARSE_GT:
		l, r, err := coerceTwoInts(expr.Left, expr.Right, settings, ">")
		if err != nil {
			return false, err
		}
		return l > r, nil
	case PARSE_GTE:
		l, r, err := coerceTwoInts(expr.Left, expr.Right, settings, ">=")
		if err != nil {
			return false, err
		}
		return l >= r, nil
	case PARSE_AND:
		l, r, err := evalTwo(expr.Left, expr.Right, settings)
		if err != nil {
			return false, err
		}
		return l && r, nil
	case PARSE_OR:
		l, r, err := evalTwo(expr.Left, expr.Right, settings)
		if err != nil {
			return false, err
		}
		return l || r, nil
	case PARSE_XOR:
		l, r, err := evalTwo(expr.Left, expr.Right, settings)
		if err != nil {
			return false, err
		}
		return (l && !r) || (!l && r), nil
	case PARSE_NUMBER:
		num, ok := util.AtoiNoOctTry(expr.Data)
		return ok && num != 0, nil
	case PARSE_STRING:
		return ValueIsTrue(expr.Data), nil
	case PARSE_IDENT:
		val := settings[expr.Data]
		return ValueIsTrue(val), nil
	default:
		return false, fmt.Errorf("invalid parse code: %d", expr.Code)
	}
}
Evaluates a fully-parsed expression.

@param node                  The root of the expression to evaluate.
@param settings              The map of syscfg settings.

@return bool                 Whether the expression evaluates to true.
package parse
import (
	"fmt"
	"sort"
	"mynewt.apache.org/newt/util"
)
type ParseCode int
const (
	PARSE_NOT_EQUALS ParseCode = iota
	PARSE_NOT
	PARSE_EQUALS
	PARSE_LT
	PARSE_LTE
	PARSE_GT
	PARSE_GTE
	PARSE_AND
	PARSE_OR
	PARSE_XOR
	PARSE_NUMBER
	PARSE_STRING
	PARSE_IDENT
)
type Node struct {
	Code ParseCode
	Data string
	Left  *Node
	Right *Node
}
func (n *Node) String() string {
	if n == nil {
		return ""
	}
	s := ""
	if n.Left != nil {
		s += n.Left.String()
	}
	if n.Left != nil && n.Right != nil {
		s += " " + n.Data + " "
	} else {
		s += n.Data
	}
	if n.Right != nil {
		s += n.Right.String()
	}
	return s
}
func (n *Node) RpnString() string {
	if n == nil {
		return ""
	}
	s := fmt.Sprintf("<%s>", n.Data)
	if n.Left != nil {
		s += " " + n.Left.RpnString()
	}
	if n.Right != nil {
		s += " " + n.Right.RpnString()
	}
	return s
}
type nodeSorter struct {
	nodes []*Node
}
func (s nodeSorter) Len() int {
	return len(s.nodes)
}
func (s nodeSorter) Swap(i, j int) {
	s.nodes[i], s.nodes[j] = s.nodes[j], s.nodes[i]
}
func (s nodeSorter) Less(i, j int) bool {
	return s.nodes[i].String() < s.nodes[j].String()
}
func SortNodes(nodes []*Node) {
	sort.Sort(nodeSorter{nodes})
}
func NodesEqual(a *Node, b *Node) bool {
	return a.String() == b.String()
}
func findAnyToken(tokens []Token, any []TokenCode) (int, error) {
	pcount := 0
	for _, a := range any {
		for i, t := range tokens {
			if t.Code == TOKEN_LPAREN {
				pcount++
			} else if t.Code == TOKEN_RPAREN {
				pcount--
				if pcount < 0 {
					return -1, fmt.Errorf("imbalanced parenthesis")
				}
			} else if pcount == 0 && t.Code == a {
				return i, nil
			}
		}
	}
	return -1, nil
}
func binTokenToParse(t TokenCode) ParseCode {
	return map[TokenCode]ParseCode{
		TOKEN_NOT_EQUALS: PARSE_NOT_EQUALS,
		TOKEN_EQUALS:     PARSE_EQUALS,
		TOKEN_LT:         PARSE_LT,
		TOKEN_LTE:        PARSE_LTE,
		TOKEN_GT:         PARSE_GT,
		TOKEN_GTE:        PARSE_GTE,
		TOKEN_AND:        PARSE_AND,
		TOKEN_OR:         PARSE_OR,
		TOKEN_XOR:        PARSE_XOR,
	}[t]
}
func stripParens(tokens []Token) ([]Token, error) {
	if tokens[0].Code != TOKEN_LPAREN {
		panic("internal error: stripParens() received unparenthesized string")
	}
	pcount := 1
	for i := 1; i < len(tokens); i++ {
		switch tokens[i].Code {
		case TOKEN_LPAREN:
			pcount++
		case TOKEN_RPAREN:
			pcount--
			if pcount == 0 {
				return tokens[1:i], nil
			}
		default:
		}
	}
	return nil, fmt.Errorf("unterminated parenthesis")
}
var binaryTokens = []TokenCode{
	TOKEN_AND,
	TOKEN_XOR,
	TOKEN_OR,
	TOKEN_EQUALS,
	TOKEN_NOT_EQUALS,
	TOKEN_LT,
	TOKEN_LTE,
	TOKEN_GT,
	TOKEN_GTE,
}
func FindBinaryToken(tokens []Token) int {
	binIdx, err := findAnyToken(tokens, binaryTokens)
	if err != nil {
		return -1
	}
	return binIdx
}
func Parse(tokens []Token) (*Node, error) {
	if len(tokens) == 0 {
		return nil, nil
	}
	if len(tokens) == 1 {
		switch tokens[0].Code {
		case TOKEN_NUMBER:
			return &Node{
				Code: PARSE_NUMBER,
				Data: tokens[0].Text,
			}, nil
		case TOKEN_STRING:
			return &Node{
				Code: PARSE_STRING,
				Data: tokens[0].Text,
			}, nil
		case TOKEN_IDENT:
			return &Node{
				Code: PARSE_IDENT,
				Data: tokens[0].Text,
			}, nil
		default:
			return nil, fmt.Errorf("invalid expression: %s", tokens[0].Text)
		}
	}
	binIdx, err := findAnyToken(tokens, binaryTokens)
	if err != nil {
		return nil, err
	}
	if binIdx == 0 || binIdx == len(tokens)-1 {
		return nil, fmt.Errorf("binary operator %s at start or end",
			tokens[binIdx].Text)
	}
	if binIdx != -1 {
		n := &Node{
			Code: binTokenToParse(tokens[binIdx].Code),
			Data: tokens[binIdx].Text,
		}
		l, err := Parse(tokens[0:binIdx])
		if err != nil {
			return nil, err
		}
		r, err := Parse(tokens[binIdx+1 : len(tokens)])
		if err != nil {
			return nil, err
		}
		n.Left = l
		n.Right = r
		return n, nil
	}
	if tokens[0].Code == TOKEN_NOT {
		n := &Node{
			Code: PARSE_NOT,
			Data: tokens[0].Text,
		}
		r, err := Parse(tokens[1:])
		if err != nil {
			return nil, err
		}
		n.Right = r
		return n, nil
	}
	if tokens[0].Code == TOKEN_LPAREN {
		stripped, err := stripParens(tokens)
		if err != nil {
			return nil, err
		}
		return Parse(stripped)
	}
	return nil, fmt.Errorf("invalid expression")
}
func evalTwo(expr1 *Node, expr2 *Node,
	settings map[string]string) (bool, bool, error) {
	v1, err := Eval(expr1, settings)
	if err != nil {
		return false, false, err
	}
	v2, err := Eval(expr2, settings)
	if err != nil {
		return false, false, err
	}
	return v1, v2, nil
}
func coerceToInt(n *Node, settings map[string]string) (int, error) {
	switch n.Code {
	case PARSE_NUMBER:
		num, ok := util.AtoiNoOctTry(n.Data)
		if !ok {
			return 0,
				util.FmtNewtError("expression contains invalid number: `%s`",
					n.Data)
		}
		return num, nil
	case PARSE_IDENT:
		val := settings[n.Data]
		num, ok := util.AtoiNoOctTry(val)
		if !ok {
			return 0,
				util.FmtNewtError("setting %s has value `%s`, "+
					"which is not a number", n.Data, val)
		}
		return num, nil
	default:
		return 0,
			util.FmtNewtError("expression `%s` is not a valid number",
				n.String())
	}
}
func coerceTwoInts(left *Node, right *Node,
	settings map[string]string, opStr string) (int, int, error) {
	lnum, err := coerceToInt(left, settings)
	if err != nil {
		return 0, 0, util.FmtNewtError("cannot apply %s to `%s`; "+
			"operand not a number", opStr, left.String())
	}
	rnum, err := coerceToInt(right, settings)
	if err != nil {
		return 0, 0, util.FmtNewtError("cannot apply %s to `%s`; "+
			"operand not a number", opStr, right.String())
	}
	return lnum, rnum, nil
}
type equalsFn func(left *Node, right *Node, settings map[string]string) bool
type equalsEntry struct {
	LeftCode  ParseCode
	RightCode ParseCode
	Fn        equalsFn
}
var equalsDispatch = []equalsEntry{
	equalsEntry{
		LeftCode:  PARSE_IDENT,
		RightCode: PARSE_IDENT,
		Fn: func(left *Node, right *Node, settings map[string]string) bool {
			return settings[left.Data] == settings[right.Data]
		},
	},
	equalsEntry{
		LeftCode:  PARSE_IDENT,
		RightCode: PARSE_NUMBER,
		Fn: func(left *Node, right *Node, settings map[string]string) bool {
			lnum, ok := util.AtoiNoOctTry(settings[left.Data])
			if !ok {
				return false
			}
			rnum, ok := util.AtoiNoOctTry(right.Data)
			if !ok {
				return false
			}
			return lnum == rnum
		},
	},
	equalsEntry{
		LeftCode:  PARSE_IDENT,
		RightCode: PARSE_STRING,
		Fn: func(left *Node, right *Node, settings map[string]string) bool {
			return settings[left.Data] == right.Data
		},
	},
	equalsEntry{
		LeftCode:  PARSE_NUMBER,
		RightCode: PARSE_NUMBER,
		Fn: func(left *Node, right *Node, settings map[string]string) bool {
			lnum, ok := util.AtoiNoOctTry(left.Data)
			if !ok {
				return false
			}
			rnum, ok := util.AtoiNoOctTry(right.Data)
			if !ok {
				return false
			}
			return lnum == rnum
		},
	},
	equalsEntry{
		LeftCode:  PARSE_NUMBER,
		RightCode: PARSE_STRING,
		Fn: func(left *Node, right *Node, settings map[string]string) bool {
			return left.Data == right.Data
		},
	},
	equalsEntry{
		LeftCode:  PARSE_STRING,
		RightCode: PARSE_STRING,
		Fn: func(left *Node, right *Node, settings map[string]string) bool {
			return left.Data == right.Data
		},
	},
}
func evalEqualsOnce(
	left *Node, right *Node, settings map[string]string) (bool, bool) {
	for _, entry := range equalsDispatch {
		if entry.LeftCode == left.Code && entry.RightCode == right.Code {
			return entry.Fn(left, right, settings), true
		}
	}
	return false, false
}
func evalEquals(
	left *Node, right *Node, settings map[string]string) (bool, error) {
	val, ok := evalEqualsOnce(left, right, settings)
	if ok {
		return val, nil
	}
	val, ok = evalEqualsOnce(right, left, settings)
	if ok {
		return val, nil
	}
	booll, boolr, err := evalTwo(left, right, settings)
	if err != nil {
		return false, err
	}
	return booll == boolr, nil
}