packages/deriver/src/Deriver/Evaluator/Micro/ConfiguredEvaluator.php

1<?php
2
3declare(strict_types=1);
4
5namespace Deriver\Deriver\Evaluator\Micro;
6
7use Closure;
8use Deriver\Deriver\Evaluator\Evidence\EvidenceKind;
9use Deriver\Deriver\Evaluator\Evidence\Node;
10use Deriver\Deriver\Evaluator\Term;
11use Deriver\Exception\EvaluationContractException;
12use Override;
13use Throwable;
14
15/**
16 * Executable micro evaluator produced from public configuration.
17 * @implements MicroEvaluator<Term|null>
18 * @visibility root
19 */
20final class ConfiguredEvaluator implements MicroEvaluator
21{
22    /**
23     * @param Closure(Request): ?Term $evaluate Converted evaluation callback
24     */
25    public function __construct(
26        public readonly string $id,
27        public readonly string $version,
28        public readonly string $operation,
29        public readonly string $name,
30        private readonly Closure $evaluate,
31        public readonly int $priority = 0,
32        public readonly ?string $path = null,
33        public readonly ?int $start = null,
34        public readonly ?int $end = null,
35    ) {
36    }
37
38    /**
39     * Applies configured semantics and records only the demanded dependencies.
40     * @throws EvaluationContractException If trusted evaluation code fails
41     */
42    #[Override]
43    public function evaluate(Request $request): ?Term
44    {
45        $operation = $request->operation();
46        $source = $request->source();
47        if ($operation !== $this->operation || $request->name() !== $this->name || $this->path !== null && $this->path !== $source->path || $this->start !== null && $this->start !== $source->start || $this->end !== null && $this->end !== $source->end) {
48            return null;
49        }
50        try {
51            $result = ($this->evaluate)($request);
52        } catch (Throwable $error) {
53            throw new EvaluationContractException($this->id . ': ' . $error->getMessage(), previous: $error);
54        }
55        if ($result === null) {
56            return null;
57        }
58        $context = $request->engine->context;
59        $context->evaluatorApplications++;
60        $evidence = new Node(EvidenceKind::EvaluatorApplication, $context->provenance->inputs($request->inputs()), $source, ['id' => $this->id, 'version' => $this->version, 'operation' => $this->operation, 'name' => $this->name]);
61        return (new \Deriver\Deriver\Evaluator\Enumeration\Choices($context->provenance))->map($result, fn (Term $value): Term => $context->provenance->attach($value, $evidence));
62    }
63
64}
65