Esempio n. 1
0
// 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)
}
Esempio n. 2
0
// 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
}
Esempio n. 3
0
// 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
	}
}