// Resolve ... func (e *Expr) Resolve(tree map[interface{}]interface{}) (*Expr, error) { switch e.Type { case Literal: return e, nil case EnvVar: v := os.Getenv(e.Name) if v == "" { return nil, ansi.Errorf("@R{Environment variable} @c{$%s} @R{is not set}", e.Name) } return &Expr{Type: Literal, Literal: v}, nil case Reference: if _, err := e.Reference.Resolve(tree); err != nil { return nil, ansi.Errorf("@R{Unable to resolve `}@c{%s}@R{`: %s}", e.Reference, err) } return e, nil case LogicalOr: if o, err := e.Left.Resolve(tree); err == nil { return o, nil } return e.Right.Resolve(tree) } return nil, ansi.Errorf("@R{unknown expression operand type (}@c{%d}@R{)}", e.Type) }
// Reduce ... func (e *Expr) Reduce() (*Expr, error) { var reduce func(*Expr) (*Expr, *Expr, bool) reduce = func(e *Expr) (*Expr, *Expr, bool) { switch e.Type { case Literal: return e, e, false case EnvVar: return e, nil, false case Reference: return e, nil, false case LogicalOr: l, short, _ := reduce(e.Left) if short != nil { return l, short, true } r, short, more := reduce(e.Right) return &Expr{ Type: LogicalOr, Left: l, Right: r, }, short, more } return nil, nil, false } reduced, short, more := reduce(e) if more && short != nil { return reduced, ansi.Errorf("@R{literal} @c{%v} @R{short-circuits expression (}@c{%s}@R{)}", short, e) } return reduced, nil }
// Run ... func (op *Opcall) Run(ev *Evaluator) (*Response, error) { was := ev.Here ev.Here = op.where r, err := op.op.Run(ev, op.args) ev.Here = was if err != nil { return nil, ansi.Errorf("@m{$.%s}: @R{%s}", op.where, err) } return r, nil }
// Run ... func (CartesianProductOperator) Run(ev *Evaluator, args []*Expr) (*Response, error) { DEBUG("running (( cartesian-product ... )) operation at $.%s", ev.Here) defer DEBUG("done with (( cartesian-product ... )) operation at $%s\n", ev.Here) var vals [][]string for i, arg := range args { v, err := arg.Resolve(ev.Tree) if err != nil { DEBUG(" [%d]: resolution failed\n error: %s", i, err) return nil, err } switch v.Type { case Literal: DEBUG(" arg[%d]: found string literal '%s'", i, v.Literal) vals = append(vals, []string{v.Literal.(string)}) case Reference: DEBUG(" arg[%d]: trying to resolve reference $.%s", i, v.Reference) s, err := v.Reference.Resolve(ev.Tree) if err != nil { DEBUG(" [%d]: resolution failed\n error: %s", i, err) return nil, ansi.Errorf("Unable to resolve `@m{%s}`: %s", v.Reference, err) } switch s.(type) { case []interface{}: var strs []string DEBUG(" [%d]: resolved to a list; verifying", i) for j, sub := range s.([]interface{}) { if _, ok := sub.([]interface{}); ok { DEBUG(" list[%d]: list item is itself a list; error!", j) return nil, fmt.Errorf("cartesian-product operator can only operate on lists of scalar values") } else if _, ok := sub.(map[interface{}]interface{}); ok { DEBUG(" list[%d]: list item is a map; error!", j) return nil, fmt.Errorf("cartesian-product operator can only operate on lists of scalar values") } DEBUG(" list[%d]: list item is a scalar: %v", j, sub) strs = append(strs, fmt.Sprintf("%v", sub)) } vals = append(vals, strs) case map[interface{}]interface{}: DEBUG(" [%d]: resolved to a map; error!", i) return nil, fmt.Errorf("cartesian-product operator only accepts arrays and string values") default: DEBUG(" [%d]: resolved to a scalar; appending", i) vals = append(vals, []string{fmt.Sprintf("%v", s)}) } default: DEBUG(" arg[%d]: I don't know what to do with '%v'", i, arg) return nil, fmt.Errorf("cartesian-product operator only accepts key reference arguments") } DEBUG("") } switch len(args) { case 0: DEBUG(" no arguments supplied to (( cartesian-product ... )) operation. oops.") return nil, ansi.Errorf("no arguments specified to @c{(( cartesian-product ... ))}") case 1: DEBUG(" called with only one argument; returning value as-is") return &Response{ Type: Replace, Value: vals[0], }, nil default: DEBUG(" called with more than one arguments; combining into a single list of strings") lst := vals[0] for _, l := range vals[1:] { lst = cartesian(lst, l) } return &Response{ Type: Replace, Value: lst, }, nil } }