This package contains virtual machine implementations for executing scripts in various languages through a consistent interface. While each supported VM has its own unique characteristics, they all follow a standardized flow pattern.
Design Philosophy
Common Interface: All VMs present the same interface (evaluationEvaluator) regardless of underlying implementation
Separation of Concerns: Compilation, data preparation, and execution are distinct phases
Thread-safe Evaluation: Each VM is designed to allow concurrent execution of scripts
Context-Based Data Flow: Runtime data is accessed with a context.Context object (saved/loaded with a data.Provider)
Execution Results: All VMs return the same evaluation.EvaluatorResponse object, which contains the execution result and metadata
Dataflow & Architecture
Compilation Instantiation
Each VM has a NewCompiler function that returns a compiler instance that implements the script.Compiler interface
The NewCompiler function may have some VM-specific options
The Compiler object includes a Compile method that takes a loader.Loader implementation
loader.Loader is a generic way to load script content from various sources
Compile-time errors are captured and returned to the caller
A script.ExecutableContent is returned by Compile
Executable Creation Stage
The script.ExecutableUnit is a wrapper around the script.ExecutableContent
NewExecutableUnit receives a Compiler and several other objects
Calls the script.Compiler to compile the script, storing the result in the ExecutableContent
The ExecutableUnit is responsible for managing the lifecycle of the script execution
Evaluator Creation
NewEvaluator takes a script.ExecutableUnit and returns an object that implements evaluationEvaluator
At this point it can be called with .Eval(ctx), however input data is required it must be prepared
Data Preparation Stage
This phase is optional, and must happen prior to evaluation when runtime input data is used
The Evaluator implements the data.Setter interface, which has an AddDataToContext method
The AddDataToContext method takes a context.Context and a variadic list of map[string]any
AddDataToContext calls the data.Provider to store the data, somewhere accessible to the Evaluator
The conversion is fairly opinionated, and handled by the data.Provider
For example, it converts an http.Request into a map[string]any using the schema in helper.RequestToMap
The AddDataToContext method returns a new context with the data stored or linked in it
Execution Stage
When Eval(ctx) is called, the data.Provider first loads the input data into the VM
The VM executes the script and returns an evaluation.EvaluatorResponse
Result Processing
The process for building the evaluation.EvaluatorResponse is different for each VM
There are several type conversions, and the result is accessible with the Interface() method
The evaluation.EvaluatorResponse also contains metadata about the execution
NewEvaluator creates a new VM with the given CPU type and globals.
This will load a script from a ExecutableUnit object into the VM, and can be run immediately.
The ExecutableUnit contains a DataProvider that provides runtime data for evaluation.