func initProgGen(factory progFactory) (Program, error) {
	_, err := factory(interpreter.NewEvalState())
	if err != nil {
		return nil, err
	}
	return &progGen{factory: factory}, nil
}
initProgGen tests the factory object by calling it once and returns a factory-based Program if
the test is successful.
package cel
import (
	"fmt"
	"math"
	"github.com/google/cel-go/common/types"
	"github.com/google/cel-go/common/types/ref"
	"github.com/google/cel-go/interpreter"
	exprpb "google.golang.org/genproto/googleapis/api/expr/v1alpha1"
)
type Program interface {
	Eval(vars interface{}) (ref.Val, *EvalDetails, error)
}
func NoVars() interpreter.Activation {
	return interpreter.EmptyActivation()
}
func PartialVars(vars interface{},
	unknowns ...*interpreter.AttributePattern) (interpreter.PartialActivation, error) {
	return interpreter.NewPartialActivation(vars, unknowns...)
}
func AttributePattern(varName string) *interpreter.AttributePattern {
	return interpreter.NewAttributePattern(varName)
}
type EvalDetails struct {
	state interpreter.EvalState
}
func (ed *EvalDetails) State() interpreter.EvalState {
	return ed.state
}
type prog struct {
	*Env
	evalOpts      EvalOption
	decorators    []interpreter.InterpretableDecorator
	defaultVars   interpreter.Activation
	dispatcher    interpreter.Dispatcher
	interpreter   interpreter.Interpreter
	interpretable interpreter.Interpretable
	attrFactory   interpreter.AttributeFactory
}
type progFactory func(interpreter.EvalState) (Program, error)
type progGen struct {
	factory progFactory
}
func newProgram(e *Env, ast *Ast, opts []ProgramOption) (Program, error) {
	disp := interpreter.NewDispatcher()
	p := &prog{
		Env:        e,
		decorators: []interpreter.InterpretableDecorator{},
		dispatcher: disp,
	}
	var err error
	for _, opt := range opts {
		if opt == nil {
			return nil, fmt.Errorf("program options should be non-nil")
		}
		p, err = opt(p)
		if err != nil {
			return nil, err
		}
	}
	if p.evalOpts&OptPartialEval == OptPartialEval {
		p.attrFactory = interpreter.NewPartialAttributeFactory(e.Container, e.adapter, e.provider)
	} else {
		p.attrFactory = interpreter.NewAttributeFactory(e.Container, e.adapter, e.provider)
	}
	interp := interpreter.NewInterpreter(disp, e.Container, e.provider, e.adapter, p.attrFactory)
	p.interpreter = interp
	decorators := make([]interpreter.InterpretableDecorator, len(p.decorators))
	copy(decorators, p.decorators)
	if p.evalOpts&OptOptimize == OptOptimize {
		decorators = append(decorators, interpreter.Optimize())
	}
	if p.evalOpts&OptExhaustiveEval == OptExhaustiveEval {
		factory := func(state interpreter.EvalState) (Program, error) {
			decs := append(decorators, interpreter.ExhaustiveEval(state))
			clone := &prog{
				evalOpts:    p.evalOpts,
				defaultVars: p.defaultVars,
				Env:         e,
				dispatcher:  disp,
				interpreter: interp}
			return initInterpretable(clone, ast, decs)
		}
		return initProgGen(factory)
	}
	if p.evalOpts&OptTrackState == OptTrackState {
		factory := func(state interpreter.EvalState) (Program, error) {
			decs := append(decorators, interpreter.TrackState(state))
			clone := &prog{
				evalOpts:    p.evalOpts,
				defaultVars: p.defaultVars,
				Env:         e,
				dispatcher:  disp,
				interpreter: interp}
			return initInterpretable(clone, ast, decs)
		}
		return initProgGen(factory)
	}
	return initInterpretable(p, ast, decorators)
}