Skip to content

tags: - EverSharpRunner - execution - api - csharp-integration


Using EverSharpRunner

The EverSharpRunner class is your main interface for executing EverSharp code from C#. This guide covers all its methods and properties.


Creating a Runner

Basic Instantiation

using Elements.Libs.EverSharp;

var runner = new EverSharpRunner();

With Extension Functions

Add custom native functions:

var extensions = new Dictionary<string, Callable>
{
    { "$CustomFunction", new MyCustomFunction() }
};

var runner = new EverSharpRunner(extensions: extensions);

With Preloaded Libraries

Load common functions at startup:

var libraries = new List<string>
{
    @"
        function calculateTax(amount, rate) {
            return amount * rate;
        }
    "
};

var runner = new EverSharpRunner(libraries: libraries);

Core Methods

Run()

Executes EverSharp statements and updates global variables.

Signature:

public void Run(string source)

Example:

runner.Run(@"
    premium = 1000;
    discount = 0.15;
    final = premium * (1 - discount);
");

var final = (decimal)runner.GlobalVariables["final"]; // 850

Use when:

  • Executing multiple statements
  • Updating variables
  • Defining functions
  • Running complete scripts

RunExpression()

Evaluates a single expression and returns its value directly.

Signature:

public object? RunExpression(string source)

Example:

var result = runner.RunExpression("10 + 20 * 3"); // 70

var max = runner.RunExpression("$Max(100, 250)"); // 250

var greeting = runner.RunExpression("\"Hello, \" + \"World\""); // "Hello, World"

Use when:

  • Evaluating single expression
  • Getting immediate result
  • No need to store in variable

Difference from Run(): | Feature | Run() | RunExpression() | |---------|-------|-----------------| | Input | Statements | Single expression | | Return value | void | Expression result | | Variables | Updates globals | No side effects (unless expression has them) | | Multiple statements | Yes | No |

Validate()

Checks syntax without executing code.

Signature:

public IEnumerable<string?> Validate(string source)

Example:

var script = "x = 10; y = 20; z = x + y;";
var errors = runner.Validate(script);

if (!errors.Any())
{
    Console.WriteLine("Script is valid");
    runner.Run(script);
}
else
{
    Console.WriteLine("Syntax errors:");
    foreach (var error in errors)
    {
        Console.WriteLine($"  - {error}");
    }
}

Use when:

  • Validating user-provided scripts
  • Checking syntax before execution
  • Providing immediate feedback in editors

ValidateExpression()

Checks expression syntax without evaluating.

Signature:

public IEnumerable<string?> ValidateExpression(string source)

Example:

var expression = "x + y * 2";
var errors = runner.ValidateExpression(expression);

if (!errors.Any())
{
    var result = runner.RunExpression(expression);
}

Environment Management

InitializeEnvironment()

Sets up constants and variables before execution.

Signature:

public void InitializeEnvironment(EverDictionary constants, EverDictionary variables)

Example:

using Elements.Libs.Extensions.EverDictionaries;

// Constants (read-only in scripts)
var constants = new EverDictionary
{
    { "TAX_RATE", 0.08m },
    { "MAX_PREMIUM", 10000m },
    { "MIN_AGE", 18m }
};

// Variables (can be modified in scripts)
var variables = new EverDictionary
{
    { "age", 35m },
    { "coverage", 250000m }
};

runner.InitializeEnvironment(constants, variables);

runner.Run(@"
    // Can read constants
    tax = basePremium * TAX_RATE;

    // Can modify variables
    age = age + 1;

    // Cannot modify constants (would create new local variable)
    // TAX_RATE = 0.10; // Creates new local, doesn't change constant
");

When to use:

  • Passing data from C# to EverSharp
  • Setting up configuration values
  • Providing context for scripts

SetExternalVariable()

Sets a single variable at runtime.

Signature:

public void SetExternalVariable(string name, object? value)

Example:

// Set variables dynamically
runner.SetExternalVariable("userAge", 42m);
runner.SetExternalVariable("userName", "Alice");
runner.SetExternalVariable("activeDate", DateTime.Now);

runner.Run(@"
    message = ""User "" + userName + "" is "" + userAge + "" years old"";
");

When to use:

  • Setting individual variables after initialization
  • Updating context during execution
  • Injecting runtime values

Properties

HasErrors

Indicates whether errors occurred during last operation.

Type: bool

Example:

runner.Run(script);

if (runner.HasErrors)
{
    Console.WriteLine("Execution failed");
}
else
{
    Console.WriteLine("Execution successful");
}

Errors

Collection of error messages from last operation.

Type: IEnumerable<string>

Example:

runner.Run(invalidScript);

if (runner.HasErrors)
{
    Console.WriteLine("Errors encountered:");
    foreach (var error in runner.Errors)
    {
        Console.WriteLine($"  - {error}");
    }
}

GlobalVariables

All mutable variables created or modified during execution.

Type: EverDictionary

Example:

runner.Run("x = 10; y = 20; sum = x + y;");

// Access by key
var sum = (decimal)runner.GlobalVariables["sum"]; // 30

// Type-safe access (extension methods)
var x = runner.GlobalVariables.GetNumber("x");
var name = runner.GlobalVariables.GetStr("name");
var isActive = runner.GlobalVariables.GetBool("isActive");

GlobalConstants

All read-only constants defined during initialization.

Type: EverDictionary

Example:

var constants = new EverDictionary { { "PI", 3.14159m } };
runner.InitializeEnvironment(constants, new EverDictionary());

var pi = runner.GlobalConstants.GetNumber("PI"); // 3.14159

Globals

Combined view of all global variables and constants.

Type: EverDictionary

Example:

var allGlobals = runner.Globals;

foreach (var kvp in allGlobals)
{
    Console.WriteLine($"{kvp.Key} = {kvp.Value}");
}

StandardOutput

Captured output from $Log() calls.

Type: string

Example:

runner.Run(@"
    $Log(""Starting calculation"");
    result = 10 + 20;
    $Log(""Result: {0}"", result);
");

Console.WriteLine(runner.StandardOutput);
// Output:
// Starting calculation
// Result: 30

Type Conversions

EverDictionary Helper Methods

// Numeric values
var num = runner.GlobalVariables.GetNumber("premium");
decimal? nullableNum = runner.GlobalVariables.GetNumber("optional");

// String values
var str = runner.GlobalVariables.GetStr("name");
string? nullableStr = runner.GlobalVariables.GetStr("optional");

// Boolean values
var flag = runner.GlobalVariables.GetBool("isActive");
bool? nullableBool = runner.GlobalVariables.GetBool("optional");

// Objects (returns EverDictionary)
var dict = runner.GlobalVariables.GetDictionary("person");
var name = dict.GetStr("name");

// Arrays
var arr = runner.GlobalVariables.GetArray("numbers");
var first = (decimal)arr[0];

Manual Casting

// Direct cast (throws if type mismatch)
var num = (decimal)runner.GlobalVariables["value"];
var str = (string)runner.GlobalVariables["text"];
var date = (DateTime)runner.GlobalVariables["timestamp"];

// Safe cast (returns null if incompatible)
var num = runner.GlobalVariables["value"] as decimal?;
if (num.HasValue)
{
    Console.WriteLine($"Number: {num.Value}");
}

Complete Example

using Elements.Libs.EverSharp;
using Elements.Libs.Extensions.EverDictionaries;

public class InsurancePremiumCalculator
{
    private readonly EverSharpRunner runner;

    public InsurancePremiumCalculator()
    {
        // Setup constants
        var constants = new EverDictionary
        {
            { "TAX_RATE", 0.08m },
            { "BASE_RATE", 0.01m },
            { "YOUTH_MULTIPLIER", 1.5m },
            { "SENIOR_MULTIPLIER", 1.25m }
        };

        // Load premium calculation library
        var libraries = new List<string>
        {
            File.ReadAllText("scripts/premium-calculations.evs")
        };

        runner = new EverSharpRunner(libraries: libraries);
        runner.InitializeEnvironment(constants, new EverDictionary());
    }

    public decimal CalculatePremium(int age, decimal coverageAmount)
    {
        // Set input variables
        runner.SetExternalVariable("age", (decimal)age);
        runner.SetExternalVariable("coverageAmount", coverageAmount);

        // Execute calculation script
        runner.Run(@"
            premium = coverageAmount * BASE_RATE;

            if (age < 25) {
                premium = premium * YOUTH_MULTIPLIER;
            } else if (age > 65) {
                premium = premium * SENIOR_MULTIPLIER;
            }

            premium = premium * (1 + TAX_RATE);
            premium = $Round(premium, 2);
        ");

        // Check for errors
        if (runner.HasErrors)
        {
            throw new Exception($"Calculation failed: {string.Join(", ", runner.Errors)}");
        }

        // Return result
        return runner.GlobalVariables.GetNumber("premium") ?? 0;
    }

    public bool ValidateScript(string script)
    {
        var errors = runner.Validate(script);

        if (errors.Any())
        {
            Console.WriteLine("Script validation failed:");
            foreach (var error in errors)
            {
                Console.WriteLine($"  - {error}");
            }
            return false;
        }

        return true;
    }
}

// Usage
var calculator = new InsurancePremiumCalculator();

if (calculator.ValidateScript(userProvidedScript))
{
    var premium = calculator.CalculatePremium(age: 35, coverageAmount: 250000m);
    Console.WriteLine($"Premium: ${premium}");
}

Best Practices

1. Check Errors After Every Operation

runner.Run(script);

if (runner.HasErrors)
{
    // Handle errors before accessing variables
    LogErrors(runner.Errors);
    return;
}

2. Validate User Scripts

// Always validate before executing user input
var errors = runner.Validate(userScript);
if (errors.Any())
{
    return BadRequest(errors);
}

runner.Run(userScript);

3. Use Type-Safe Access

// Prefer
var value = runner.GlobalVariables.GetNumber("premium") ?? 0;

// Over
var value = (decimal)(runner.GlobalVariables["premium"] ?? 0m);

4. Initialize Environment Once

// Setup once at startup
runner.InitializeEnvironment(constants, initialVariables);

// Use SetExternalVariable for runtime updates
runner.SetExternalVariable("currentDate", DateTime.Now);

5. Capture Standard Output for Debugging

runner.Run(script);

if (!string.IsNullOrEmpty(runner.StandardOutput))
{
    logger.Debug($"Script output: {runner.StandardOutput}");
}

Common Patterns

Pattern 1: Configuration-Driven Calculations

// Load configuration
var config = LoadConfiguration();
runner.InitializeEnvironment(config.Constants, config.Variables);

// Run calculation
runner.Run(config.CalculationScript);
var result = runner.GlobalVariables.GetNumber("result");

Pattern 2: Dynamic Rule Evaluation

foreach (var rule in rules)
{
    runner.SetExternalVariable("ruleContext", ConvertToEverDictionary(context));
    runner.Run(rule.Script);

    if (runner.GlobalVariables.GetBool("rulePassed") == true)
    {
        ApplyRule(rule);
    }
}

Pattern 3: Template-Based Generation

var template = LoadTemplate("premium-calculation");
var script = template.Replace("{{AGE}}", age.ToString())
                     .Replace("{{COVERAGE}}", coverage.ToString());

runner.Run(script);
return runner.GlobalVariables.GetNumber("result");

Next Steps