diff options
Diffstat (limited to 'vendor/github.com/mitchellh/packer/vendor/github.com/ChrisTrenkamp/goxpath/internal/execxp/paths.go')
-rw-r--r-- | vendor/github.com/mitchellh/packer/vendor/github.com/ChrisTrenkamp/goxpath/internal/execxp/paths.go | 397 |
1 files changed, 397 insertions, 0 deletions
diff --git a/vendor/github.com/mitchellh/packer/vendor/github.com/ChrisTrenkamp/goxpath/internal/execxp/paths.go b/vendor/github.com/mitchellh/packer/vendor/github.com/ChrisTrenkamp/goxpath/internal/execxp/paths.go new file mode 100644 index 00000000..60ada7ab --- /dev/null +++ b/vendor/github.com/mitchellh/packer/vendor/github.com/ChrisTrenkamp/goxpath/internal/execxp/paths.go @@ -0,0 +1,397 @@ +package execxp + +import ( + "encoding/xml" + "fmt" + "strconv" + "strings" + + "github.com/ChrisTrenkamp/goxpath/internal/parser" + "github.com/ChrisTrenkamp/goxpath/internal/parser/findutil" + "github.com/ChrisTrenkamp/goxpath/internal/parser/intfns" + "github.com/ChrisTrenkamp/goxpath/internal/xconst" + "github.com/ChrisTrenkamp/goxpath/internal/xsort" + + "github.com/ChrisTrenkamp/goxpath/internal/lexer" + "github.com/ChrisTrenkamp/goxpath/internal/parser/pathexpr" + "github.com/ChrisTrenkamp/goxpath/tree" +) + +type xpFilt struct { + t tree.Node + ctx tree.Result + expr pathexpr.PathExpr + ns map[string]string + ctxPos int + ctxSize int + proxPos map[int]int + fns map[xml.Name]tree.Wrap + variables map[string]tree.Result +} + +type xpExecFn func(*xpFilt, string) + +var xpFns = map[lexer.XItemType]xpExecFn{ + lexer.XItemAbsLocPath: xfAbsLocPath, + lexer.XItemAbbrAbsLocPath: xfAbbrAbsLocPath, + lexer.XItemRelLocPath: xfRelLocPath, + lexer.XItemAbbrRelLocPath: xfAbbrRelLocPath, + lexer.XItemAxis: xfAxis, + lexer.XItemAbbrAxis: xfAbbrAxis, + lexer.XItemNCName: xfNCName, + lexer.XItemQName: xfQName, + lexer.XItemNodeType: xfNodeType, + lexer.XItemProcLit: xfProcInstLit, + lexer.XItemStrLit: xfStrLit, + lexer.XItemNumLit: xfNumLit, +} + +func xfExec(f *xpFilt, n *parser.Node) (err error) { + for n != nil { + if fn, ok := xpFns[n.Val.Typ]; ok { + fn(f, n.Val.Val) + n = n.Left + } else if n.Val.Typ == lexer.XItemPredicate { + if err = xfPredicate(f, n.Left); err != nil { + return + } + + n = n.Right + } else if n.Val.Typ == lexer.XItemFunction { + if err = xfFunction(f, n); err != nil { + return + } + + n = n.Right + } else if n.Val.Typ == lexer.XItemOperator { + lf := xpFilt{ + t: f.t, + ns: f.ns, + ctx: f.ctx, + ctxPos: f.ctxPos, + ctxSize: f.ctxSize, + proxPos: f.proxPos, + fns: f.fns, + variables: f.variables, + } + left, err := exec(&lf, n.Left) + if err != nil { + return err + } + + rf := xpFilt{ + t: f.t, + ns: f.ns, + ctx: f.ctx, + fns: f.fns, + variables: f.variables, + } + right, err := exec(&rf, n.Right) + if err != nil { + return err + } + + return xfOperator(left, right, f, n.Val.Val) + } else if n.Val.Typ == lexer.XItemVariable { + if res, ok := f.variables[n.Val.Val]; ok { + f.ctx = res + return nil + } + return fmt.Errorf("Invalid variable '%s'", n.Val.Val) + } else if string(n.Val.Typ) == "" { + n = n.Left + //} else { + // return fmt.Errorf("Cannot process " + string(n.Val.Typ)) + } + } + + return +} + +func xfPredicate(f *xpFilt, n *parser.Node) (err error) { + res := f.ctx.(tree.NodeSet) + newRes := make(tree.NodeSet, 0, len(res)) + + for i := range res { + pf := xpFilt{ + t: f.t, + ns: f.ns, + ctxPos: i, + ctxSize: f.ctxSize, + ctx: tree.NodeSet{res[i]}, + fns: f.fns, + variables: f.variables, + } + + predRes, err := exec(&pf, n) + if err != nil { + return err + } + + ok, err := checkPredRes(predRes, f, res[i]) + if err != nil { + return err + } + + if ok { + newRes = append(newRes, res[i]) + } + } + + f.proxPos = make(map[int]int) + for pos, j := range newRes { + f.proxPos[j.Pos()] = pos + 1 + } + + f.ctx = newRes + f.ctxSize = len(newRes) + + return +} + +func checkPredRes(ret tree.Result, f *xpFilt, node tree.Node) (bool, error) { + if num, ok := ret.(tree.Num); ok { + if float64(f.proxPos[node.Pos()]) == float64(num) { + return true, nil + } + return false, nil + } + + if b, ok := ret.(tree.IsBool); ok { + return bool(b.Bool()), nil + } + + return false, fmt.Errorf("Cannot convert argument to boolean") +} + +func xfFunction(f *xpFilt, n *parser.Node) error { + spl := strings.Split(n.Val.Val, ":") + var name xml.Name + if len(spl) == 1 { + name.Local = spl[0] + } else { + name.Space = f.ns[spl[0]] + name.Local = spl[1] + } + fn, ok := intfns.BuiltIn[name] + if !ok { + fn, ok = f.fns[name] + } + + if ok { + args := []tree.Result{} + param := n.Left + + for param != nil { + pf := xpFilt{ + t: f.t, + ctx: f.ctx, + ns: f.ns, + ctxPos: f.ctxPos, + ctxSize: f.ctxSize, + fns: f.fns, + variables: f.variables, + } + res, err := exec(&pf, param.Left) + if err != nil { + return err + } + + args = append(args, res) + param = param.Right + } + + filt, err := fn.Call(tree.Ctx{NodeSet: f.ctx.(tree.NodeSet), Size: f.ctxSize, Pos: f.ctxPos + 1}, args...) + f.ctx = filt + return err + } + + return fmt.Errorf("Unknown function: %s", n.Val.Val) +} + +var eqOps = map[string]bool{ + "=": true, + "!=": true, +} + +var booleanOps = map[string]bool{ + "=": true, + "!=": true, + "<": true, + "<=": true, + ">": true, + ">=": true, +} + +var numOps = map[string]bool{ + "*": true, + "div": true, + "mod": true, + "+": true, + "-": true, + "=": true, + "!=": true, + "<": true, + "<=": true, + ">": true, + ">=": true, +} + +var andOrOps = map[string]bool{ + "and": true, + "or": true, +} + +func xfOperator(left, right tree.Result, f *xpFilt, op string) error { + if booleanOps[op] { + lNode, lOK := left.(tree.NodeSet) + rNode, rOK := right.(tree.NodeSet) + if lOK && rOK { + return bothNodeOperator(lNode, rNode, f, op) + } + + if lOK { + return leftNodeOperator(lNode, right, f, op) + } + + if rOK { + return rightNodeOperator(left, rNode, f, op) + } + + if eqOps[op] { + return equalsOperator(left, right, f, op) + } + } + + if numOps[op] { + return numberOperator(left, right, f, op) + } + + if andOrOps[op] { + return andOrOperator(left, right, f, op) + } + + //if op == "|" { + return unionOperator(left, right, f, op) + //} + + //return fmt.Errorf("Unknown operator " + op) +} + +func xfAbsLocPath(f *xpFilt, val string) { + i := f.t + for i.GetNodeType() != tree.NtRoot { + i = i.GetParent() + } + f.ctx = tree.NodeSet{i} +} + +func xfAbbrAbsLocPath(f *xpFilt, val string) { + i := f.t + for i.GetNodeType() != tree.NtRoot { + i = i.GetParent() + } + f.ctx = tree.NodeSet{i} + f.expr = abbrPathExpr() + find(f) +} + +func xfRelLocPath(f *xpFilt, val string) { +} + +func xfAbbrRelLocPath(f *xpFilt, val string) { + f.expr = abbrPathExpr() + find(f) +} + +func xfAxis(f *xpFilt, val string) { + f.expr.Axis = val +} + +func xfAbbrAxis(f *xpFilt, val string) { + f.expr.Axis = xconst.AxisAttribute +} + +func xfNCName(f *xpFilt, val string) { + f.expr.Name.Space = val +} + +func xfQName(f *xpFilt, val string) { + f.expr.Name.Local = val + find(f) +} + +func xfNodeType(f *xpFilt, val string) { + f.expr.NodeType = val + find(f) +} + +func xfProcInstLit(f *xpFilt, val string) { + filt := tree.NodeSet{} + for _, i := range f.ctx.(tree.NodeSet) { + if i.GetToken().(xml.ProcInst).Target == val { + filt = append(filt, i) + } + } + f.ctx = filt +} + +func xfStrLit(f *xpFilt, val string) { + f.ctx = tree.String(val) +} + +func xfNumLit(f *xpFilt, val string) { + num, _ := strconv.ParseFloat(val, 64) + f.ctx = tree.Num(num) +} + +func abbrPathExpr() pathexpr.PathExpr { + return pathexpr.PathExpr{ + Name: xml.Name{}, + Axis: xconst.AxisDescendentOrSelf, + NodeType: xconst.NodeTypeNode, + } +} + +func find(f *xpFilt) { + dupFilt := make(map[int]tree.Node) + f.proxPos = make(map[int]int) + + if f.expr.Axis == "" && f.expr.NodeType == "" && f.expr.Name.Space == "" { + if f.expr.Name.Local == "." { + f.expr = pathexpr.PathExpr{ + Name: xml.Name{}, + Axis: xconst.AxisSelf, + NodeType: xconst.NodeTypeNode, + } + } + + if f.expr.Name.Local == ".." { + f.expr = pathexpr.PathExpr{ + Name: xml.Name{}, + Axis: xconst.AxisParent, + NodeType: xconst.NodeTypeNode, + } + } + } + + f.expr.NS = f.ns + + for _, i := range f.ctx.(tree.NodeSet) { + for pos, j := range findutil.Find(i, f.expr) { + dupFilt[j.Pos()] = j + f.proxPos[j.Pos()] = pos + 1 + } + } + + res := make(tree.NodeSet, 0, len(dupFilt)) + for _, i := range dupFilt { + res = append(res, i) + } + + xsort.SortNodes(res) + + f.expr = pathexpr.PathExpr{} + f.ctxSize = len(res) + f.ctx = res +} |