func (p *planner) planCall(expr *exprpb.Expr) (Interpretable, error) {
	call := expr.GetCallExpr()
	target, fnName, oName := p.resolveFunction(expr)
	argCount := len(call.GetArgs())
	var offset int
	if target != nil {
		argCount++
		offset++
	}
	args := make([]Interpretable, argCount)
	if target != nil {
		arg, err := p.Plan(target)
		if err != nil {
			return nil, err
		}
		args[0] = arg
	}
	for i, argExpr := range call.GetArgs() {
		arg, err := p.Plan(argExpr)
		if err != nil {
			return nil, err
		}
		args[i+offset] = arg
	}
	switch fnName {
	case operators.LogicalAnd:
		return p.planCallLogicalAnd(expr, args)
	case operators.LogicalOr:
		return p.planCallLogicalOr(expr, args)
	case operators.Conditional:
		return p.planCallConditional(expr, args)
	case operators.Equals:
		return p.planCallEqual(expr, args)
	case operators.NotEquals:
		return p.planCallNotEqual(expr, args)
	case operators.Index:
		return p.planCallIndex(expr, args)
	}
	var fnDef *functions.Overload
	if oName != "" {
		fnDef, _ = p.disp.FindOverload(oName)
	}
	if fnDef == nil {
		fnDef, _ = p.disp.FindOverload(fnName)
	}
	switch argCount {
	case 0:
		return p.planCallZero(expr, fnName, oName, fnDef)
	case 1:
		return p.planCallUnary(expr, fnName, oName, fnDef, args)
	case 2:
		return p.planCallBinary(expr, fnName, oName, fnDef, args)
	default:
		return p.planCallVarArgs(expr, fnName, oName, fnDef, args)
	}
}
planCall creates a callable Interpretable while specializing for common functions and invocation
patterns. Specifically, conditional operators &&, ||, ?:, and (in)equality functions result in
optimized Interpretable values.
package interpreter
import (
	"fmt"
	"strings"
	"github.com/google/cel-go/common/containers"
	"github.com/google/cel-go/common/operators"
	"github.com/google/cel-go/common/types"
	"github.com/google/cel-go/common/types/ref"
	"github.com/google/cel-go/interpreter/functions"
	exprpb "google.golang.org/genproto/googleapis/api/expr/v1alpha1"
)
type interpretablePlanner interface {
	Plan(expr *exprpb.Expr) (Interpretable, error)
}
func newPlanner(disp Dispatcher,
	provider ref.TypeProvider,
	adapter ref.TypeAdapter,
	attrFactory AttributeFactory,
	cont *containers.Container,
	checked *exprpb.CheckedExpr,
	decorators ...InterpretableDecorator) interpretablePlanner {
	return &planner{
		disp:        disp,
		provider:    provider,
		adapter:     adapter,
		attrFactory: attrFactory,
		container:   cont,
		refMap:      checked.GetReferenceMap(),
		typeMap:     checked.GetTypeMap(),
		decorators:  decorators,
	}
}
func newUncheckedPlanner(disp Dispatcher,
	provider ref.TypeProvider,
	adapter ref.TypeAdapter,
	attrFactory AttributeFactory,
	cont *containers.Container,
	decorators ...InterpretableDecorator) interpretablePlanner {
	return &planner{
		disp:        disp,
		provider:    provider,
		adapter:     adapter,
		attrFactory: attrFactory,
		container:   cont,
		refMap:      make(map[int64]*exprpb.Reference),
		typeMap:     make(map[int64]*exprpb.Type),
		decorators:  decorators,
	}
}
type planner struct {
	disp        Dispatcher
	provider    ref.TypeProvider
	adapter     ref.TypeAdapter
	attrFactory AttributeFactory
	container   *containers.Container
	refMap      map[int64]*exprpb.Reference
	typeMap     map[int64]*exprpb.Type
	decorators  []InterpretableDecorator
}
func (p *planner) Plan(expr *exprpb.Expr) (Interpretable, error) {
	switch expr.ExprKind.(type) {
	case *exprpb.Expr_CallExpr:
		return p.decorate(p.planCall(expr))
	case *exprpb.Expr_IdentExpr:
		return p.decorate(p.planIdent(expr))
	case *exprpb.Expr_SelectExpr:
		return p.decorate(p.planSelect(expr))
	case *exprpb.Expr_ListExpr:
		return p.decorate(p.planCreateList(expr))
	case *exprpb.Expr_StructExpr:
		return p.decorate(p.planCreateStruct(expr))
	case *exprpb.Expr_ComprehensionExpr:
		return p.decorate(p.planComprehension(expr))
	case *exprpb.Expr_ConstExpr:
		return p.decorate(p.planConst(expr))
	}
	return nil, fmt.Errorf("unsupported expr: %v", expr)
}
func (p *planner) decorate(i Interpretable, err error) (Interpretable, error) {
	if err != nil {
		return nil, err
	}
	for _, dec := range p.decorators {
		i, err = dec(i)
		if err != nil {
			return nil, err
		}
	}
	return i, nil
}
func (p *planner) planIdent(expr *exprpb.Expr) (Interpretable, error) {
	if identRef, found := p.refMap[expr.GetId()]; found {
		return p.planCheckedIdent(expr.GetId(), identRef)
	}
	ident := expr.GetIdentExpr()
	return &evalAttr{
		adapter: p.adapter,
		attr:    p.attrFactory.MaybeAttribute(expr.GetId(), ident.Name),
	}, nil
}
func (p *planner) planCheckedIdent(id int64, identRef *exprpb.Reference) (Interpretable, error) {
	if identRef.Value != nil {
		return p.Plan(&exprpb.Expr{Id: id,
			ExprKind: &exprpb.Expr_ConstExpr{
				ConstExpr: identRef.Value,
			}})
	}
	cType := p.typeMap[id]
	if cType.GetType() != nil {
		cVal, found := p.provider.FindIdent(identRef.Name)
		if !found {
			return nil, fmt.Errorf("reference to undefined type: %s", identRef.Name)
		}
		return NewConstValue(id, cVal), nil
	}
	return &evalAttr{
		adapter: p.adapter,
		attr:    p.attrFactory.AbsoluteAttribute(id, identRef.Name),
	}, nil
}
func (p *planner) planSelect(expr *exprpb.Expr) (Interpretable, error) {
	if identRef, found := p.refMap[expr.GetId()]; found {
		return p.planCheckedIdent(expr.GetId(), identRef)
	}
	sel := expr.GetSelectExpr()
	op, err := p.Plan(sel.GetOperand())
	if err != nil {
		return nil, err
	}
	var fieldType *ref.FieldType
	opType := p.typeMap[sel.GetOperand().GetId()]
	if opType.GetMessageType() != "" {
		ft, found := p.provider.FindFieldType(opType.GetMessageType(), sel.Field)
		if found && ft.IsSet != nil && ft.GetFrom != nil {
			fieldType = ft
		}
	}
	if sel.TestOnly {
		return &evalTestOnly{
			id:        expr.Id,
			field:     types.String(sel.Field),
			fieldType: fieldType,
			op:        op,
		}, nil
	}
	qual, err := p.attrFactory.NewQualifier(
		opType, expr.Id, sel.Field)
	if err != nil {
		return nil, err
	}
	attr, isAttr := op.(InterpretableAttribute)
	if isAttr {
		_, err = attr.AddQualifier(qual)
		return attr, err
	}
	relAttr, err := p.relativeAttr(op.ID(), op)
	if err != nil {
		return nil, err
	}
	_, err = relAttr.AddQualifier(qual)
	if err != nil {
		return nil, err
	}
	return relAttr, nil
}