package specops

import (
	"fmt"

	"github.com/ethereum/go-ethereum/core/vm"
)

// A stackDelta carries the number of values popped and pushed by an opcode.
// Values are generated by the opcopy binary.
type stackDelta struct {
	pop, push uint
}

// Inverted applies DUP<X> and SWAP<X> opcodes relative to the bottom-most value
// on the stack unless there are more than 16 values, in which case they are
// applied relative to the 16th.
//
// For a stack with n <= 16 values on it, `Inverted(DUP1)` and `Inverted(SWAP1)`
// will apply to the nth value instead of the first. Similarly, `Inverted(DUP2)`
// will apply to the (n-1)the value, etc. For a stack with >16 items, the same
// logic applies but with n = 16.
//
// Note that the semantics disallow `Inverted(SWAP16)` as it would be a noop. In
// fact, in all cases, inverted SWAPs are capped at `depth-1`. While they could
// be offset by one (like regular SWAPs) this is less intuitive than
// `Inverted(SWAP1)` being the bottom of a (sub-16-depth) stack.
//
// See stack.SetDepth() for caveats. It is best practice to use `Inverted` in
// conjunction with stack.{Set/Expect}Depth().
type Inverted vm.OpCode

// Bytecode always returns an error.
func (i Inverted) Bytecode() ([]byte, error) {
	return nil, fmt.Errorf("call to %T.Bytecode()", i)
}
