newProgram creates a program instance with an environment, an ast, and an optional list of ProgramOption values. If the program cannot be configured the prog will be nil, with a non-nil error response.
(e *Env, a *ast.AST, opts []ProgramOption)
| 230 | // |
| 231 | // If the program cannot be configured the prog will be nil, with a non-nil error response. |
| 232 | func newProgram(e *Env, a *ast.AST, opts []ProgramOption) (Program, error) { |
| 233 | // Build the env's function bindings and shared dispatcher once (pure functions of the |
| 234 | // env). The dispatcher holding the env's function bindings is identical across every |
| 235 | // Program() built from it and read-only during planning — so assemble it once per env |
| 236 | // and layer a thin child over it here for per-program Functions() isolation, rather than |
| 237 | // re-indexing overloads on every Program() call. |
| 238 | sharedDisp, hasAsync, err := e.initDispatcher() |
| 239 | if err != nil { |
| 240 | return nil, err |
| 241 | } |
| 242 | disp := interpreter.ExtendDispatcher(sharedDisp) |
| 243 | |
| 244 | // Ensure the default attribute factory is set after the adapter and provider are |
| 245 | // configured. |
| 246 | p := &prog{ |
| 247 | Env: e, |
| 248 | plannerOptions: []interpreter.PlannerOption{}, |
| 249 | dispatcher: disp, |
| 250 | costOptions: []interpreter.CostTrackerOption{}, |
| 251 | drainStrategy: async.DrainReady(100 * time.Microsecond), |
| 252 | hasAsync: hasAsync, |
| 253 | } |
| 254 | |
| 255 | // Configure the program via the ProgramOption values. |
| 256 | for _, opt := range opts { |
| 257 | p, err = opt(p) |
| 258 | if err != nil { |
| 259 | return nil, err |
| 260 | } |
| 261 | } |
| 262 | |
| 263 | // Set the attribute factory after the options have been set. |
| 264 | var attrFactory interpreter.AttributeFactory |
| 265 | attrFactorOpts := []interpreter.AttrFactoryOption{ |
| 266 | interpreter.EnableErrorOnBadPresenceTest(p.HasFeature(featureEnableErrorOnBadPresenceTest)), |
| 267 | } |
| 268 | if a.SourceInfo().HasExtension("json_name", ast.NewExtensionVersion(1, 1)) { |
| 269 | if !e.HasFeature(featureJSONFieldNames) { |
| 270 | return nil, errors.New("the AST extension 'json_name' requires the option cel.JSONFieldNames(true)") |
| 271 | } |
| 272 | } |
| 273 | // Configure the type provider, considering whether the AST indicates whether it supports JSON field names |
| 274 | if p.evalOpts&OptPartialEval == OptPartialEval { |
| 275 | attrFactory = interpreter.NewPartialAttributeFactory(e.Container, e.adapter, e.provider, attrFactorOpts...) |
| 276 | } else { |
| 277 | attrFactory = interpreter.NewAttributeFactory(e.Container, e.adapter, e.provider, attrFactorOpts...) |
| 278 | } |
| 279 | interp := interpreter.NewInterpreter(disp, e.Container, e.provider, e.adapter, attrFactory) |
| 280 | p.interpreter = interp |
| 281 | |
| 282 | // Translate the EvalOption flags into InterpretableDecorator instances. |
| 283 | plannerOptions := make([]interpreter.PlannerOption, len(p.plannerOptions)) |
| 284 | copy(plannerOptions, p.plannerOptions) |
| 285 | |
| 286 | // Enable interrupt checking if there's a non-zero check frequency |
| 287 | if p.interruptCheckFrequency > 0 { |
| 288 | plannerOptions = append(plannerOptions, interpreter.InterruptableEval()) |
| 289 | } |
no test coverage detected