A high-performance, modular scripting foundation for Haxe. This library is designed to provide a robust environment for embedding scripting languages into Haxe applications, enabling dynamic behavior, sandboxed execution, and highly extensible architectures.
This project delivers a fully compliant, self-contained, and highly robust implementation of the Wren programming language in 100% pure Haxe with zero external dependencies.
digigun.scripting.hx is ideal for:
- Plugin Systems: Allow users to extend your application with custom logic without recompiling.
- Extension Systems: Build modular software where features can be hot-loaded at runtime.
- Runtime Generated GUI: Define and manipulate user interfaces dynamically through scriptable layouts.
- Game Logic: Decouple high-level game rules from the engine performance core.
- Sandbox Execution: Run untrusted or user-provided scripts safely within a controlled environment.
This library follows standard Haxelib conventions. To include it in your project, add it to your .hxml or project.xml:
-L digigun.scripting.hxFor local development/WIP access, you can link the repository:
haxelib dev digigun.scripting.hx path/to/repoAlternatively you can checkout the repo directly with Haxelib:
haxelib git digigun.scripting.hx https://github.com/Igazine/digigun.scripting.hxThe library provides a set of common abstractions for:
- AST-based Interpretation: Clean separation between parsing and execution.
- Foreign Function Interface (FFI): Seamlessly bind Haxe classes and methods to the scripting environment.
- Module Resolution: Configurable loading systems for handling multi-file script projects.
- Transparent Scoping: Robust handling of locals and globals across different execution frames.
The first fully-featured scripting engine implemented in this library is Wren—a small, fast, class-based concurrent scripting language (https://wren.io/).
Note
Wren is a lightweight, fast, and embeddable scripting language with a simple syntax and a focus on performance. It is a great choice for embedding into Haxe applications due to its small footprint and ease of integration. It also lacks the quirks of other scripting languages (eg. ECMAScript or even TypeScript) which makes it a perfect candidate for a scripting foundation as it avoids many of the pitfalls of its more well-known cousins. Although Wren's syntax is different, conceptually it builds on very similar principles and foundations as Haxe, so Haxe developers can feel immediately at home with its clean, modern syntax.
Important
This implementation utilizes a high-level AST-based Interpreter model rather than a Bytecode JIT or AOT compilation. While this ensures maximum compatibility across all Haxe targets (including HashLink, JavaScript, and C++), it introduces certain performance caveats:
- Overhead: Every script operation involves AST traversal and dynamic dispatch, which is slower than native Haxe code or low-level bytecode VMs.
- Target Logic: This library is designed for high-level orchestration, plugin logic, and UI definitions. It is not recommended for performance-critical inner loops or core engine logic where microsecond latency is required.
- Memory: Interpretation involves more object allocations for frames and expressions compared to compiled models.
Use this library to bring flexibility to your app, but keep your heavy lifting in native Haxe.
import wren.Wren;
class Main {
static function main() {
var vm = new Wren();
// Basic execution
vm.interpret("System.print(\"Hello from Wren!\")");
// Binding a foreign method
vm.bindForeignMethod("MyClass", "myMethod", true, 0, (args) -> {
trace("Haxe method called!");
return 42;
});
}
}To support modular pluggable engine components, digigun.scripting.hx introduces a powerful runtime Traits & Interfaces model, natively integrated with Wren's dynamic is operator check:
// 1. Declare an Interface contract
class IGreetable {
greet() { Fiber.abort("Must implement greet()") }
}
// 2. Declare a Trait (Mixin) providing shared behavior
class GreetableTrait {
sayHello() {
System.print("Hello " + name)
}
}
class Person {
construct new(name) {
_name = name
}
name { _name }
greet() {
System.print("Hi, I am " + name)
}
}
// Dynamically mix in the trait
Person.mixin(GreetableTrait)
// Enforce the IGreetable interface contract
Person.implements(IGreetable)
var p = Person.new("Alice")
p.greet() // Hi, I am Alice
p.sayHello() // Hello Alice
// The dynamic "is" type-checking check is fully recursively interface-aware!
System.print(p is Person) // true
System.print(p is IGreetable) // trueAny syntax or runtime error automatically collects and generates a highly-detailed multi-line stack trace from the origin of the execution context to the script root:
[line 3] Runtime Error: Method nonExistent() not found on String.
[line 3, col 6] in call
[line 1, col 17] in call
[line 1, col 1] in script
ListUtilities: Added pure Wren fast in-placesort()andsort(comparator)algorithms alongside instantfirstandlastelement getters.MathUtilities: Added pure staticMath.clamp(value, min, max)andMath.lerp(a, b, t)methods.
- Full Class & Inheritance model (with base constructor inheritance)
- Implicit
thisresolution - Property Getters & Setters (with scoping rules resolving local assignments correctly)
- Foreign Class & Method FFI bindings
- Foreign subscript bindings (
[]and[]=) for lists, maps, and classes - Short-circuiting Logic (
&&,||) and Ternary Operator (? :) - Stateful loop redirection (
breakandcontinuewith automatic stack unwinding) - Module System (
import) - String Slicing & Interpolation
- Fibers & Asymmetric Cooperative Multitasking (
Fiber.new,suspend,yield,transfer,try()) - Standard Library (List, Map, String, Num, Bool, Null, System, Math, Range)
- Loom Traits & Interfaces (
Class.mixin&Class.implements)
We verify the compiler engine specifications through the unified TestRunner suite, yielding 100% pass rates across core environments.
To execute tests on the Haxe Eval target:
haxe -L digigun.scripting.hx -cp test --run wren.TestRunnerTo execute tests on the JavaScript / Node.js target:
haxe -L digigun.scripting.hx -cp test/wren -main TestWren -js bin/test_wren.js && node bin/test_wren.jsPart of the Digigun ecosystem. Licensed under the MIT License.