func (t *Tree) parseRightTestOperand(prev *NameExpr) (*TestExpr, error) {
	right, err := t.parseInnerExpr()
	if err != nil {
		return nil, err
	}
	if prev == nil {
		if r, ok := right.(*NameExpr); ok {
			if nxt := t.peekNonSpace(); nxt.tokenType == tokenName {
				return t.parseRightTestOperand(r)
			}
		}
	}
	switch r := right.(type) {
	case *NameExpr:
		if prev != nil {
			r.Name = prev.Name + " " + r.Name
		}
		return NewTestExpr(r.Name, []Expr{}, r.Pos), nil
	case *FuncExpr:
		if prev != nil {
			r.Name = prev.Name + " " + r.Name
		}
		return &TestExpr{r}, nil
	default:
		return nil, fmt.Errorf(`Expected name or function, got "%v"`, right)
	}
}
parseIsRightOperand handles "is" and "is not" tests, which can
themselves be two words, such as "divisible by":
{% if 10 is divisible by(3) %}
package parse
import "fmt"
func (t *Tree) parseExpr() (Expr, error) {
	expr, err := t.parseInnerExpr()
	if err != nil {
		return nil, err
	}
	return t.parseOuterExpr(expr)
}
func (t *Tree) parseOuterExpr(expr Expr) (Expr, error) {
	switch nt := t.nextNonSpace(); nt.tokenType {
	case tokenParensOpen:
		switch name := expr.(type) {
		case *NameExpr:
			return t.parseFunc(name)
		default:
			return nil, newUnexpectedTokenError(nt)
		}
	case tokenArrayOpen, tokenPunctuation:
		switch nt.value {
		case ".", "[":  
			var args = make([]Expr, 0)
			attr, err := t.parseInnerExpr()
			if err != nil {
				return nil, err
			}
			if nt.value == "[" {
				ntt := t.peekNonSpace()
				if ntt.tokenType != tokenArrayClose {
					if attr, err = t.parseOuterExpr(attr); err != nil {
						return nil, err
					}
				}
				if _, err := t.expect(tokenArrayClose); err != nil {
					return nil, err
				}
			} else {
				switch exp := attr.(type) {
				case *NameExpr:
					attr = NewStringExpr(exp.Name, exp.Pos)
				case *NumberExpr:
					attr = NewStringExpr(exp.Value, exp.Pos)
				case *FuncExpr:
					for _, v := range exp.Args {
						args = append(args, v)
					}
					attr = NewStringExpr(exp.Name, exp.Pos)
				default:
					return nil, newUnexpectedTokenError(nt)
				}
			}
			return t.parseOuterExpr(NewGetAttrExpr(expr, attr, args, nt.Pos))
		case "|":  
			nx, err := t.parseExpr()
			if err != nil {
				return nil, err
			}
			switch n := nx.(type) {
			case *BinaryExpr:
				switch b := n.Left.(type) {
				case *NameExpr:
					v := NewFilterExpr(b.Name, []Expr{expr}, nt.Pos)
					n.Left = v
					return n, nil
				case *FuncExpr:
					b.Args = append([]Expr{expr}, b.Args...)
					v := NewFilterExpr(b.Name, b.Args, nt.Pos)
					n.Left = v
					return n, nil
				default:
					return nil, newUnexpectedTokenError(nt)
				}
			case *NameExpr:
				return NewFilterExpr(n.Name, []Expr{expr}, nt.Pos), nil
			case *FuncExpr:
				n.Args = append([]Expr{expr}, n.Args...)
				return NewFilterExpr(n.Name, n.Args, n.Pos), nil
			default:
				return nil, newUnexpectedTokenError(nt)
			}
		case "?":  
			tx, err := t.parseExpr()
			if err != nil {
				return nil, err
			}
			_, err = t.expectValue(tokenPunctuation, ":")
			if err != nil {
				return nil, err
			}
			fx, err := t.parseExpr()
			if err != nil {
				return nil, err
			}
			return NewTernaryIfExpr(expr, tx, fx, expr.Start()), nil
		default:
			t.backup()
			return expr, nil
		}
	case tokenOperator:
		op, ok := binaryOperators[nt.value]
		if !ok {
			return nil, newUnexpectedTokenError(nt)
		}
		var right Node
		var err error
		if op.op == OpBinaryIs || op.op == OpBinaryIsNot {
			right, err = t.parseRightTestOperand(nil)
			if err != nil {
				return nil, err
			}
		} else {
			right, err = t.parseExpr()
			if err != nil {
				return nil, err
			}
			if v, ok := right.(*BinaryExpr); ok {
				nxop := binaryOperators[v.Op]
				if nxop.precedence < op.precedence || (nxop.precedence == op.precedence && op.leftAssoc()) {
					left := v.Left
					res := NewBinaryExpr(expr, op.Operator(), left, expr.Start())
					v.Left = res
					return v, nil
				}
			}
		}
		return NewBinaryExpr(expr, op.Operator(), right, expr.Start()), nil
	default:
		t.backup()
		return expr, nil
	}
}