packages/deriver/src/Deriver/Evaluator/Invocation/Bodies.php

1<?php
2
3declare(strict_types=1);
4
5namespace Deriver\Deriver\Evaluator\Invocation;
6
7use Deriver\Deriver\Evaluator\CallEvaluation;
8use Deriver\Deriver\Evaluator\Evaluator;
9use Deriver\Deriver\Evaluator\Scope\Frame;
10use Deriver\Deriver\Lowerer\Graph\Instruction;
11
12/**
13 * The only candidate entry to source or evaluator implementations.
14 * @visibility parent
15 */
16final class Bodies
17{
18    /**
19     * Uses the current dependency context.
20     */
21    public function __construct(private readonly Evaluator $engine)
22    {
23    }
24
25    /**
26     * Selects once per call and bindings, before inspecting effects.
27     */
28    public function select(Frame $caller, Instruction $call, string $target, int $depth): Body
29    {
30        $context = $this->engine->context;
31        $key = $caller->identity . ':' . $call->id . ':' . $target;
32        if (isset($context->implementations[$key])) {
33            return $context->implementations[$key];
34        }
35        $request = new \Deriver\Deriver\Evaluator\Micro\Request($this->engine, $caller, $call, $depth, $target);
36        $builtin = new CallEvaluation($this->engine);
37        $evaluator = (new \Deriver\Deriver\Evaluator\Micro\Dispatch())->evaluate($request, $builtin);
38        return $context->implementations[$key] = new Body($evaluator ?? $context->index->graph($target), $evaluator !== null);
39    }
40}
41