// Copyright 2014 The ql Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found pIn the LICENSE file.

package ql

import (
	"fmt"
	"math/big"
	"regexp"
	"strings"
	"time"
)

var (
	_ expression = (*binaryOperation)(nil)
	_ expression = (*call)(nil)
	_ expression = (*conversion)(nil)
	_ expression = (*ident)(nil)
	_ expression = (*indexOp)(nil)
	_ expression = (*isNull)(nil)
	_ expression = (*pIn)(nil)
	_ expression = (*pLike)(nil)
	_ expression = (*parameter)(nil)
	_ expression = (*pexpr)(nil)
	_ expression = (*slice)(nil)
	_ expression = (*unaryOperation)(nil)
	_ expression = value{}
)

type expression interface {
	clone(arg []interface{}, unqualify ...string) (expression, error)
	eval(execCtx *execCtx, ctx map[interface{}]interface{}) (v interface{}, err error)
	isStatic() bool
	String() string
}

func cloneExpressionList(arg []interface{}, list []expression, unqualify ...string) ([]expression, error) {
	r := make([]expression, len(list))
	var err error
	for i, v := range list {
		if r[i], err = v.clone(arg, unqualify...); err != nil {
			return nil, err
		}
	}
	return r, nil
}

func isConstValue(v interface{}) interface{} {
	switch x := v.(type) {
	case value:
		return x.val
	case
		idealComplex,
		idealFloat,
		idealInt,
		idealRune,
		idealUint:
		return v
	default:
		return nil
	}
}

func isColumnExpression(v expression) (bool, string) {
	x, ok := v.(*ident)
	if ok {
		return true, x.s
	}

	c, ok := v.(*call)
	if !ok || c.f != "id" || len(c.arg) != 0 {
		return false, ""
	}

	return true, "id()"
}

func mentionedColumns0(e expression, q, nq bool, m map[string]struct{}) {
	switch x := e.(type) {
	case parameter,
		value:
		// nop
	case *binaryOperation:
		mentionedColumns0(x.l, q, nq, m)
		mentionedColumns0(x.r, q, nq, m)
	case *call:
		if x.f != "id" {
			for _, e := range x.arg {
				mentionedColumns0(e, q, nq, m)
			}
		}
	case *conversion:
		mentionedColumns0(x.val, q, nq, m)
	case *ident:
		if q && x.isQualified() {
			m[x.s] = struct{}{}
		}
		if nq && !x.isQualified() {
			m[x.s] = struct{}{}
		}
	case *indexOp:
		mentionedColumns0(x.expr, q, nq, m)
		mentionedColumns0(x.x, q, nq, m)
	case *isNull:
		mentionedColumns0(x.expr, q, nq, m)
	case *pexpr:
		mentionedColumns0(x.expr, q, nq, m)
	case *pIn:
		mentionedColumns0(x.expr, q, nq, m)
		for _, e := range x.list {
			mentionedColumns0(e, q, nq, m)
		}
	case *pLike:
		mentionedColumns0(x.expr, q, nq, m)
		mentionedColumns0(x.pattern, q, nq, m)
	case *slice:
		mentionedColumns0(x.expr, q, nq, m)
		if y := x.lo; y != nil {
			mentionedColumns0(*y, q, nq, m)
		}
		if y := x.hi; y != nil {
			mentionedColumns0(*y, q, nq, m)
		}
	case *unaryOperation:
		mentionedColumns0(x.v, q, nq, m)
	default:
		panic("internal error 052")
	}
}

func mentionedColumns(e expression) map[string]struct{} {
	m := map[string]struct{}{}
	mentionedColumns0(e, false, true, m)
	return m
}

func staticExpr(e expression) (expression, error) {
	if e.isStatic() {
		v, err := e.eval(nil, nil)
		if err != nil {
			return nil, err
		}

		if v == nil {
			return value{nil}, nil
		}

		return value{v}, nil
	}

	return e, nil
}

type (
	idealComplex complex128
	idealFloat   float64
	idealInt     int64
	idealRune    int32
	idealUint    uint64
)

type pexpr struct {
	expr expression
}

func (p *pexpr) clone(arg []interface{}, unqualify ...string) (expression, error) {
	expr, err := p.expr.clone(arg, unqualify...)
	if err != nil {
		return nil, err
	}

	return &pexpr{expr: expr}, nil
}

func (p *pexpr) isStatic() bool { return p.expr.isStatic() }

func (p *pexpr) String() string {
	return fmt.Sprintf("(%s)", p.expr)
}

func (p *pexpr) eval(execCtx *execCtx, ctx map[interface{}]interface{}) (v interface{}, err error) {
	return p.expr.eval(execCtx, ctx)
}

//DONE newBetween
//LATER like newBetween, check all others have and use new*

func newBetween(expr, lo, hi interface{}, not bool) (expression, error) {
	e, err := staticExpr(expr.(expression))
	if err != nil {
		return nil, err
	}

	l, err := staticExpr(lo.(expression))
	if err != nil {
		return nil, err
	}

	h, err := staticExpr(hi.(expression))
	if err != nil {
		return nil, err
	}

	var a, b expression
	op := andand
	switch {
	case not: // e < l || e > h
		op = oror
		if a, err = newBinaryOperation('<', e, l); err != nil {
			return nil, err
		}

		if b, err = newBinaryOperation('>', e, h); err != nil {
			return nil, err
		}
	default: // e >= l && e <= h
		if a, err = newBinaryOperation(ge, e, l); err != nil {
			return nil, err
		}

		if b, err = newBinaryOperation(le, e, h); err != nil {
			return nil, err
		}
	}

	if a, err = staticExpr(a); err != nil {
		return nil, err
	}

	if b, err = staticExpr(b); err != nil {
		return nil, err
	}

	ret, err := newBinaryOperation(op, a, b)
	if err != nil {
		return nil, err
	}

	return staticExpr(ret)
}

type pLike struct {
	expr    expression
	pattern expression
	re      *regexp.Regexp
	sexpr   *string
}

func (p *pLike) clone(arg []interface{}, unqualify ...string) (expression, error) {
	expr, err := p.expr.clone(arg, unqualify...)
	if err != nil {
		return nil, err
	}

	pattern, err := p.pattern.clone(arg, unqualify...)
	if err != nil {
		return nil, err
	}

	return &pLike{
		expr:    expr,
		pattern: pattern,
		re:      p.re,
		sexpr:   p.sexpr,
	}, nil
}

func (p *pLike) isStatic() bool { return p.expr.isStatic() && p.pattern.isStatic() }
func (p *pLike) String() string { return fmt.Sprintf("%s LIKE %s", p.expr, p.pattern) }

func (p *pLike) eval(execCtx *execCtx, ctx map[interface{}]interface{}) (v interface{}, err error) {
	var sexpr string
	var ok bool
	switch {
	case p.sexpr != nil:
		sexpr = *p.sexpr
	default:
		expr, err := expand1(p.expr.eval(execCtx, ctx))
		if err != nil {
			return nil, err
		}

		if expr == nil {
			return nil, nil
		}

		sexpr, ok = expr.(string)
		if !ok {
			return nil, fmt.Errorf("non-string expression in LIKE: %v (value of type %T)", expr, expr)
		}

		if p.expr.isStatic() {
			p.sexpr = new(string)
			*p.sexpr = sexpr
		}
	}

	re := p.re
	if re == nil {
		pattern, err := expand1(p.pattern.eval(execCtx, ctx))
		if err != nil {
			return nil, err
		}

		if pattern == nil {
			return nil, nil
		}

		spattern, ok := pattern.(string)
		if !ok {
			return nil, fmt.Errorf("non-string pattern in LIKE: %v (value of type %T)", pattern, pattern)
		}

		if re, err = regexp.Compile(spattern); err != nil {
			return nil, err
		}

		if p.pattern.isStatic() {
			p.re = re
		}
	}

	return re.MatchString(sexpr), nil
}

type binaryOperation struct {
	op   int
	l, r expression
}

func newBinaryOperation0(op int, x, y interface{}) (v expression, err error) {
	if op == eq {
		if l, ok := x.(value); ok {
			if b, ok := l.val.(bool); ok {
				if b { // true == y: y
					return y.(expression), nil
				}

				// false == y: !y
				return newUnaryOperation('!', y)
			}
		}

		if r, ok := y.(value); ok {
			if b, ok := r.val.(bool); ok {
				if b { // x == true: x
					return x.(expression), nil
				}

				// x == false: !x
				return newUnaryOperation('!', x)
			}
		}
	}

	if op == neq {
		if l, ok := x.(value); ok {
			if b, ok := l.val.(bool); ok {
				if b { // true != y: !y
					return newUnaryOperation('!', y)
				}

				// false != y: y
				return y.(expression), nil
			}
		}

		if r, ok := y.(value); ok {
			if b, ok := r.val.(bool); ok {
				if b { // x != true: !x
					return newUnaryOperation('!', x)
				}

				// x != false: x
				return x.(expression), nil
			}
		}
	}

	b := binaryOperation{op, x.(expression), y.(expression)}
	var lv interface{}
	if e := b.l; e.isStatic() {
		if lv, err = e.eval(nil, nil); err != nil {
			return nil, err
		}

		b.l = value{lv}
	}

	if e := b.r; e.isStatic() {
		v, err := e.eval(nil, nil)
		if err != nil {
			return nil, err
		}

		if v == nil {
			return value{nil}, nil
		}

		if op == '/' || op == '%' {
			rb := binaryOperation{eq, e, value{idealInt(0)}}
			val, err := rb.eval(nil, nil)
			if err != nil {
				return nil, err
			}

			if val.(bool) {
				return nil, errDivByZero
			}
		}

		if b.l.isStatic() && lv == nil {
			return value{nil}, nil
		}

		b.r = value{v}
	}

	if !b.isStatic() {
		return &b, nil
	}

	val, err := b.eval(nil, nil)
	return value{val}, err
}

func newBinaryOperation(op int, x, y interface{}) (v expression, err error) {
	expr, err := newBinaryOperation0(op, x, y)
	if err != nil {
		return nil, err
	}

	b, ok := expr.(*binaryOperation)
	if !ok {
		return expr, nil
	}

	if _, ok := b.l.(*ident); ok {
		return expr, nil
	}

	if c, ok := b.l.(*call); ok && c.f == "id" {
		return expr, nil
	}

	var r expression
	if r, ok = b.r.(*ident); !ok {
		r1, ok := b.r.(*call)
		if !ok || r1.f != "id" || len(r1.arg) != 0 {
			return expr, nil
		}

		r = r1
	}

	// Normalize expr relOp indent: ident invRelOp expr
	switch b.op {
	case '<':
		return &binaryOperation{'>', r, b.l}, nil
	case le:
		return &binaryOperation{ge, r, b.l}, nil
	case '>':
		return &binaryOperation{'<', r, b.l}, nil
	case ge:
		return &binaryOperation{le, r, b.l}, nil
	case eq, neq:
		return &binaryOperation{b.op, r, b.l}, nil
	default:
		return expr, nil
	}
}

func (o *binaryOperation) isIdentRelOpVal() (bool, string, interface{}, error) {
	sid := ""
	id, ok := o.l.(*ident)
	if !ok {
		f, ok := o.l.(*call)
		if !ok || f.f != "id" || len(f.arg) != 0 {
			return false, "", nil, nil
		}

		sid = "id()"
	} else {
		if id.isQualified() {
			return false, "", nil, nil
		}

		sid = id.s
	}

	if v, ok := o.r.(value); ok {
		switch o.op {
		case '<',
			le,
			'>',
			ge,
			eq,
			neq:
			return true, sid, v.val, nil
		default:
			return false, "", nil, nil
		}
	}

	return false, "", nil, nil
}

func (o *binaryOperation) clone(arg []interface{}, unqualify ...string) (expression, error) {
	l, err := o.l.clone(arg, unqualify...)
	if err != nil {
		return nil, err
	}

	r, err := o.r.clone(arg, unqualify...)
	if err != nil {
		return nil, err
	}

	return newBinaryOperation(o.op, l, r)
}

func (o *binaryOperation) isStatic() bool { return o.l.isStatic() && o.r.isStatic() }

func (o *binaryOperation) String() string {
	return fmt.Sprintf("%s %s %s", o.l, iop(o.op), o.r)
}

func (o *binaryOperation) eval(execCtx *execCtx, ctx map[interface{}]interface{}) (r interface{}, err error) {
	defer func() {
		if e := recover(); e != nil {
			switch x := e.(type) {
			case error:
				r, err = nil, x
			default:
				r, err = nil, fmt.Errorf("%v", x)
			}
		}
	}()

	switch op := o.op; op {
	case andand:
		a, err := expand1(o.l.eval(execCtx, ctx))
		if err != nil {
			return nil, err
		}

		switch x := a.(type) {
		case nil:
			b, err := expand1(o.r.eval(execCtx, ctx))
			if err != nil {
				return nil, err
			}

			switch y := b.(type) {
			case nil:
				return nil, nil
			case bool:
				if !y {
					return false, nil
				}

				return nil, nil
			default:
				return invOp2(x, y, op)
			}
		case bool:
			if !x {
				return false, nil
			}

			b, err := expand1(o.r.eval(execCtx, ctx))
			if err != nil {
				return nil, err
			}

			switch y := b.(type) {
			case nil:
				return nil, nil
			case bool:
				return y, nil
			default:
				return invOp2(x, y, op)
			}
		default:
			return undOp(x, op)
		}
	case oror:
		a, err := expand1(o.l.eval(execCtx, ctx))
		if err != nil {
			return nil, err
		}

		switch x := a.(type) {
		case nil:
			b, err := expand1(o.r.eval(execCtx, ctx))
			if err != nil {
				return nil, err
			}

			switch y := b.(type) {
			case nil:
				return nil, nil
			case bool:
				if y {
					return y, nil
				}

				return nil, nil
			default:
				return invOp2(x, y, op)
			}
		case bool:
			if x {
				return x, nil
			}

			b, err := expand1(o.r.eval(execCtx, ctx))
			if err != nil {
				return nil, err
			}

			switch y := b.(type) {
			case nil:
				return nil, nil
			case bool:
				return y, nil
			default:
				return invOp2(x, y, op)
			}
		default:
			return undOp(x, op)
		}
	case '>':
		a, b := o.get2(execCtx, ctx)
		if a == nil || b == nil {
			return
		}
		switch x := a.(type) {
		//case nil:
		case idealComplex:
			return undOp2(a, b, op)
		case idealFloat:
			switch y := b.(type) {
			case idealFloat:
				return x > y, nil
			default:
				return invOp2(x, y, op)
			}
		case idealInt:
			switch y := b.(type) {
			case idealInt:
				return x > y, nil
			default:
				return invOp2(x, y, op)
			}
		case idealRune:
			switch y := b.(type) {
			case idealRune:
				return x > y, nil
			default:
				return invOp2(x, y, op)
			}
		case idealUint:
			switch y := b.(type) {
			case idealUint:
				return x > y, nil
			default:
				return invOp2(x, y, op)
			}
		case bool:
			return undOp2(a, b, op)
		case complex64:
			return undOp2(a, b, op)
		case complex128:
			return undOp2(a, b, op)
		case float32:
			switch y := b.(type) {
			case float32:
				return x > y, nil
			default:
				return invOp2(x, y, op)
			}
		case float64:
			switch y := b.(type) {
			case float64:
				return x > y, nil
			default:
				return invOp2(x, y, op)
			}
		case int8:
			switch y := b.(type) {
			case int8:
				return x > y, nil
			default:
				return invOp2(x, y, op)
			}
		case int16:
			switch y := b.(type) {
			case int16:
				return x > y, nil
			default:
				return invOp2(x, y, op)
			}
		case int32:
			switch y := b.(type) {
			case int32:
				return x > y, nil
			default:
				return invOp2(x, y, op)
			}
		case int64:
			switch y := b.(type) {
			case int64:
				return x > y, nil
			default:
				return invOp2(x, y, op)
			}
		case string:
			switch y := b.(type) {
			case string:
				return x > y, nil
			default:
				return invOp2(x, y, op)
			}
		case uint8:
			switch y := b.(type) {
			case uint8:
				return x > y, nil
			default:
				return invOp2(x, y, op)
			}
		case uint16:
			switch y := b.(type) {
			case uint16:
				return x > y, nil
			default:
				return invOp2(x, y, op)
			}
		case uint32:
			switch y := b.(type) {
			case uint32:
				return x > y, nil
			default:
				return invOp2(x, y, op)
			}
		case uint64:
			switch y := b.(type) {
			case uint64:
				return x > y, nil
			default:
				return invOp2(x, y, op)
			}
		case *big.Int:
			switch y := b.(type) {
			case *big.Int:
				return x.Cmp(y) > 0, nil
			default:
				return invOp2(x, y, op)
			}
		case *big.Rat:
			switch y := b.(type) {
			case *big.Rat:
				return x.Cmp(y) > 0, nil
			default:
				return invOp2(x, y, op)
			}
		case time.Duration:
			switch y := b.(type) {
			case time.Duration:
				return x > y, nil
			default:
				return invOp2(x, y, op)
			}
		case time.Time:
			switch y := b.(type) {
			case time.Time:
				return x.After(y), nil
			default:
				return invOp2(x, y, op)
			}
		default:
			return invOp2(a, b, op)
		}
	case '<':
		a, b := o.get2(execCtx, ctx)
		if a == nil || b == nil {
			return
		}
		switch x := a.(type) {
		//case nil:
		case idealComplex:
			return undOp2(a, b, op)
		case idealFloat:
			switch y := b.(type) {
			case idealFloat:
				return x < y, nil
			default:
				return invOp2(x, y, op)
			}
		case idealInt:
			switch y := b.(type) {
			case idealInt:
				return x < y, nil
			default:
				return invOp2(x, y, op)
			}
		case idealRune:
			switch y := b.(type) {
			case idealRune:
				return x < y, nil
			default:
				return invOp2(x, y, op)
			}
		case idealUint:
			switch y := b.(type) {
			case idealUint:
				return x < y, nil
			default:
				return invOp2(x, y, op)
			}
		case bool:
			return undOp2(a, b, op)
		case complex64:
			return undOp2(a, b, op)
		case complex128:
			return undOp2(a, b, op)
		case float32:
			switch y := b.(type) {
			case float32:
				return x < y, nil
			default:
				return invOp2(x, y, op)
			}
		case float64:
			switch y := b.(type) {
			case float64:
				return x < y, nil
			default:
				return invOp2(x, y, op)
			}
		case int8:
			switch y := b.(type) {
			case int8:
				return x < y, nil
			default:
				return invOp2(x, y, op)
			}
		case int16:
			switch y := b.(type) {
			case int16:
				return x < y, nil
			default:
				return invOp2(x, y, op)
			}
		case int32:
			switch y := b.(type) {
			case int32:
				return x < y, nil
			default:
				return invOp2(x, y, op)
			}
		case int64:
			switch y := b.(type) {
			case int64:
				return x < y, nil
			default:
				return invOp2(x, y, op)
			}
		case string:
			switch y := b.(type) {
			case string:
				return x < y, nil
			default:
				return invOp2(x, y, op)
			}
		case uint8:
			switch y := b.(type) {
			case uint8:
				return x < y, nil
			default:
				return invOp2(x, y, op)
			}
		case uint16:
			switch y := b.(type) {
			case uint16:
				return x < y, nil
			default:
				return invOp2(x, y, op)
			}
		case uint32:
			switch y := b.(type) {
			case uint32:
				return x < y, nil
			default:
				return invOp2(x, y, op)
			}
		case uint64:
			switch y := b.(type) {
			case uint64:
				return x < y, nil
			default:
				return invOp2(x, y, op)
			}
		case *big.Int:
			switch y := b.(type) {
			case *big.Int:
				return x.Cmp(y) < 0, nil
			default:
				return invOp2(x, y, op)
			}
		case *big.Rat:
			switch y := b.(type) {
			case *big.Rat:
				return x.Cmp(y) < 0, nil
			default:
				return invOp2(x, y, op)
			}
		case time.Duration:
			switch y := b.(type) {
			case time.Duration:
				return x < y, nil
			default:
				return invOp2(x, y, op)
			}
		case time.Time:
			switch y := b.(type) {
			case time.Time:
				return x.Before(y), nil
			default:
				return invOp2(x, y, op)
			}
		default:
			return invOp2(a, b, op)
		}
	case le:
		a, b := o.get2(execCtx, ctx)
		if a == nil || b == nil {
			return
		}
		switch x := a.(type) {
		//case nil:
		case idealComplex:
			return undOp2(a, b, op)
		case idealFloat:
			switch y := b.(type) {
			case idealFloat:
				return x <= y, nil
			default:
				return invOp2(x, y, op)
			}
		case idealInt:
			switch y := b.(type) {
			case idealInt:
				return x <= y, nil
			default:
				return invOp2(x, y, op)
			}
		case idealRune:
			switch y := b.(type) {
			case idealRune:
				return x <= y, nil
			default:
				return invOp2(x, y, op)
			}
		case idealUint:
			switch y := b.(type) {
			case idealUint:
				return x <= y, nil
			default:
				return invOp2(x, y, op)
			}
		case bool:
			return undOp2(a, b, op)
		case complex64:
			return undOp2(a, b, op)
		case complex128:
			return undOp2(a, b, op)
		case float32:
			switch y := b.(type) {
			case float32:
				return x <= y, nil
			default:
				return invOp2(x, y, op)
			}
		case float64:
			switch y := b.(type) {
			case float64:
				return x <= y, nil
			default:
				return invOp2(x, y, op)
			}
		case int8:
			switch y := b.(type) {
			case int8:
				return x <= y, nil
			default:
				return invOp2(x, y, op)
			}
		case int16:
			switch y := b.(type) {
			case int16:
				return x <= y, nil
			default:
				return invOp2(x, y, op)
			}
		case int32:
			switch y := b.(type) {
			case int32:
				return x <= y, nil
			default:
				return invOp2(x, y, op)
			}
		case int64:
			switch y := b.(type) {
			case int64:
				return x <= y, nil
			default:
				return invOp2(x, y, op)
			}
		case string:
			switch y := b.(type) {
			case string:
				return x <= y, nil
			default:
				return invOp2(x, y, op)
			}
		case uint8:
			switch y := b.(type) {
			case uint8:
				return x <= y, nil
			default:
				return invOp2(x, y, op)
			}
		case uint16:
			switch y := b.(type) {
			case uint16:
				return x <= y, nil
			default:
				return invOp2(x, y, op)
			}
		case uint32:
			switch y := b.(type) {
			case uint32:
				return x <= y, nil
			default:
				return invOp2(x, y, op)
			}
		case uint64:
			switch y := b.(type) {
			case uint64:
				return x <= y, nil
			default:
				return invOp2(x, y, op)
			}
		case *big.Int:
			switch y := b.(type) {
			case *big.Int:
				return x.Cmp(y) <= 0, nil
			default:
				return invOp2(x, y, op)
			}
		case *big.Rat:
			switch y := b.(type) {
			case *big.Rat:
				return x.Cmp(y) <= 0, nil
			default:
				return invOp2(x, y, op)
			}
		case time.Duration:
			switch y := b.(type) {
			case time.Duration:
				return x <= y, nil
			default:
				return invOp2(x, y, op)
			}
		case time.Time:
			switch y := b.(type) {
			case time.Time:
				return x.Before(y) || x.Equal(y), nil
			default:
				return invOp2(x, y, op)
			}
		default:
			return invOp2(a, b, op)
		}
	case ge:
		a, b := o.get2(execCtx, ctx)
		if a == nil || b == nil {
			return
		}
		switch x := a.(type) {
		//case nil:
		case idealComplex:
			return undOp2(a, b, op)
		case idealFloat:
			switch y := b.(type) {
			case idealFloat:
				return x >= y, nil
			default:
				return invOp2(x, y, op)
			}
		case idealInt:
			switch y := b.(type) {
			case idealInt:
				return x >= y, nil
			default:
				return invOp2(x, y, op)
			}
		case idealRune:
			switch y := b.(type) {
			case idealRune:
				return x >= y, nil
			default:
				return invOp2(x, y, op)
			}
		case idealUint:
			switch y := b.(type) {
			case idealUint:
				return x >= y, nil
			default:
				return invOp2(x, y, op)
			}
		case bool:
			return undOp2(a, b, op)
		case complex64:
			return undOp2(a, b, op)
		case complex128:
			return undOp2(a, b, op)
		case float32:
			switch y := b.(type) {
			case float32:
				return x >= y, nil
			default:
				return invOp2(x, y, op)
			}
		case float64:
			switch y := b.(type) {
			case float64:
				return x >= y, nil
			default:
				return invOp2(x, y, op)
			}
		case int8:
			switch y := b.(type) {
			case int8:
				return x >= y, nil
			default:
				return invOp2(x, y, op)
			}
		case int16:
			switch y := b.(type) {
			case int16:
				return x >= y, nil
			default:
				return invOp2(x, y, op)
			}
		case int32:
			switch y := b.(type) {
			case int32:
				return x >= y, nil
			default:
				return invOp2(x, y, op)
			}
		case int64:
			switch y := b.(type) {
			case int64:
				return x >= y, nil
			default:
				return invOp2(x, y, op)
			}
		case string:
			switch y := b.(type) {
			case string:
				return x >= y, nil
			default:
				return invOp2(x, y, op)
			}
		case uint8:
			switch y := b.(type) {
			case uint8:
				return x >= y, nil
			default:
				return invOp2(x, y, op)
			}
		case uint16:
			switch y := b.(type) {
			case uint16:
				return x >= y, nil
			default:
				return invOp2(x, y, op)
			}
		case uint32:
			switch y := b.(type) {
			case uint32:
				return x >= y, nil
			default:
				return invOp2(x, y, op)
			}
		case uint64:
			switch y := b.(type) {
			case uint64:
				return x >= y, nil
			default:
				return invOp2(x, y, op)
			}
		case *big.Int:
			switch y := b.(type) {
			case *big.Int:
				return x.Cmp(y) >= 0, nil
			default:
				return invOp2(x, y, op)
			}
		case *big.Rat:
			switch y := b.(type) {
			case *big.Rat:
				return x.Cmp(y) >= 0, nil
			default:
				return invOp2(x, y, op)
			}
		case time.Duration:
			switch y := b.(type) {
			case time.Duration:
				return x >= y, nil
			default:
				return invOp2(x, y, op)
			}
		case time.Time:
			switch y := b.(type) {
			case time.Time:
				return x.After(y) || x.Equal(y), nil
			default:
				return invOp2(x, y, op)
			}
		default:
			return invOp2(a, b, op)
		}
	case neq:
		a, b := o.get2(execCtx, ctx)
		if a == nil || b == nil {
			return
		}
		switch x := a.(type) {
		//case nil:
		case idealComplex:
			switch y := b.(type) {
			case idealComplex:
				return x != y, nil
			default:
				return invOp2(x, y, op)
			}
		case idealFloat:
			switch y := b.(type) {
			case idealFloat:
				return x != y, nil
			default:
				return invOp2(x, y, op)
			}
		case idealInt:
			switch y := b.(type) {
			case idealInt:
				return x != y, nil
			default:
				return invOp2(x, y, op)
			}
		case idealRune:
			switch y := b.(type) {
			case idealRune:
				return x != y, nil
			default:
				return invOp2(x, y, op)
			}
		case idealUint:
			switch y := b.(type) {
			case idealUint:
				return x != y, nil
			default:
				return invOp2(x, y, op)
			}
		case bool:
			switch y := b.(type) {
			case bool:
				return x != y, nil
			default:
				return invOp2(x, y, op)
			}
		case complex64:
			switch y := b.(type) {
			case complex64:
				return x != y, nil
			default:
				return invOp2(x, y, op)
			}
		case complex128:
			switch y := b.(type) {
			case complex128:
				return x != y, nil
			default:
				return invOp2(x, y, op)
			}
		case float32:
			switch y := b.(type) {
			case float32:
				return x != y, nil
			default:
				return invOp2(x, y, op)
			}
		case float64:
			switch y := b.(type) {
			case float64:
				return x != y, nil
			default:
				return invOp2(x, y, op)
			}
		case int8:
			switch y := b.(type) {
			case int8:
				return x != y, nil
			default:
				return invOp2(x, y, op)
			}
		case int16:
			switch y := b.(type) {
			case int16:
				return x != y, nil
			default:
				return invOp2(x, y, op)
			}
		case int32:
			switch y := b.(type) {
			case int32:
				return x != y, nil
			default:
				return invOp2(x, y, op)
			}
		case int64:
			switch y := b.(type) {
			case int64:
				return x != y, nil
			default:
				return invOp2(x, y, op)
			}
		case string:
			switch y := b.(type) {
			case string:
				return x != y, nil
			default:
				return invOp2(x, y, op)
			}
		case uint8:
			switch y := b.(type) {
			case uint8:
				return x != y, nil
			default:
				return invOp2(x, y, op)
			}
		case uint16:
			switch y := b.(type) {
			case uint16:
				return x != y, nil
			default:
				return invOp2(x, y, op)
			}
		case uint32:
			switch y := b.(type) {
			case uint32:
				return x != y, nil
			default:
				return invOp2(x, y, op)
			}
		case uint64:
			switch y := b.(type) {
			case uint64:
				return x != y, nil
			default:
				return invOp2(x, y, op)
			}
		case *big.Int:
			switch y := b.(type) {
			case *big.Int:
				return x.Cmp(y) != 0, nil
			default:
				return invOp2(x, y, op)
			}
		case *big.Rat:
			switch y := b.(type) {
			case *big.Rat:
				return x.Cmp(y) != 0, nil
			default:
				return invOp2(x, y, op)
			}
		case time.Duration:
			switch y := b.(type) {
			case time.Duration:
				return x != y, nil
			default:
				return invOp2(x, y, op)
			}
		case time.Time:
			switch y := b.(type) {
			case time.Time:
				return !x.Equal(y), nil
			default:
				return invOp2(x, y, op)
			}
		default:
			return invOp2(a, b, op)
		}
	case eq:
		a, b := o.get2(execCtx, ctx)
		if a == nil || b == nil {
			return
		}
		switch x := a.(type) {
		//case nil:
		case idealComplex:
			switch y := b.(type) {
			case idealComplex:
				return x == y, nil
			default:
				return invOp2(x, y, op)
			}
		case idealFloat:
			switch y := b.(type) {
			case idealFloat:
				return x == y, nil
			default:
				return invOp2(x, y, op)
			}
		case idealInt:
			switch y := b.(type) {
			case idealInt:
				return x == y, nil
			default:
				return invOp2(x, y, op)
			}
		case idealRune:
			switch y := b.(type) {
			case idealRune:
				return x == y, nil
			default:
				return invOp2(x, y, op)
			}
		case idealUint:
			switch y := b.(type) {
			case idealUint:
				return x == y, nil
			default:
				return invOp2(x, y, op)
			}
		case bool:
			switch y := b.(type) {
			case bool:
				return x == y, nil
			default:
				return invOp2(x, y, op)
			}
		case complex64:
			switch y := b.(type) {
			case complex64:
				return x == y, nil
			default:
				return invOp2(x, y, op)
			}
		case complex128:
			switch y := b.(type) {
			case complex128:
				return x == y, nil
			default:
				return invOp2(x, y, op)
			}
		case float32:
			switch y := b.(type) {
			case float32:
				return x == y, nil
			default:
				return invOp2(x, y, op)
			}
		case float64:
			switch y := b.(type) {
			case float64:
				return x == y, nil
			default:
				return invOp2(x, y, op)
			}
		case int8:
			switch y := b.(type) {
			case int8:
				return x == y, nil
			default:
				return invOp2(x, y, op)
			}
		case int16:
			switch y := b.(type) {
			case int16:
				return x == y, nil
			default:
				return invOp2(x, y, op)
			}
		case int32:
			switch y := b.(type) {
			case int32:
				return x == y, nil
			default:
				return invOp2(x, y, op)
			}
		case int64:
			switch y := b.(type) {
			case int64:
				return x == y, nil
			default:
				return invOp2(x, y, op)
			}
		case string:
			switch y := b.(type) {
			case string:
				return x == y, nil
			default:
				return invOp2(x, y, op)
			}
		case uint8:
			switch y := b.(type) {
			case uint8:
				return x == y, nil
			default:
				return invOp2(x, y, op)
			}
		case uint16:
			switch y := b.(type) {
			case uint16:
				return x == y, nil
			default:
				return invOp2(x, y, op)
			}
		case uint32:
			switch y := b.(type) {
			case uint32:
				return x == y, nil
			default:
				return invOp2(x, y, op)
			}
		case uint64:
			switch y := b.(type) {
			case uint64:
				return x == y, nil
			default:
				return invOp2(x, y, op)
			}
		case *big.Int:
			switch y := b.(type) {
			case *big.Int:
				return x.Cmp(y) == 0, nil
			default:
				return invOp2(x, y, op)
			}
		case *big.Rat:
			switch y := b.(type) {
			case *big.Rat:
				return x.Cmp(y) == 0, nil
			default:
				return invOp2(x, y, op)
			}
		case time.Duration:
			switch y := b.(type) {
			case time.Duration:
				return x == y, nil
			default:
				return invOp2(x, y, op)
			}
		case time.Time:
			switch y := b.(type) {
			case time.Time:
				return x.Equal(y), nil
			default:
				return invOp2(x, y, op)
			}
		default:
			return invOp2(a, b, op)
		}
	case '+':
		a, b := o.get2(execCtx, ctx)
		if a == nil || b == nil {
			return
		}
		switch x := a.(type) {
		//case nil:
		case idealComplex:
			switch y := b.(type) {
			case idealComplex:
				return idealComplex(complex64(x) + complex64(y)), nil
			default:
				return invOp2(x, y, op)
			}
		case idealFloat:
			switch y := b.(type) {
			case idealFloat:
				return idealFloat(float64(x) + float64(y)), nil
			default:
				return invOp2(x, y, op)
			}
		case idealInt:
			switch y := b.(type) {
			case idealInt:
				return idealInt(int64(x) + int64(y)), nil
			default:
				return invOp2(x, y, op)
			}
		case idealRune:
			switch y := b.(type) {
			case idealRune:
				return idealRune(int64(x) + int64(y)), nil
			default:
				return invOp2(x, y, op)
			}
		case idealUint:
			switch y := b.(type) {
			case idealUint:
				return idealUint(uint64(x) + uint64(y)), nil
			default:
				return invOp2(x, y, op)
			}
		case bool:
			return undOp2(a, b, op)
		case complex64:
			switch y := b.(type) {
			case complex64:
				return x + y, nil
			default:
				return invOp2(x, y, op)
			}
		case complex128:
			switch y := b.(type) {
			case complex128:
				return x + y, nil
			default:
				return invOp2(x, y, op)
			}
		case float32:
			switch y := b.(type) {
			case float32:
				return x + y, nil
			default:
				return invOp2(x, y, op)
			}
		case float64:
			switch y := b.(type) {
			case float64:
				return x + y, nil
			default:
				return invOp2(x, y, op)
			}
		case int8:
			switch y := b.(type) {
			case int8:
				return x + y, nil
			default:
				return invOp2(x, y, op)
			}
		case int16:
			switch y := b.(type) {
			case int16:
				return x + y, nil
			default:
				return invOp2(x, y, op)
			}
		case int32:
			switch y := b.(type) {
			case int32:
				return x + y, nil
			default:
				return invOp2(x, y, op)
			}
		case int64:
			switch y := b.(type) {
			case int64:
				return x + y, nil
			default:
				return invOp2(x, y, op)
			}
		case string:
			switch y := b.(type) {
			case string:
				return x + y, nil
			default:
				return invOp2(x, y, op)
			}
		case uint8:
			switch y := b.(type) {
			case uint8:
				return x + y, nil
			default:
				return invOp2(x, y, op)
			}
		case uint16:
			switch y := b.(type) {
			case uint16:
				return x + y, nil
			default:
				return invOp2(x, y, op)
			}
		case uint32:
			switch y := b.(type) {
			case uint32:
				return x + y, nil
			default:
				return invOp2(x, y, op)
			}
		case uint64:
			switch y := b.(type) {
			case uint64:
				return x + y, nil
			default:
				return invOp2(x, y, op)
			}
		case *big.Int:
			switch y := b.(type) {
			case *big.Int:
				var z big.Int
				return z.Add(x, y), nil
			default:
				return invOp2(x, y, op)
			}
		case *big.Rat:
			switch y := b.(type) {
			case *big.Rat:
				var z big.Rat
				return z.Add(x, y), nil
			default:
				return invOp2(x, y, op)
			}
		case time.Duration:
			switch y := b.(type) {
			case time.Duration:
				return x + y, nil
			case time.Time:
				return y.Add(x), nil
			default:
				return invOp2(x, y, op)
			}
		case time.Time:
			switch y := b.(type) {
			case time.Duration:
				return x.Add(y), nil
			default:
				return invOp2(x, y, op)
			}
		default:
			return invOp2(a, b, op)
		}
	case '-':
		a, b := o.get2(execCtx, ctx)
		if a == nil || b == nil {
			return
		}
		switch x := a.(type) {
		//case nil:
		case idealComplex:
			switch y := b.(type) {
			case idealComplex:
				return idealComplex(complex64(x) - complex64(y)), nil
			default:
				return invOp2(x, y, op)
			}
		case idealFloat:
			switch y := b.(type) {
			case idealFloat:
				return idealFloat(float64(x) - float64(y)), nil
			default:
				return invOp2(x, y, op)
			}
		case idealInt:
			switch y := b.(type) {
			case idealInt:
				return idealInt(int64(x) - int64(y)), nil
			default:
				return invOp2(x, y, op)
			}
		case idealRune:
			switch y := b.(type) {
			case idealRune:
				return idealRune(int64(x) - int64(y)), nil
			default:
				return invOp2(x, y, op)
			}
		case idealUint:
			switch y := b.(type) {
			case idealUint:
				return idealUint(uint64(x) - uint64(y)), nil
			default:
				return invOp2(x, y, op)
			}
		case bool:
			return undOp2(a, b, op)
		case complex64:
			switch y := b.(type) {
			case complex64:
				return x - y, nil
			default:
				return invOp2(x, y, op)
			}
		case complex128:
			switch y := b.(type) {
			case complex128:
				return x - y, nil
			default:
				return invOp2(x, y, op)
			}
		case float32:
			switch y := b.(type) {
			case float32:
				return x - y, nil
			default:
				return invOp2(x, y, op)
			}
		case float64:
			switch y := b.(type) {
			case float64:
				return x - y, nil
			default:
				return invOp2(x, y, op)
			}
		case int8:
			switch y := b.(type) {
			case int8:
				return x - y, nil
			default:
				return invOp2(x, y, op)
			}
		case int16:
			switch y := b.(type) {
			case int16:
				return x - y, nil
			default:
				return invOp2(x, y, op)
			}
		case int32:
			switch y := b.(type) {
			case int32:
				return x - y, nil
			default:
				return invOp2(x, y, op)
			}
		case int64:
			switch y := b.(type) {
			case int64:
				return x - y, nil
			default:
				return invOp2(x, y, op)
			}
		case string:
			return undOp2(a, b, op)
		case uint8:
			switch y := b.(type) {
			case uint8:
				return x - y, nil
			default:
				return invOp2(x, y, op)
			}
		case uint16:
			switch y := b.(type) {
			case uint16:
				return x - y, nil
			default:
				return invOp2(x, y, op)
			}
		case uint32:
			switch y := b.(type) {
			case uint32:
				return x - y, nil
			default:
				return invOp2(x, y, op)
			}
		case uint64:
			switch y := b.(type) {
			case uint64:
				return x - y, nil
			default:
				return invOp2(x, y, op)
			}
		case *big.Int:
			switch y := b.(type) {
			case *big.Int:
				var z big.Int
				return z.Sub(x, y), nil
			default:
				return invOp2(x, y, op)
			}
		case *big.Rat:
			switch y := b.(type) {
			case *big.Rat:
				var z big.Rat
				return z.Sub(x, y), nil
			default:
				return invOp2(x, y, op)
			}
		case time.Duration:
			switch y := b.(type) {
			case time.Duration:
				return x - y, nil
			default:
				return invOp2(x, y, op)
			}
		case time.Time:
			switch y := b.(type) {
			case time.Duration:
				return x.Add(-y), nil
			case time.Time:
				return x.Sub(y), nil
			default:
				return invOp2(x, y, op)
			}
		default:
			return invOp2(a, b, op)
		}
	case rsh:
		a, b := eval2(o.l, o.r, execCtx, ctx)
		if a == nil || b == nil {
			return
		}

		var cnt uint64
		switch y := b.(type) {
		//case nil:
		case idealComplex:
			return invShiftRHS(a, b)
		case idealFloat:
			return invShiftRHS(a, b)
		case idealInt:
			cnt = uint64(y)
		case idealRune:
			cnt = uint64(y)
		case idealUint:
			cnt = uint64(y)
		case bool:
			return invShiftRHS(a, b)
		case complex64:
			return invShiftRHS(a, b)
		case complex128:
			return invShiftRHS(a, b)
		case float32:
			return invShiftRHS(a, b)
		case float64:
			return invShiftRHS(a, b)
		case int8:
			return invShiftRHS(a, b)
		case int16:
			return invShiftRHS(a, b)
		case int32:
			return invShiftRHS(a, b)
		case int64:
			return invShiftRHS(a, b)
		case string:
			return invShiftRHS(a, b)
		case uint8:
			cnt = uint64(y)
		case uint16:
			cnt = uint64(y)
		case uint32:
			cnt = uint64(y)
		case uint64:
			cnt = uint64(y)
		default:
			return invOp2(a, b, op)
		}

		switch x := a.(type) {
		//case nil:
		case idealComplex:
			return undOp2(a, b, op)
		case idealFloat:
			return undOp2(a, b, op)
		case idealInt:
			return idealInt(int64(x) >> cnt), nil
		case idealRune:
			return idealRune(int64(x) >> cnt), nil
		case idealUint:
			return idealUint(uint64(x) >> cnt), nil
		case bool:
			return undOp2(a, b, op)
		case complex64:
			return undOp2(a, b, op)
		case complex128:
			return undOp2(a, b, op)
		case float32:
			return undOp2(a, b, op)
		case float64:
			return undOp2(a, b, op)
		case int8:
			return x >> cnt, nil
		case int16:
			return x >> cnt, nil
		case int32:
			return x >> cnt, nil
		case int64:
			return x >> cnt, nil
		case string:
			return undOp2(a, b, op)
		case uint8:
			return x >> cnt, nil
		case uint16:
			return x >> cnt, nil
		case uint32:
			return x >> cnt, nil
		case uint64:
			return x >> cnt, nil
		case *big.Int:
			var z big.Int
			return z.Rsh(x, uint(cnt)), nil
		case time.Duration:
			return x >> cnt, nil
		default:
			return invOp2(a, b, op)
		}
	case lsh:
		a, b := eval2(o.l, o.r, execCtx, ctx)
		if a == nil || b == nil {
			return
		}

		var cnt uint64
		switch y := b.(type) {
		//case nil:
		case idealComplex:
			return invShiftRHS(a, b)
		case idealFloat:
			return invShiftRHS(a, b)
		case idealInt:
			cnt = uint64(y)
		case idealRune:
			cnt = uint64(y)
		case idealUint:
			cnt = uint64(y)
		case bool:
			return invShiftRHS(a, b)
		case complex64:
			return invShiftRHS(a, b)
		case complex128:
			return invShiftRHS(a, b)
		case float32:
			return invShiftRHS(a, b)
		case float64:
			return invShiftRHS(a, b)
		case int8:
			return invShiftRHS(a, b)
		case int16:
			return invShiftRHS(a, b)
		case int32:
			return invShiftRHS(a, b)
		case int64:
			return invShiftRHS(a, b)
		case string:
			return invShiftRHS(a, b)
		case uint8:
			cnt = uint64(y)
		case uint16:
			cnt = uint64(y)
		case uint32:
			cnt = uint64(y)
		case uint64:
			cnt = uint64(y)
		default:
			return invOp2(a, b, op)
		}

		switch x := a.(type) {
		//case nil:
		case idealComplex:
			return undOp2(a, b, op)
		case idealFloat:
			return undOp2(a, b, op)
		case idealInt:
			return idealInt(int64(x) << cnt), nil
		case idealRune:
			return idealRune(int64(x) << cnt), nil
		case idealUint:
			return idealUint(uint64(x) << cnt), nil
		case bool:
			return undOp2(a, b, op)
		case complex64:
			return undOp2(a, b, op)
		case complex128:
			return undOp2(a, b, op)
		case float32:
			return undOp2(a, b, op)
		case float64:
			return undOp2(a, b, op)
		case int8:
			return x << cnt, nil
		case int16:
			return x << cnt, nil
		case int32:
			return x << cnt, nil
		case int64:
			return x << cnt, nil
		case string:
			return undOp2(a, b, op)
		case uint8:
			return x << cnt, nil
		case uint16:
			return x << cnt, nil
		case uint32:
			return x << cnt, nil
		case uint64:
			return x << cnt, nil
		case *big.Int:
			var z big.Int
			return z.Lsh(x, uint(cnt)), nil
		case time.Duration:
			return x << cnt, nil
		default:
			return invOp2(a, b, op)
		}
	case '&':
		a, b := o.get2(execCtx, ctx)
		if a == nil || b == nil {
			return
		}
		switch x := a.(type) {
		//case nil:
		case idealComplex:
			return undOp2(a, b, op)
		case idealFloat:
			return undOp2(a, b, op)
		case idealInt:
			switch y := b.(type) {
			case idealInt:
				return idealInt(int64(x) & int64(y)), nil
			default:
				return invOp2(x, y, op)
			}
		case idealRune:
			switch y := b.(type) {
			case idealRune:
				return idealRune(int64(x) & int64(y)), nil
			default:
				return invOp2(x, y, op)
			}
		case idealUint:
			switch y := b.(type) {
			case idealUint:
				return idealUint(uint64(x) & uint64(y)), nil
			default:
				return invOp2(x, y, op)
			}
		case bool:
			return undOp2(a, b, op)
		case complex64:
			return undOp2(a, b, op)
		case complex128:
			return undOp2(a, b, op)
		case float32:
			return undOp2(a, b, op)
		case float64:
			return undOp2(a, b, op)
		case int8:
			switch y := b.(type) {
			case int8:
				return x & y, nil
			default:
				return invOp2(x, y, op)
			}
		case int16:
			switch y := b.(type) {
			case int16:
				return x & y, nil
			default:
				return invOp2(x, y, op)
			}
		case int32:
			switch y := b.(type) {
			case int32:
				return x & y, nil
			default:
				return invOp2(x, y, op)
			}
		case int64:
			switch y := b.(type) {
			case int64:
				return x & y, nil
			default:
				return invOp2(x, y, op)
			}
		case string:
			return undOp2(a, b, op)
		case uint8:
			switch y := b.(type) {
			case uint8:
				return x & y, nil
			default:
				return invOp2(x, y, op)
			}
		case uint16:
			switch y := b.(type) {
			case uint16:
				return x & y, nil
			default:
				return invOp2(x, y, op)
			}
		case uint32:
			switch y := b.(type) {
			case uint32:
				return x & y, nil
			default:
				return invOp2(x, y, op)
			}
		case uint64:
			switch y := b.(type) {
			case uint64:
				return x & y, nil
			default:
				return invOp2(x, y, op)
			}
		case *big.Int:
			switch y := b.(type) {
			case *big.Int:
				var z big.Int
				return z.And(x, y), nil
			default:
				return invOp2(x, y, op)
			}
		case time.Duration:
			switch y := b.(type) {
			case time.Duration:
				return x & y, nil
			default:
				return invOp2(x, y, op)
			}
		default:
			return invOp2(a, b, op)
		}
	case '|':
		a, b := o.get2(execCtx, ctx)
		if a == nil || b == nil {
			return
		}
		switch x := a.(type) {
		//case nil:
		case idealComplex:
			return undOp2(a, b, op)
		case idealFloat:
			return undOp2(a, b, op)
		case idealInt:
			switch y := b.(type) {
			case idealInt:
				return idealInt(int64(x) | int64(y)), nil
			default:
				return invOp2(x, y, op)
			}
		case idealRune:
			switch y := b.(type) {
			case idealRune:
				return idealRune(int64(x) | int64(y)), nil
			default:
				return invOp2(x, y, op)
			}
		case idealUint:
			switch y := b.(type) {
			case idealUint:
				return idealUint(uint64(x) | uint64(y)), nil
			default:
				return invOp2(x, y, op)
			}
		case bool:
			return undOp2(a, b, op)
		case complex64:
			return undOp2(a, b, op)
		case complex128:
			return undOp2(a, b, op)
		case float32:
			return undOp2(a, b, op)
		case float64:
			return undOp2(a, b, op)
		case int8:
			switch y := b.(type) {
			case int8:
				return x | y, nil
			default:
				return invOp2(x, y, op)
			}
		case int16:
			switch y := b.(type) {
			case int16:
				return x | y, nil
			default:
				return invOp2(x, y, op)
			}
		case int32:
			switch y := b.(type) {
			case int32:
				return x | y, nil
			default:
				return invOp2(x, y, op)
			}
		case int64:
			switch y := b.(type) {
			case int64:
				return x | y, nil
			default:
				return invOp2(x, y, op)
			}
		case string:
			return undOp2(a, b, op)
		case uint8:
			switch y := b.(type) {
			case uint8:
				return x | y, nil
			default:
				return invOp2(x, y, op)
			}
		case uint16:
			switch y := b.(type) {
			case uint16:
				return x | y, nil
			default:
				return invOp2(x, y, op)
			}
		case uint32:
			switch y := b.(type) {
			case uint32:
				return x | y, nil
			default:
				return invOp2(x, y, op)
			}
		case uint64:
			switch y := b.(type) {
			case uint64:
				return x | y, nil
			default:
				return invOp2(x, y, op)
			}
		case *big.Int:
			switch y := b.(type) {
			case *big.Int:
				var z big.Int
				return z.Or(x, y), nil
			default:
				return invOp2(x, y, op)
			}
		case time.Duration:
			switch y := b.(type) {
			case time.Duration:
				return x | y, nil
			default:
				return invOp2(x, y, op)
			}
		default:
			return invOp2(a, b, op)
		}
	case andnot:
		a, b := o.get2(execCtx, ctx)
		if a == nil || b == nil {
			return
		}
		switch x := a.(type) {
		//case nil:
		case idealComplex:
			return undOp2(a, b, op)
		case idealFloat:
			return undOp2(a, b, op)
		case idealInt:
			switch y := b.(type) {
			case idealInt:
				return idealInt(int64(x) &^ int64(y)), nil
			default:
				return invOp2(x, y, op)
			}
		case idealRune:
			switch y := b.(type) {
			case idealRune:
				return idealRune(int64(x) &^ int64(y)), nil
			default:
				return invOp2(x, y, op)
			}
		case idealUint:
			switch y := b.(type) {
			case idealUint:
				return idealUint(uint64(x) &^ uint64(y)), nil
			default:
				return invOp2(x, y, op)
			}
		case bool:
			return undOp2(a, b, op)
		case complex64:
			return undOp2(a, b, op)
		case complex128:
			return undOp2(a, b, op)
		case float32:
			return undOp2(a, b, op)
		case float64:
			return undOp2(a, b, op)
		case int8:
			switch y := b.(type) {
			case int8:
				return x &^ y, nil
			default:
				return invOp2(x, y, op)
			}
		case int16:
			switch y := b.(type) {
			case int16:
				return x &^ y, nil
			default:
				return invOp2(x, y, op)
			}
		case int32:
			switch y := b.(type) {
			case int32:
				return x &^ y, nil
			default:
				return invOp2(x, y, op)
			}
		case int64:
			switch y := b.(type) {
			case int64:
				return x &^ y, nil
			default:
				return invOp2(x, y, op)
			}
		case string:
			return undOp2(a, b, op)
		case uint8:
			switch y := b.(type) {
			case uint8:
				return x &^ y, nil
			default:
				return invOp2(x, y, op)
			}
		case uint16:
			switch y := b.(type) {
			case uint16:
				return x &^ y, nil
			default:
				return invOp2(x, y, op)
			}
		case uint32:
			switch y := b.(type) {
			case uint32:
				return x &^ y, nil
			default:
				return invOp2(x, y, op)
			}
		case uint64:
			switch y := b.(type) {
			case uint64:
				return x &^ y, nil
			default:
				return invOp2(x, y, op)
			}
		case *big.Int:
			switch y := b.(type) {
			case *big.Int:
				var z big.Int
				return z.AndNot(x, y), nil
			default:
				return invOp2(x, y, op)
			}
		case time.Duration:
			switch y := b.(type) {
			case time.Duration:
				return x &^ y, nil
			default:
				return invOp2(x, y, op)
			}
		default:
			return invOp2(a, b, op)
		}
	case '^':
		a, b := o.get2(execCtx, ctx)
		if a == nil || b == nil {
			return
		}
		switch x := a.(type) {
		//case nil:
		case idealComplex:
			return undOp2(a, b, op)
		case idealFloat:
			return undOp2(a, b, op)
		case idealInt:
			switch y := b.(type) {
			case idealInt:
				return idealInt(int64(x) ^ int64(y)), nil
			default:
				return invOp2(x, y, op)
			}
		case idealRune:
			switch y := b.(type) {
			case idealRune:
				return idealRune(int64(x) ^ int64(y)), nil
			default:
				return invOp2(x, y, op)
			}
		case idealUint:
			switch y := b.(type) {
			case idealUint:
				return idealUint(uint64(x) ^ uint64(y)), nil
			default:
				return invOp2(x, y, op)
			}
		case bool:
			return undOp2(a, b, op)
		case complex64:
			return undOp2(a, b, op)
		case complex128:
			return undOp2(a, b, op)
		case float32:
			return undOp2(a, b, op)
		case float64:
			return undOp2(a, b, op)
		case int8:
			switch y := b.(type) {
			case int8:
				return x ^ y, nil
			default:
				return invOp2(x, y, op)
			}
		case int16:
			switch y := b.(type) {
			case int16:
				return x ^ y, nil
			default:
				return invOp2(x, y, op)
			}
		case int32:
			switch y := b.(type) {
			case int32:
				return x ^ y, nil
			default:
				return invOp2(x, y, op)
			}
		case int64:
			switch y := b.(type) {
			case int64:
				return x ^ y, nil
			default:
				return invOp2(x, y, op)
			}
		case string:
			return undOp2(a, b, op)
		case uint8:
			switch y := b.(type) {
			case uint8:
				return x ^ y, nil
			default:
				return invOp2(x, y, op)
			}
		case uint16:
			switch y := b.(type) {
			case uint16:
				return x ^ y, nil
			default:
				return invOp2(x, y, op)
			}
		case uint32:
			switch y := b.(type) {
			case uint32:
				return x ^ y, nil
			default:
				return invOp2(x, y, op)
			}
		case uint64:
			switch y := b.(type) {
			case uint64:
				return x ^ y, nil
			default:
				return invOp2(x, y, op)
			}
		case *big.Int:
			switch y := b.(type) {
			case *big.Int:
				var z big.Int
				return z.Xor(x, y), nil
			default:
				return invOp2(x, y, op)
			}
		case time.Duration:
			switch y := b.(type) {
			case time.Duration:
				return x ^ y, nil
			default:
				return invOp2(x, y, op)
			}
		default:
			return invOp2(a, b, op)
		}
	case '%':
		a, b := o.get2(execCtx, ctx)
		if a == nil || b == nil {
			return
		}
		switch x := a.(type) {
		//case nil:
		case idealComplex:
			return undOp2(a, b, op)
		case idealFloat:
			return undOp2(a, b, op)
		case idealInt:
			switch y := b.(type) {
			case idealInt:
				return idealInt(int64(x) % int64(y)), nil
			default:
				return invOp2(x, y, op)
			}
		case idealRune:
			switch y := b.(type) {
			case idealRune:
				return idealRune(int64(x) % int64(y)), nil
			default:
				return invOp2(x, y, op)
			}
		case idealUint:
			switch y := b.(type) {
			case idealUint:
				return idealUint(uint64(x) % uint64(y)), nil
			default:
				return invOp2(x, y, op)
			}
		case bool:
			return undOp2(a, b, op)
		case complex64:
			return undOp2(a, b, op)
		case complex128:
			return undOp2(a, b, op)
		case float32:
			return undOp2(a, b, op)
		case float64:
			return undOp2(a, b, op)
		case int8:
			switch y := b.(type) {
			case int8:
				return x % y, nil
			default:
				return invOp2(x, y, op)
			}
		case int16:
			switch y := b.(type) {
			case int16:
				return x % y, nil
			default:
				return invOp2(x, y, op)
			}
		case int32:
			switch y := b.(type) {
			case int32:
				return x % y, nil
			default:
				return invOp2(x, y, op)
			}
		case int64:
			switch y := b.(type) {
			case int64:
				return x % y, nil
			default:
				return invOp2(x, y, op)
			}
		case string:
			return undOp2(a, b, op)
		case uint8:
			switch y := b.(type) {
			case uint8:
				return x % y, nil
			default:
				return invOp2(x, y, op)
			}
		case uint16:
			switch y := b.(type) {
			case uint16:
				return x % y, nil
			default:
				return invOp2(x, y, op)
			}
		case uint32:
			switch y := b.(type) {
			case uint32:
				return x % y, nil
			default:
				return invOp2(x, y, op)
			}
		case uint64:
			switch y := b.(type) {
			case uint64:
				return x % y, nil
			default:
				return invOp2(x, y, op)
			}
		case *big.Int:
			switch y := b.(type) {
			case *big.Int:
				if y.Sign() == 0 {
					return nil, errDivByZero
				}

				var z big.Int
				return z.Mod(x, y), nil
			default:
				return invOp2(x, y, op)
			}
		case time.Duration:
			switch y := b.(type) {
			case time.Duration:
				return x % y, nil
			default:
				return invOp2(x, y, op)
			}
		default:
			return invOp2(a, b, op)
		}
	case '/':
		a, b := o.get2(execCtx, ctx)
		if a == nil || b == nil {
			return
		}
		switch x := a.(type) {
		//case nil:
		case idealComplex:
			switch y := b.(type) {
			case idealComplex:
				return idealComplex(complex64(x) / complex64(y)), nil
			default:
				return invOp2(x, y, op)
			}
		case idealFloat:
			switch y := b.(type) {
			case idealFloat:
				return idealFloat(float64(x) / float64(y)), nil
			default:
				return invOp2(x, y, op)
			}
		case idealInt:
			switch y := b.(type) {
			case idealInt:
				return idealInt(int64(x) / int64(y)), nil
			default:
				return invOp2(x, y, op)
			}
		case idealRune:
			switch y := b.(type) {
			case idealRune:
				return idealRune(int64(x) / int64(y)), nil
			default:
				return invOp2(x, y, op)
			}
		case idealUint:
			switch y := b.(type) {
			case idealUint:
				return idealUint(uint64(x) / uint64(y)), nil
			default:
				return invOp2(x, y, op)
			}
		case bool:
			return undOp2(a, b, op)
		case complex64:
			switch y := b.(type) {
			case complex64:
				return x / y, nil
			default:
				return invOp2(x, y, op)
			}
		case complex128:
			switch y := b.(type) {
			case complex128:
				return x / y, nil
			default:
				return invOp2(x, y, op)
			}
		case float32:
			switch y := b.(type) {
			case float32:
				return x / y, nil
			default:
				return invOp2(x, y, op)
			}
		case float64:
			switch y := b.(type) {
			case float64:
				return x / y, nil
			default:
				return invOp2(x, y, op)
			}
		case int8:
			switch y := b.(type) {
			case int8:
				return x / y, nil
			default:
				return invOp2(x, y, op)
			}
		case int16:
			switch y := b.(type) {
			case int16:
				return x / y, nil
			default:
				return invOp2(x, y, op)
			}
		case int32:
			switch y := b.(type) {
			case int32:
				return x / y, nil
			default:
				return invOp2(x, y, op)
			}
		case int64:
			switch y := b.(type) {
			case int64:
				return x / y, nil
			default:
				return invOp2(x, y, op)
			}
		case string:
			return undOp2(a, b, op)
		case uint8:
			switch y := b.(type) {
			case uint8:
				return x / y, nil
			default:
				return invOp2(x, y, op)
			}
		case uint16:
			switch y := b.(type) {
			case uint16:
				return x / y, nil
			default:
				return invOp2(x, y, op)
			}
		case uint32:
			switch y := b.(type) {
			case uint32:
				return x / y, nil
			default:
				return invOp2(x, y, op)
			}
		case uint64:
			switch y := b.(type) {
			case uint64:
				return x / y, nil
			default:
				return invOp2(x, y, op)
			}
		case *big.Int:
			switch y := b.(type) {
			case *big.Int:
				if y.Sign() == 0 {
					return nil, errDivByZero
				}

				var z big.Int
				return z.Quo(x, y), nil
			default:
				return invOp2(x, y, op)
			}
		case *big.Rat:
			switch y := b.(type) {
			case *big.Rat:
				if y.Sign() == 0 {
					return nil, errDivByZero
				}

				var z big.Rat
				return z.Quo(x, y), nil
			default:
				return invOp2(x, y, op)
			}
		case time.Duration:
			switch y := b.(type) {
			case time.Duration:
				return x / y, nil
			default:
				return invOp2(x, y, op)
			}
		default:
			return invOp2(a, b, op)
		}
	case '*':
		a, b := o.get2(execCtx, ctx)
		if a == nil || b == nil {
			return
		}
		switch x := a.(type) {
		//case nil:
		case idealComplex:
			switch y := b.(type) {
			case idealComplex:
				return idealComplex(complex64(x) * complex64(y)), nil
			default:
				return invOp2(x, y, op)
			}
		case idealFloat:
			switch y := b.(type) {
			case idealFloat:
				return idealFloat(float64(x) * float64(y)), nil
			default:
				return invOp2(x, y, op)
			}
		case idealInt:
			switch y := b.(type) {
			case idealInt:
				return idealInt(int64(x) * int64(y)), nil
			default:
				return invOp2(x, y, op)
			}
		case idealRune:
			switch y := b.(type) {
			case idealRune:
				return idealRune(int64(x) * int64(y)), nil
			default:
				return invOp2(x, y, op)
			}
		case idealUint:
			switch y := b.(type) {
			case idealUint:
				return idealUint(uint64(x) * uint64(y)), nil
			default:
				return invOp2(x, y, op)
			}
		case bool:
			return undOp2(a, b, op)
		case complex64:
			switch y := b.(type) {
			case complex64:
				return x * y, nil
			default:
				return invOp2(x, y, op)
			}
		case complex128:
			switch y := b.(type) {
			case complex128:
				return x * y, nil
			default:
				return invOp2(x, y, op)
			}
		case float32:
			switch y := b.(type) {
			case float32:
				return x * y, nil
			default:
				return invOp2(x, y, op)
			}
		case float64:
			switch y := b.(type) {
			case float64:
				return x * y, nil
			default:
				return invOp2(x, y, op)
			}
		case int8:
			switch y := b.(type) {
			case int8:
				return x * y, nil
			default:
				return invOp2(x, y, op)
			}
		case int16:
			switch y := b.(type) {
			case int16:
				return x * y, nil
			default:
				return invOp2(x, y, op)
			}
		case int32:
			switch y := b.(type) {
			case int32:
				return x * y, nil
			default:
				return invOp2(x, y, op)
			}
		case int64:
			switch y := b.(type) {
			case int64:
				return x * y, nil
			default:
				return invOp2(x, y, op)
			}
		case string:
			return undOp2(a, b, op)
		case uint8:
			switch y := b.(type) {
			case uint8:
				return x * y, nil
			default:
				return invOp2(x, y, op)
			}
		case uint16:
			switch y := b.(type) {
			case uint16:
				return x * y, nil
			default:
				return invOp2(x, y, op)
			}
		case uint32:
			switch y := b.(type) {
			case uint32:
				return x * y, nil
			default:
				return invOp2(x, y, op)
			}
		case uint64:
			switch y := b.(type) {
			case uint64:
				return x * y, nil
			default:
				return invOp2(x, y, op)
			}
		case *big.Int:
			switch y := b.(type) {
			case *big.Int:
				var z big.Int
				return z.Mul(x, y), nil
			default:
				return invOp2(x, y, op)
			}
		case *big.Rat:
			switch y := b.(type) {
			case *big.Rat:
				var z big.Rat
				return z.Mul(x, y), nil
			default:
				return invOp2(x, y, op)
			}
		case time.Duration:
			switch y := b.(type) {
			case time.Duration:
				return x * y, nil
			default:
				return invOp2(x, y, op)
			}
		default:
			return invOp2(a, b, op)
		}
	default:
		panic("internal error 037")
	}
}

func (o *binaryOperation) get2(execCtx *execCtx, ctx map[interface{}]interface{}) (x, y interface{}) {
	x, y = eval2(o.l, o.r, execCtx, ctx)
	//dbg("get2 pIn     - ", x, y)
	//defer func() {dbg("get2 coerced ", x, y)}()
	return coerce(x, y)
}

type ident struct {
	s string
}

func (i *ident) clone(arg []interface{}, unqualify ...string) (expression, error) {
	x := strings.IndexByte(i.s, '.')
	if x < 0 {
		return &ident{s: i.s}, nil
	}

	q := i.s[:x]
	for _, v := range unqualify {
		if q == v {
			return &ident{i.s[x+1:]}, nil
		}
	}
	return &ident{s: i.s}, nil
}

func (i *ident) isQualified() bool { return strings.Contains(i.s, ".") }

func (i *ident) isStatic() bool { return false }

func (i *ident) String() string { return i.s }

func (i *ident) eval(execCtx *execCtx, ctx map[interface{}]interface{}) (v interface{}, err error) {
	if _, ok := ctx["$agg0"]; ok {
		return int64(0), nil
	}

	//defer func() { dbg("ident %q -> %v %v", i.s, v, err) }()
	v, ok := ctx[i.s]
	if !ok {
		err = fmt.Errorf("unknown field %s", i.s)
	}
	return
}

type pInEval struct {
	m      map[interface{}]struct{} // IN (SELECT...) results
	sample interface{}
}

type pIn struct {
	expr expression
	list []expression
	not  bool
	sel  *selectStmt
}

func (n *pIn) clone(arg []interface{}, unqualify ...string) (expression, error) {
	expr, err := n.expr.clone(arg, unqualify...)
	if err != nil {
		return nil, err
	}

	list, err := cloneExpressionList(arg, n.list)
	if err != nil {
		return nil, err
	}

	return &pIn{
		expr: expr,
		list: list,
		not:  n.not,
		sel:  n.sel,
	}, nil
}

func (n *pIn) isStatic() bool {
	if !n.expr.isStatic() || n.sel != nil {
		return false
	}

	for _, v := range n.list {
		if !v.isStatic() {
			return false
		}
	}
	return true
}

//LATER newIn

func (n *pIn) String() string {
	if n.sel == nil {
		a := []string{}
		for _, v := range n.list {
			a = append(a, v.String())
		}
		if n.not {
			return fmt.Sprintf("%s NOT IN (%s)", n.expr, strings.Join(a, ","))
		}

		return fmt.Sprintf("%s IN (%s)", n.expr, strings.Join(a, ","))
	}

	if n.not {
		return fmt.Sprintf("%s NOT IN (%s)", n.expr, n.sel)
	}

	return fmt.Sprintf("%s IN (%s)", n.expr, n.sel)
}

func (n *pIn) eval(execCtx *execCtx, ctx map[interface{}]interface{}) (v interface{}, err error) {
	lhs, err := expand1(n.expr.eval(execCtx, ctx))
	if err != nil {
		return nil, err
	}

	if lhs == nil {
		return nil, nil //TODO Add test for NULL LHS.
	}

	if n.sel == nil {
		for _, v := range n.list {
			b, err := newBinaryOperation(eq, value{lhs}, v)
			if err != nil {
				return nil, err
			}

			eval, err := b.eval(execCtx, ctx)
			if err != nil {
				return nil, err
			}

			if x, ok := eval.(bool); ok && x {
				return !n.not, nil
			}
		}
		return n.not, nil
	}

	var ev *pInEval
	ev0 := ctx[n]
	if ev0 == nil { // SELECT not yet evaluated.
		r, err := n.sel.plan(execCtx)
		if err != nil {
			return nil, err
		}

		if g, e := len(r.fieldNames()), 1; g != e {
			return false, fmt.Errorf("IN (%s): mismatched field count, have %d, need %d", n.sel, g, e)
		}

		ev = &pInEval{m: map[interface{}]struct{}{}}
		ctx[n] = ev
		m := ev.m
		typechecked := false
		if err := r.do(execCtx, func(id interface{}, data []interface{}) (more bool, err error) {
			if typechecked {
				if data[0] == nil {
					return true, nil
				}

				m[data[0]] = struct{}{}
			}

			if data[0] == nil {
				return true, nil
			}

			ev.sample = data[0]
			switch ev.sample.(type) {
			case bool, byte, complex128, complex64, float32,
				float64, int16, int32, int64, int8,
				string, uint16, uint32, uint64:
				typechecked = true
				m[ev.sample] = struct{}{}
				return true, nil
			default:
				return false, fmt.Errorf("IN (%s): invalid field type: %T", n.sel, data[0])
			}

		}); err != nil {
			return nil, err
		}
	} else {
		ev = ev0.(*pInEval)
	}

	if ev.sample == nil {
		return nil, nil
	}

	_, ok := ev.m[coerce1(lhs, ev.sample)]
	return ok != n.not, nil
}

type value struct {
	val interface{}
}

func (l value) clone(arg []interface{}, unqualify ...string) (expression, error) {
	return value{val: l.val}, nil
}

func (l value) isStatic() bool { return true }

func (l value) String() string {
	switch x := l.val.(type) {
	case nil:
		return "NULL"
	case idealComplex:
		s := fmt.Sprint(x)
		return s[1 : len(s)-1]
	case complex64:
		s := fmt.Sprint(x)
		return s[1 : len(s)-1]
	case complex128:
		s := fmt.Sprint(x)
		return s[1 : len(s)-1]
	case string:
		return fmt.Sprintf("%q", x)
	case time.Duration:
		return fmt.Sprintf("duration(%q)", l.val)
	case time.Time:
		y, m, d := x.Date()
		zone, _ := x.Zone()
		return fmt.Sprintf("date(%v, %v, %v, %v, %v, %v, %v, %v)", y, m, d, x.Hour(), x.Minute(), x.Second(), x.Nanosecond(), zone)
	case *big.Rat:
		return fmt.Sprintf("bigrat(%q)", l.val)
	case *big.Int:
		return fmt.Sprintf(`bigint("%v")`, l.val)
	default:
		return fmt.Sprintf("%v", l.val)
	}
}

func (l value) eval(execCtx *execCtx, ctx map[interface{}]interface{}) (interface{}, error) {
	return l.val, nil
}

type conversion struct {
	typ int
	val expression
}

func (c *conversion) clone(arg []interface{}, unqualify ...string) (expression, error) {
	val, err := c.val.clone(arg, unqualify...)
	if err != nil {
		return nil, err
	}

	return &conversion{typ: c.typ, val: val}, nil
}

func (c *conversion) isStatic() bool {
	return c.val.isStatic()
}

//LATER newConversion or fake unary op

func (c *conversion) String() string {
	return fmt.Sprintf("%s(%s)", typeStr(c.typ), c.val)
}

func (c *conversion) eval(execCtx *execCtx, ctx map[interface{}]interface{}) (v interface{}, err error) {
	val, err := expand1(c.val.eval(execCtx, ctx))
	if err != nil {
		return
	}

	return convert(val, c.typ)
}

type unaryOperation struct {
	op int
	v  expression
}

func newUnaryOperation(op int, x interface{}) (v expression, err error) {
	l, ok := x.(expression)
	if !ok {
		panic("internal error 038")
	}

	for {
		pe, ok := l.(*pexpr)
		if ok {
			l = pe.expr
			continue
		}

		break
	}

	if l.isStatic() {
		val, err := l.eval(nil, nil)
		if err != nil {
			return nil, err
		}

		l = value{val}
	}

	if op == '!' {
		b, ok := l.(*binaryOperation)
		if ok {
			switch b.op {
			case eq:
				b.op = neq
				return b, nil
			case neq:
				b.op = eq
				return b, nil
			case '>':
				b.op = le
				return b, nil
			case ge:
				b.op = '<'
				return b, nil
			case '<':
				b.op = ge
				return b, nil
			case le:
				b.op = '>'
				return b, nil
			}
		}

		u, ok := l.(*unaryOperation)
		if ok && u.op == '!' { // !!x: x
			return u.v, nil
		}
	}

	return &unaryOperation{op, l}, nil
}

func (u *unaryOperation) clone(arg []interface{}, unqualify ...string) (expression, error) {
	v, err := u.v.clone(arg, unqualify...)
	if err != nil {
		return nil, err
	}

	return &unaryOperation{op: u.op, v: v}, nil
}

func (u *unaryOperation) isStatic() bool { return u.v.isStatic() }

func (u *unaryOperation) String() string {
	switch u.v.(type) {
	case *binaryOperation:
		return fmt.Sprintf("%s(%s)", iop(u.op), u.v)
	default:
		return fmt.Sprintf("%s%s", iop(u.op), u.v)
	}
}

func (u *unaryOperation) eval(execCtx *execCtx, ctx map[interface{}]interface{}) (r interface{}, err error) {
	defer func() {
		if e := recover(); e != nil {
			switch x := e.(type) {
			case error:
				r, err = nil, x
			default:
				r, err = nil, fmt.Errorf("%v", x)
			}
		}
	}()

	switch op := u.op; op {
	case '!':
		a := eval(u.v, execCtx, ctx)
		if a == nil {
			return
		}

		switch x := a.(type) {
		case bool:
			return !x, nil
		default:
			return undOp(a, op)
		}
	case '^':
		a := eval(u.v, execCtx, ctx)
		if a == nil {
			return
		}

		switch x := a.(type) {
		//case nil:
		case idealComplex:
			return undOp(a, op)
		case idealFloat:
			return undOp(a, op)
		case idealInt:
			return ^x, nil
		case idealRune:
			return ^x, nil
		case idealUint:
			return ^x, nil
		case bool:
			return undOp(a, op)
		case complex64:
			return undOp(a, op)
		case complex128:
			return undOp(a, op)
		case float32:
			return undOp(a, op)
		case float64:
			return undOp(a, op)
		case int8:
			return ^x, nil
		case int16:
			return ^x, nil
		case int32:
			return ^x, nil
		case int64:
			return ^x, nil
		case string:
			return undOp(a, op)
		case uint8:
			return ^x, nil
		case uint16:
			return ^x, nil
		case uint32:
			return ^x, nil
		case uint64:
			return ^x, nil
		case *big.Int:
			var z big.Int
			return z.Not(x), nil
		case time.Duration:
			return ^x, nil
		default:
			return undOp(a, op)
		}
	case '+':
		a := eval(u.v, execCtx, ctx)
		if a == nil {
			return
		}

		switch x := a.(type) {
		//case nil:
		case idealComplex:
			return +x, nil
		case idealFloat:
			return +x, nil
		case idealInt:
			return +x, nil
		case idealRune:
			return +x, nil
		case idealUint:
			return +x, nil
		case bool:
			return undOp(a, op)
		case complex64:
			return +x, nil
		case complex128:
			return +x, nil
		case float32:
			return +x, nil
		case float64:
			return +x, nil
		case int8:
			return +x, nil
		case int16:
			return +x, nil
		case int32:
			return +x, nil
		case int64:
			return +x, nil
		case string:
			return undOp(a, op)
		case uint8:
			return +x, nil
		case uint16:
			return +x, nil
		case uint32:
			return +x, nil
		case uint64:
			return +x, nil
		case *big.Int:
			var z big.Int
			return z.Set(x), nil
		case *big.Rat:
			var z big.Rat
			return z.Set(x), nil
		case time.Duration:
			return x, nil
		default:
			return undOp(a, op)
		}
	case '-':
		a := eval(u.v, execCtx, ctx)
		if a == nil {
			return
		}

		switch x := a.(type) {
		//case nil:
		case idealComplex:
			return -x, nil
		case idealFloat:
			return -x, nil
		case idealInt:
			return -x, nil
		case idealRune:
			return -x, nil
		case idealUint:
			return -x, nil
		case bool:
			return undOp(a, op)
		case complex64:
			return -x, nil
		case complex128:
			return -x, nil
		case float32:
			return -x, nil
		case float64:
			return -x, nil
		case int8:
			return -x, nil
		case int16:
			return -x, nil
		case int32:
			return -x, nil
		case int64:
			return -x, nil
		case string:
			return undOp(a, op)
		case uint8:
			return -x, nil
		case uint16:
			return -x, nil
		case uint32:
			return -x, nil
		case uint64:
			return -x, nil
		case *big.Int:
			var z big.Int
			return z.Neg(x), nil
		case *big.Rat:
			var z big.Rat
			return z.Neg(x), nil
		case time.Duration:
			return -x, nil
		default:
			return undOp(a, op)
		}
	default:
		panic("internal error 039")
	}
}

type call struct {
	f   string
	arg []expression
}

func newCall(f string, arg []expression) (v expression, isAgg bool, err error) {
	x := builtin[f]
	if x.f == nil {
		return nil, false, fmt.Errorf("undefined: %s", f)
	}

	isAgg = x.isAggregate
	if g, min, max := len(arg), x.minArgs, x.maxArgs; g < min || g > max {
		a := []interface{}{}
		for _, v := range arg {
			a = append(a, v)
		}
		return nil, false, badNArgs(min, f, a)
	}

	c := call{f: f}
	for _, val := range arg {
		if !val.isStatic() {
			c.arg = append(c.arg, val)
			continue
		}

		eval, err := val.eval(nil, nil)
		if err != nil {
			return nil, isAgg, err
		}

		c.arg = append(c.arg, value{eval})
	}

	return &c, isAgg, nil
}

func (c *call) clone(arg []interface{}, unqualify ...string) (expression, error) {
	list, err := cloneExpressionList(arg, c.arg)
	if err != nil {
		return nil, err
	}

	return &call{f: c.f, arg: list}, nil
}

func (c *call) isStatic() bool {
	v := builtin[c.f]
	if v.f == nil || !v.isStatic {
		return false
	}

	for _, v := range c.arg {
		if !v.isStatic() {
			return false
		}
	}
	return true
}

func (c *call) String() string {
	a := []string{}
	for _, v := range c.arg {
		a = append(a, v.String())
	}
	return fmt.Sprintf("%s(%s)", c.f, strings.Join(a, ", "))
}

func (c *call) eval(execCtx *execCtx, ctx map[interface{}]interface{}) (v interface{}, err error) {
	f, ok := builtin[c.f]
	if !ok {
		return nil, fmt.Errorf("unknown function %s", c.f)
	}

	isID := c.f == "id"
	a := make([]interface{}, len(c.arg))
	for i, arg := range c.arg {
		if v, err = expand1(arg.eval(execCtx, ctx)); err != nil {
			if !isID {
				return nil, err
			}

			if _, ok := arg.(*ident); !ok {
				return nil, err
			}

			a[i] = arg
			continue
		}

		a[i] = v
	}

	if ctx != nil {
		ctx["$fn"] = c
	}
	return f.f(a, ctx)
}

type parameter struct {
	n int
}

func (p parameter) clone(arg []interface{}, unqualify ...string) (expression, error) {
	i := p.n - 1
	if i < len(arg) {
		return value{val: arg[i]}, nil
	}

	return nil, fmt.Errorf("missing %s", p)
}

func (parameter) isStatic() bool { return false }

func (p parameter) String() string { return fmt.Sprintf("$%d", p.n) }

func (p parameter) eval(execCtx *execCtx, ctx map[interface{}]interface{}) (v interface{}, err error) {
	i := p.n - 1
	if i < len(execCtx.arg) {
		return execCtx.arg[i], nil
	}

	return nil, fmt.Errorf("missing %s", p)
}

//MAYBE make it an unary operation
type isNull struct {
	expr expression
	not  bool
}

//LATER newIsNull

func (is *isNull) clone(arg []interface{}, unqualify ...string) (expression, error) {
	expr, err := is.expr.clone(arg, unqualify...)
	if err != nil {
		return nil, err
	}

	return &isNull{expr: expr, not: is.not}, nil
}

func (is *isNull) isStatic() bool { return is.expr.isStatic() }

func (is *isNull) String() string {
	if is.not {
		return fmt.Sprintf("%s IS NOT NULL", is.expr)
	}

	return fmt.Sprintf("%s IS NULL", is.expr)
}

func (is *isNull) eval(execCtx *execCtx, ctx map[interface{}]interface{}) (v interface{}, err error) {
	val, err := is.expr.eval(execCtx, ctx)
	if err != nil {
		return
	}

	return val == nil != is.not, nil
}

type indexOp struct {
	expr, x expression
}

func newIndex(sv, xv expression) (v expression, err error) {
	s, fs, i := "", false, uint64(0)
	x := indexOp{sv, xv}
	if x.expr.isStatic() {
		v, err := x.expr.eval(nil, nil)
		if err != nil {
			return nil, err
		}

		if v == nil {
			return value{nil}, nil
		}

		if s, fs = v.(string); !fs {
			return nil, invXOp(sv, xv)
		}

		x.expr = value{s}
	}

	if x.x.isStatic() {
		v, err := x.x.eval(nil, nil)
		if err != nil {
			return nil, err
		}

		if v == nil {
			return value{nil}, nil
		}

		var p *string
		if fs {
			p = &s
		}
		if i, err = indexExpr(p, v); err != nil {
			return nil, err
		}

		x.x = value{i}
	}

	return &x, nil
}

func (x *indexOp) clone(arg []interface{}, unqualify ...string) (expression, error) {
	expr, err := x.expr.clone(arg, unqualify...)
	if err != nil {
		return nil, err
	}

	x2, err := x.x.clone(arg, unqualify...)
	if err != nil {
		return nil, err
	}

	return &indexOp{expr: expr, x: x2}, nil
}

func (x *indexOp) isStatic() bool {
	return x.expr.isStatic() && x.x.isStatic()
}

func (x *indexOp) String() string { return fmt.Sprintf("%s[%s]", x.expr, x.x) }

func (x *indexOp) eval(execCtx *execCtx, ctx map[interface{}]interface{}) (v interface{}, err error) {
	s0, err := x.expr.eval(execCtx, ctx)
	if err != nil {
		return nil, runErr(err)
	}

	s, ok := s0.(string)
	if !ok {
		return nil, runErr(invXOp(s0, x.x))
	}

	i0, err := x.x.eval(execCtx, ctx)
	if err != nil {
		return nil, runErr(err)
	}

	if i0 == nil {
		return nil, nil
	}

	i, err := indexExpr(&s, i0)
	if err != nil {
		return nil, runErr(err)
	}

	return s[i], nil
}

type slice struct {
	expr   expression
	lo, hi *expression
}

func newSlice(e expression, lo, hi *expression) (v expression, err error) {
	y := slice{e, lo, hi}
	var val interface{}
	if e := y.expr; e.isStatic() {
		if val, err = e.eval(nil, nil); err != nil {
			return nil, err
		}

		if val == nil {
			return value{nil}, nil
		}

		y.expr = value{val}
	}

	if p := y.lo; p != nil {
		if e := expr(*p); e.isStatic() {
			if val, err = e.eval(nil, nil); err != nil {
				return nil, err
			}

			if val == nil {
				return value{nil}, nil
			}

			v := expression(value{val})
			y.lo = &v
		}
	}

	if p := y.hi; p != nil {
		if e := expr(*p); e.isStatic() {
			if val, err = e.eval(nil, nil); err != nil {
				return nil, err
			}

			if val == nil {
				return value{nil}, nil
			}

			v := expression(value{val})
			y.hi = &v
		}
	}
	return &y, nil
}

func (s *slice) clone(arg []interface{}, unqualify ...string) (expression, error) {
	expr, err := s.expr.clone(arg, unqualify...)
	if err != nil {
		return nil, err
	}

	r := &slice{expr: expr, lo: s.lo, hi: s.hi}
	if s.lo != nil {
		e, err := (*s.lo).clone(arg, unqualify...)
		if err != nil {
			return nil, err
		}

		r.lo = &e
	}
	if s.hi != nil {
		e, err := (*s.hi).clone(arg, unqualify...)
		if err != nil {
			return nil, err
		}

		r.hi = &e
	}
	return r, nil
}

func (s *slice) eval(execCtx *execCtx, ctx map[interface{}]interface{}) (v interface{}, err error) {
	s0, err := s.expr.eval(execCtx, ctx)
	if err != nil {
		return
	}

	if s0 == nil {
		return
	}

	ss, ok := s0.(string)
	if !ok {
		return nil, runErr(invSOp(s0))
	}

	var iLo, iHi uint64
	if s.lo != nil {
		i, err := (*s.lo).eval(execCtx, ctx)
		if err != nil {
			return nil, err
		}

		if i == nil {
			return nil, err
		}

		if iLo, err = sliceExpr(&ss, i, 0); err != nil {
			return nil, err
		}
	}

	iHi = uint64(len(ss))
	if s.hi != nil {
		i, err := (*s.hi).eval(execCtx, ctx)
		if err != nil {
			return nil, err
		}

		if i == nil {
			return nil, err
		}

		if iHi, err = sliceExpr(&ss, i, 1); err != nil {
			return nil, err
		}
	}

	return ss[iLo:iHi], nil
}

func (s *slice) isStatic() bool {
	if !s.expr.isStatic() {
		return false
	}

	if p := s.lo; p != nil && !(*p).isStatic() {
		return false
	}

	if p := s.hi; p != nil && !(*p).isStatic() {
		return false
	}

	return false
}

func (s *slice) String() string {
	switch {
	case s.lo == nil && s.hi == nil:
		return fmt.Sprintf("%v[:]", s.expr)
	case s.lo == nil && s.hi != nil:
		return fmt.Sprintf("%v[:%v]", s.expr, *s.hi)
	case s.lo != nil && s.hi == nil:
		return fmt.Sprintf("%v[%v:]", s.expr, *s.lo)
	default: //case s.lo != nil && s.hi != nil:
		return fmt.Sprintf("%v[%v:%v]", s.expr, *s.lo, *s.hi)
	}
}
