package vals

import (
	
	
	
)

// Concatter wraps the Concat method. See Concat for how it is used.
type Concatter interface {
	// Concat concatenates the receiver with another value, the receiver being
	// the left operand. If concatenation is not supported for the given value,
	// the method can return the special error type ErrCatNotImplemented.
	Concat(v interface{}) (interface{}, error)
}

// RConcatter wraps the RConcat method. See Concat for how it is used.
type RConcatter interface {
	RConcat(v interface{}) (interface{}, error)
}

// ErrConcatNotImplemented is a special error value used to signal that
// concatenation is not implemented. See Concat for how it is used.
var ErrConcatNotImplemented = errors.New("concat not implemented")

type cannotConcat struct {
	lhsKind string
	rhsKind string
}

func ( cannotConcat) () string {
	return fmt.Sprintf("cannot concatenate %s and %s", .lhsKind, .rhsKind)
}

// Concat concatenates two values. If both operands are strings, it returns lhs
// + rhs, nil. If the left operand implements Concatter, it calls
// lhs.Concat(rhs). If lhs doesn't implement the interface or returned
// ErrConcatNotImplemented, it then calls rhs.RConcat(lhs). If all attempts
// fail, it returns nil and an error.
func (,  interface{}) (interface{}, error) {
	if ,  := tryConcatBuiltins(, );  {
		return , nil
	}

	if ,  := .(Concatter);  {
		,  := .Concat()
		if  != ErrConcatNotImplemented {
			return , 
		}
	}

	if ,  := .(RConcatter);  {
		,  := .RConcat()
		if  != ErrConcatNotImplemented {
			return , 
		}
	}

	return nil, cannotConcat{Kind(), Kind()}
}

func (,  interface{}) (interface{}, bool) {
	switch lhs := .(type) {
	case string, int, *big.Int, *big.Rat, float64:
		switch rhs := .(type) {
		case string, int, *big.Int, *big.Rat, float64:
			return ToString() + ToString(), true
		}
	}

	return nil, false
}