Skip to content

tags: - api - EverSharpRunner - reference - integration


EverSharpRunner API Reference

Complete C# API reference for integrating EverSharp into .NET applications.

Overview

EverSharpRunner is the primary class for executing EverSharp scripts from C#. It provides methods for running scripts, expressions, managing environments, and handling errors.

Class Definition

namespace Elements.Libs.EverSharp;

public class EverSharpRunner

Constructor

EverSharpRunner(IEnumerable\<string>? libraries, Dictionary\<string, Callable>? extensions)

Creates a new EverSharpRunner instance.

Parameters:

  • libraries (optional): Collection of library scripts to execute on initialization
  • extensions (optional): Dictionary of custom native functions to register

Example:

// Basic instantiation
var runner = new EverSharpRunner();

// With libraries
var libraries = new[] {
    "PI = 3.14159;",
    "function square(n) { return n * n; }"
};
var runner = new EverSharpRunner(libraries);

// With custom extensions
var extensions = new Dictionary<string, Callable>
{
    ["$MyFunction"] = new MyCustomFunction()
};
var runner = new EverSharpRunner(null, extensions);

Core Execution Methods

Run(string source)

Executes a complete EverSharp script containing statements and declarations.

Parameters:

  • source: EverSharp script code to execute

Returns: void

Example:

var runner = new EverSharpRunner();

string script = @"
    x = 10;
    y = 20;
    result = x + y;
";

runner.Run(script);

// Check for errors
if (runner.HasErrors)
{
    foreach (var error in runner.Errors)
    {
        Console.WriteLine($"Error: {error}");
    }
}

Use Cases:

  • Running multi-line scripts
  • Executing function declarations
  • Running initialization scripts

RunExpression(string source)

Evaluates a single EverSharp expression and returns its result.

Parameters:

  • source: EverSharp expression to evaluate

Returns: object? - The result of the expression, or null if error occurred

Example:

var runner = new EverSharpRunner();

// Evaluate arithmetic
var result = runner.RunExpression("10 + 5 * 2");
Console.WriteLine(result);  // 20

// Evaluate with variables
runner.Run("x = 100;");
var doubled = runner.RunExpression("x * 2");
Console.WriteLine(doubled);  // 200

// Call functions
runner.Run("function add(a, b) { return a + b; }");
var sum = runner.RunExpression("add(5, 3)");
Console.WriteLine(sum);  // 8

Use Cases:

  • Calculating single values
  • Evaluating formulas
  • Quick expression evaluation without statements

Environment Management

InitializeEnvironment(EverDictionary constants, EverDictionary variables)

Initializes the global environment with constants and variables from C#.

Parameters:

  • constants: Dictionary of constant values (read-only in EverSharp)
  • variables: Dictionary of variable values (read-write in EverSharp)

Example:

using Elements.Libs.Extensions.EverDictionaries;

var runner = new EverSharpRunner();

// Create constants (read-only from EverSharp)
var constants = new EverDictionary
{
    ["TAX_RATE"] = 0.08m,
    ["MAX_AMOUNT"] = 10000m,
    ["COMPANY_NAME"] = "Acme Insurance"
};

// Create variables (read-write from EverSharp)
var variables = new EverDictionary
{
    ["policyNumber"] = "POL-12345",
    ["premium"] = 1200m,
    ["effectiveDate"] = DateTime.Parse("2024-01-01")
};

runner.InitializeEnvironment(constants, variables);

// Access in script
runner.Run(@"
    taxAmount = premium * TAX_RATE;
    totalAmount = premium + taxAmount;
");

// Get results back
var total = runner.GlobalVariables["totalAmount"];
Console.WriteLine($"Total: {total}");  // Total: 1296

SetExternalVariable(string name, object? value)

Sets or updates a single global variable from C#.

Parameters:

  • name: Variable name
  • value: Variable value

Example:

var runner = new EverSharpRunner();

// Set individual variables
runner.SetExternalVariable("customerName", "John Smith");
runner.SetExternalVariable("age", 35);
runner.SetExternalVariable("premium", 1200m);

// Use in script
runner.Run(@"
    if (age < 25) {
        adjustedPremium = premium * 1.5;
    } else {
        adjustedPremium = premium;
    }
");

// Get result
var adjusted = runner.GlobalVariables["adjustedPremium"];
Console.WriteLine($"Adjusted Premium: {adjusted}");

Properties

HasErrors (bool)

Indicates whether any errors occurred during the last execution.

Example:

runner.Run("x = 10 / 0;");  // Division by zero

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

Errors (IEnumerable\<string>)

Collection of error messages from the last execution.

Example:

runner.Run("invalid syntax here");

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

GlobalVariables (EverDictionary)

Read-only dictionary of all global variables and their current values.

Example:

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

var x = runner.GlobalVariables["x"];
var y = runner.GlobalVariables["y"];
var result = runner.GlobalVariables["result"];

Console.WriteLine($"x={x}, y={y}, result={result}");
// Output: x=10, y=20, result=30

GlobalConstants (EverDictionary)

Read-only dictionary of all global constants.

Example:

var constants = new EverDictionary
{
    ["PI"] = 3.14159m,
    ["MAX_VALUE"] = 1000m
};

runner.InitializeEnvironment(constants, new EverDictionary());

// Constants are available
var pi = runner.GlobalConstants["PI"];
Console.WriteLine($"PI = {pi}");  // PI = 3.14159

Globals (EverDictionary)

Combined dictionary of all globals (constants + variables).

Example:

var constants = new EverDictionary { ["TAX_RATE"] = 0.08m };
var variables = new EverDictionary { ["amount"] = 1000m };

runner.InitializeEnvironment(constants, variables);

runner.Run("total = amount * (1 + TAX_RATE);");

// Access all globals
foreach (var kvp in runner.Globals)
{
    Console.WriteLine($"{kvp.Key} = {kvp.Value}");
}
// Output:
// TAX_RATE = 0.08
// amount = 1000
// total = 1080

StandardOutput (string)

Accumulated output from $Log() calls in the script.

Example:

runner.Run(@"
    $Log('Starting calculation');
    result = 10 + 5;
    $Log('Result: ' + $ToString(result));
");

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

Practical Examples

Example 1: Simple Calculator

public decimal Calculate(string expression)
{
    var runner = new EverSharpRunner();

    var result = runner.RunExpression(expression);

    if (runner.HasErrors)
    {
        throw new Exception($"Calculation error: {string.Join(", ", runner.Errors)}");
    }

    return Convert.ToDecimal(result);
}

// Usage
var result = Calculate("(100 + 50) * 0.08");
Console.WriteLine(result);  // 12

Example 2: Insurance Premium Calculator

public class PremiumCalculator
{
    private readonly EverSharpRunner runner;

    public PremiumCalculator()
    {
        runner = new EverSharpRunner();

        // Load business rules
        string rules = @"
            function calculatePremium(baseAmount, age, riskFactor) {
                premium = baseAmount;

                if (age < 25) {
                    premium = premium * 1.5;
                } else if (age > 65) {
                    premium = premium * 1.3;
                }

                premium = premium * riskFactor;

                return premium;
            }
        ";

        runner.Run(rules);
    }

    public decimal CalculatePremium(decimal baseAmount, int age, decimal riskFactor)
    {
        runner.SetExternalVariable("baseAmount", baseAmount);
        runner.SetExternalVariable("age", age);
        runner.SetExternalVariable("riskFactor", riskFactor);

        var result = runner.RunExpression("calculatePremium(baseAmount, age, riskFactor)");

        if (runner.HasErrors)
        {
            throw new Exception($"Error: {string.Join(", ", runner.Errors)}");
        }

        return Convert.ToDecimal(result);
    }
}

// Usage
var calculator = new PremiumCalculator();
var premium = calculator.CalculatePremium(1000m, 28, 1.2m);
Console.WriteLine($"Premium: ${premium}");  // Premium: $1440

Example 3: Dynamic Business Rules

public class RuleEngine
{
    private readonly EverSharpRunner runner;

    public RuleEngine(string rulesScript)
    {
        runner = new EverSharpRunner();
        runner.Run(rulesScript);

        if (runner.HasErrors)
        {
            throw new Exception($"Failed to load rules: {string.Join(", ", runner.Errors)}");
        }
    }

    public bool EvaluateRule(string ruleName, Dictionary<string, object> context)
    {
        // Set context variables
        foreach (var kvp in context)
        {
            runner.SetExternalVariable(kvp.Key, kvp.Value);
        }

        // Evaluate rule
        var result = runner.RunExpression($"{ruleName}()");

        if (runner.HasErrors)
        {
            throw new Exception($"Rule evaluation failed: {string.Join(", ", runner.Errors)}");
        }

        return Convert.ToBoolean(result);
    }
}

// Usage
string rules = @"
    function isEligibleForDiscount() {
        return age >= 25 && yearsWithCompany >= 5 && claimCount == 0;
    }

    function isHighRisk() {
        return age < 25 || claimCount > 2;
    }
";

var engine = new RuleEngine(rules);

var context = new Dictionary<string, object>
{
    ["age"] = 30,
    ["yearsWithCompany"] = 6,
    ["claimCount"] = 0
};

bool eligible = engine.EvaluateRule("isEligibleForDiscount", context);
Console.WriteLine($"Eligible for discount: {eligible}");  // true

bool highRisk = engine.EvaluateRule("isHighRisk", context);
Console.WriteLine($"High risk: {highRisk}");  // false

Example 4: Multi-Step Calculation

public class PolicyCalculator
{
    public PolicyResult CalculatePolicy(PolicyInput input)
    {
        var runner = new EverSharpRunner();

        // Initialize with input data
        var variables = new EverDictionary
        {
            ["coverageAmount"] = input.CoverageAmount,
            ["age"] = input.Age,
            ["hasDiscount"] = input.HasDiscount,
            ["baseRate"] = input.BaseRate
        };

        runner.InitializeEnvironment(new EverDictionary(), variables);

        // Execute multi-step calculation
        string script = @"
            // Step 1: Calculate base premium
            basePremium = coverageAmount * baseRate / 1000;

            // Step 2: Apply age factor
            if (age < 30) {
                ageFactor = 1.2;
            } else if (age < 50) {
                ageFactor = 1.0;
            } else {
                ageFactor = 1.3;
            }
            adjustedPremium = basePremium * ageFactor;

            // Step 3: Apply discount
            if (hasDiscount) {
                discount = adjustedPremium * 0.10;
                finalPremium = adjustedPremium - discount;
            } else {
                discount = 0;
                finalPremium = adjustedPremium;
            }
        ";

        runner.Run(script);

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

        // Extract results
        return new PolicyResult
        {
            BasePremium = Convert.ToDecimal(runner.GlobalVariables["basePremium"]),
            AgeFactor = Convert.ToDecimal(runner.GlobalVariables["ageFactor"]),
            AdjustedPremium = Convert.ToDecimal(runner.GlobalVariables["adjustedPremium"]),
            Discount = Convert.ToDecimal(runner.GlobalVariables["discount"]),
            FinalPremium = Convert.ToDecimal(runner.GlobalVariables["finalPremium"])
        };
    }
}

public class PolicyInput
{
    public decimal CoverageAmount { get; set; }
    public int Age { get; set; }
    public bool HasDiscount { get; set; }
    public decimal BaseRate { get; set; }
}

public class PolicyResult
{
    public decimal BasePremium { get; set; }
    public decimal AgeFactor { get; set; }
    public decimal AdjustedPremium { get; set; }
    public decimal Discount { get; set; }
    public decimal FinalPremium { get; set; }
}

Example 5: Script Validation

public class ScriptValidator
{
    public ValidationResult Validate(string script)
    {
        var runner = new EverSharpRunner();

        // Try to run the script
        runner.Run(script);

        if (runner.HasErrors)
        {
            return new ValidationResult
            {
                IsValid = false,
                Errors = runner.Errors.ToList()
            };
        }

        return new ValidationResult
        {
            IsValid = true,
            Errors = new List<string>()
        };
    }

    public ValidationResult ValidateExpression(string expression)
    {
        var runner = new EverSharpRunner();

        var result = runner.RunExpression(expression);

        if (runner.HasErrors)
        {
            return new ValidationResult
            {
                IsValid = false,
                Errors = runner.Errors.ToList()
            };
        }

        return new ValidationResult
        {
            IsValid = true,
            Errors = new List<string>()
        };
    }
}

public class ValidationResult
{
    public bool IsValid { get; set; }
    public List<string> Errors { get; set; }
}

// Usage
var validator = new ScriptValidator();

var result1 = validator.ValidateExpression("10 + 5 * 2");
Console.WriteLine($"Valid: {result1.IsValid}");  // true

var result2 = validator.ValidateExpression("10 + * 5");
Console.WriteLine($"Valid: {result2.IsValid}");  // false
foreach (var error in result2.Errors)
{
    Console.WriteLine($"  Error: {error}");
}

Error Handling

Common Error Scenarios

var runner = new EverSharpRunner();

// Syntax error
runner.Run("x = 10 +");
if (runner.HasErrors)
{
    Console.WriteLine("Syntax error detected");
}

// Runtime error
runner.Run("result = undefinedVariable;");
if (runner.HasErrors)
{
    Console.WriteLine("Runtime error: undefined variable");
}

// Type error
runner.Run("result = 'text' + 5;");  // String concatenation works
runner.Run("result = 'text' * 5;");  // Type error
if (runner.HasErrors)
{
    Console.WriteLine("Type error: invalid operation");
}

Best Practices

  1. Always check HasErrors after execution:
runner.Run(script);
if (runner.HasErrors)
{
    // Handle errors
    LogErrors(runner.Errors);
    return;
}
// Continue with success logic
  1. Clear errors between runs (automatic):
// Errors are automatically cleared on each Run/RunExpression call
runner.Run("x = 10;");  // Success
runner.Run("invalid");  // Error - previous errors are cleared
  1. Use appropriate method for task:
// Use Run() for scripts with statements
runner.Run("x = 10; y = 20;");

// Use RunExpression() for single expressions
var result = runner.RunExpression("x + y");

Thread Safety

EverSharpRunner is not thread-safe. Each thread should have its own instance:

// Wrong - sharing instance across threads
var sharedRunner = new EverSharpRunner();
Parallel.For(0, 10, i =>
{
    sharedRunner.Run($"x = {i};");  // Race condition!
});

// Correct - instance per thread
Parallel.For(0, 10, i =>
{
    var runner = new EverSharpRunner();
    runner.Run($"x = {i};");
});

Performance Considerations

  1. Reuse instances when possible:
// Good - reuse runner for multiple calculations
var runner = new EverSharpRunner();
for (int i = 0; i < 1000; i++)
{
    runner.SetExternalVariable("value", i);
    var result = runner.RunExpression("value * 2");
}

// Less efficient - creating new instance each time
for (int i = 0; i < 1000; i++)
{
    var runner = new EverSharpRunner();  // New instance overhead
    var result = runner.RunExpression($"{i} * 2");
}
  1. Pre-compile scripts:
// Load and compile rules once
var runner = new EverSharpRunner();
runner.Run(complexRulesScript);  // Parse once

// Execute many times with different data
for (int i = 0; i < 1000; i++)
{
    runner.SetExternalVariable("input", i);
    var result = runner.RunExpression("processInput(input)");
}

See Also