func isAddressable(expr Expr) bool {
	expr = skipSuperfluousParens(expr)
	switch n := expr.(type) {
	case *Ident:
		return n.source == envVar
	case *StarExpr:
		return true
	case *IndexExpr:
		x := n.X
		t := x.KnownType()[0]
		switch t.Kind() {
		case reflect.Slice:
			return true
		case reflect.Array:
			return isAddressable(x)
		case reflect.Ptr:
			return true
		}
	case *SelectorExpr:
		if n.pkgName != "" {
			return isAddressable(n.Sel)
		}
		x := n.X
		t := x.KnownType()[0]
		switch t.Kind() {
		case reflect.Struct:
			return isAddressable(x)
		case reflect.Ptr:
			return true
		}
	}
	return false
}
spec: addressable, that is, either a
variable,
pointer indirection,
or slice indexing operation;
or a field selector of an addressable struct operand;
or an array indexing operation of an addressable array.
As an exception to the addressability requirement, x may also be a (possibly parenthesized) composite literal
package eval
import (
	"reflect"
	"regexp"
	"strconv"
	"strings"
	"go/ast"
	"go/token"
)
func hackedNew(t reflect.Type) reflect.Value {
	return reflect.New(unhackType(t))
}
func unhackType(t reflect.Type) reflect.Type {
	switch tt := t.(type) {
	case Rune:
		return tt.Type
	case Byte:
		return tt.Type
	default:
		return t
	}
}
func typeAssignableTo(from, to reflect.Type) bool {
	return from.AssignableTo(unhackType(to))
}
func checkExprAssignableTo(expr ast.Expr, t reflect.Type, env Env) (Expr, bool, []error) {
	var errs []error
	aexpr, moreErrs := CheckExpr(expr, env)
	if moreErrs != nil {
		errs = append(errs, moreErrs...)
	} else if _, err := expectSingleType(aexpr); err != nil {
		errs = append(errs, err)
	}
	if errs != nil {
		return aexpr, true, errs
	}
	ok, convErrs := exprAssignableTo(aexpr, t)
	if convErrs != nil {
		errs = append(errs, convErrs...)
	}
	return aexpr, ok, errs
}
func exprAssignableTo(from Expr, to reflect.Type) (bool, []error) {
	if len(from.KnownType()) != 1 {
		panic("go-eval: assignableTo called with from.KnownType() != 1")
	}
	fromType := from.KnownType()[0]
	if c, ok := fromType.(ConstType); ok && from.IsConst() {
		cv, errs := promoteConstToTyped(c, constValue(from.Const()), to, from)
		return reflect.Value(cv).IsValid(), errs
	}
	return typeAssignableTo(fromType, to), nil
}
func expectSingleType(expr Expr) (reflect.Type, error) {
	types := expr.KnownType()
	if len(types) == 0 {
		return nil, ErrMissingValue{expr}
	} else if multivalueOk(expr) {
		return types[0], nil
	} else if len(types) != 1 {
		return nil, ErrMultiInSingleContext{expr}
	} else {
		return types[0], nil
	}
}
func isBooleanOp(op token.Token) bool {
	switch op {
	case token.EQL, token.NEQ, token.LEQ, token.GEQ, token.LSS, token.GTR:
		return true
	default:
		return false
	}
}
func isOpDefinedOn(op token.Token, t reflect.Type) bool {
	if _, ok := t.(ConstNilType); ok {
		return false
	}
	switch t.Kind() {
	case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64,
		reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64:
		switch op {
		case token.ADD, token.SUB, token.MUL, token.QUO,
			token.REM, token.AND, token.OR, token.XOR, token.AND_NOT,
			token.EQL, token.NEQ,
			token.LEQ, token.GEQ, token.LSS, token.GTR:
			return true
		}
	case reflect.Float32, reflect.Float64:
		switch op {
		case token.ADD, token.SUB, token.MUL, token.QUO,
			token.EQL, token.NEQ,
			token.LEQ, token.GEQ, token.LSS, token.GTR:
			return true
		}
	case reflect.Complex64, reflect.Complex128:
		switch op {
		case token.ADD, token.SUB, token.MUL, token.QUO,
			token.EQL, token.NEQ:
			return true
		}
	case reflect.Bool:
		switch op {
		case token.LAND, token.LOR, token.EQL, token.NEQ:
			return true
		}
	case reflect.String:
		switch op {
		case token.ADD, token.EQL, token.NEQ, token.LEQ, token.GEQ, token.LSS, token.GTR:
			return true
		}
	case reflect.Ptr, reflect.Array, reflect.Interface, reflect.Struct,
		reflect.Slice, reflect.Map, reflect.Chan:
		return op == token.EQL || op == token.NEQ
	}
	return false
}
func isUnaryOpDefinedOn(op token.Token, t reflect.Type) bool {
	if _, ok := t.(ConstNilType); ok {
		return false
	}
	switch t.Kind() {
	case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64,
		reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64:
		switch op {
		case token.ADD, token.SUB, token.XOR:
			return true
		}
	case reflect.Float32, reflect.Float64, reflect.Complex64, reflect.Complex128:
		switch op {
		case token.ADD, token.SUB:
			return true
		}
	case reflect.Bool:
		switch op {
		case token.NOT:
			return true
		}
	}
	return false
}
var parseError = regexp.MustCompile(`^([0-9]+):([0-9]+): `)
func FormatErrorPos(source, errmsg string) (cursored [] string) {
	matches := parseError.FindStringSubmatch(errmsg)
	if len(matches) == 3 {
		var err error
		var line, column int
		if line, err = strconv.Atoi(matches[1]); err != nil {
			return cursored
		}
		if column, err = strconv.Atoi(matches[2]); err != nil {
			return cursored
		}
		sourceLines := strings.Split(source, "\n")
		if line > len(sourceLines) {
			return cursored
		}
		errLine := sourceLines[line-1]
		cursored = append(cursored, errLine)
		if column-1 > len(errLine) || column < 1 {
			return cursored
		} else if column == 1 {
			cursored = append(cursored, "^")
		} else {
			cursored = append(cursored, strings.Repeat("-", column-1) + "^")
		}
	}
	return cursored
}
func skipSuperfluousParens(expr Expr) Expr {
	if p, ok := expr.(*ParenExpr); ok {
		for tmp, ok := p.X.(*ParenExpr); ok; tmp, ok = p.X.(*ParenExpr) {
			p = tmp
		}
		switch p.X.(type) {
		case *BinaryExpr:
			return p
		default:
			return p.X
		}
	}
	return expr
}
func comprisingFloatType(complexType reflect.Type) reflect.Type {
	if complexType == c128 {
		return f64
	} else {
		return f32
	}
}
func evalTypedExpr(expr Expr, t knownType, env Env) (xs []reflect.Value, err error) {
        if expr.IsConst() {
                x := expr.Const()
                if ct, ok := expr.KnownType()[0].(ConstType); ok {
                        cx, _ := promoteConstToTyped(ct, constValue(x), t[0], expr)
                        xs = []reflect.Value{reflect.Value(cx)}
                } else {
                        xs = []reflect.Value{x}
                }
        } else {
                xs, err = EvalExpr(expr, env)
        }
        return xs, err
}
func checkInteger(expr ast.Expr, env Env) (aexpr Expr, i int, ok bool, checkErrs []error) {
	aexpr, checkErrs = CheckExpr(expr, env)
	if checkErrs != nil && !aexpr.IsConst() {
		return aexpr, 0, false, checkErrs
	}
	t, err := expectSingleType(aexpr)
	if err != nil {
		return aexpr, 0, false, append(checkErrs, err)
	}
	var ii int64
	if ct, ok := t.(ConstType); ok {
		c, moreErrs := promoteConstToTyped(ct, constValue(aexpr.Const()), intType, aexpr)
		if moreErrs != nil {
			checkErrs = append(checkErrs, moreErrs...)
		}
		v := reflect.Value(c)
		if v.IsValid() {
			ii = v.Int()
		} else {
			return aexpr, 0, false, checkErrs
		}
	} else {
		switch t.Kind() {
		case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
			if aexpr.IsConst() {
				ii = aexpr.Const().Int()
			}
		case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64:
			if aexpr.IsConst() {
				ii = int64(aexpr.Const().Uint())
			}
		default:
			return aexpr, 0, false, checkErrs
		}
	}
	return aexpr, int(ii), true, checkErrs
}
func evalInteger(expr Expr, env Env) (int, error) {
        if expr.IsConst() {
                x := expr.Const()
                if ct, ok := expr.KnownType()[0].(ConstType); ok {
                        cx, _ := promoteConstToTyped(ct, constValue(x), intType, expr)
			return int(reflect.Value(cx).Int()), nil
                } else {
			panic(dytc("const bool or string evaluated as int"))
                }
        } else {
                xs, err := EvalExpr(expr, env);
		if err != nil {
			return 0, err
		}
		x := xs[0]
		switch x.Type().Kind() {
		case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
			return int(x.Int()), nil
		case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64:
			return int(x.Uint()), nil
		default:
			panic(dytc("non-integral type evaluated as int"))
		}
        }
}
func checkArrayIndex(expr ast.Expr, env Env) (aexpr Expr, i int, ok bool, checkErrs []error) {
	aexpr, checkErrs = CheckExpr(expr, env)
	if !aexpr.IsConst() {
		return aexpr, 0, false, checkErrs
	}
	t := aexpr.KnownType()[0]
	var ii int64
	if ct, ok := t.(ConstType); ok {
		c, moreErrs := promoteConstToTyped(ct, constValue(aexpr.Const()), intType, aexpr)
		if moreErrs != nil {
			checkErrs = append(checkErrs, moreErrs...)
		}
		v := reflect.Value(c)
		if v.IsValid() {
			ii = v.Int()
		} else {
			return aexpr, 0, false, checkErrs
		}
	} else {
		switch t.Kind() {
		case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
			ii = aexpr.Const().Int()
		case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64:
			ii = int64(aexpr.Const().Uint())
		default:
			return aexpr, 0, false, checkErrs
		}
	}
	return aexpr, int(ii), 0 <= ii && ii <= 0x7fffffff, checkErrs
}