Cr-Wren: a binding to the Wren language

A binding to wren, a small, fast, class-based, concurrent scripting language.

The main goal is to make this binding as comfortable and easy to use as possible, and allow Crystal developers to make apps extensible using a nice, readable language.

The current status of the binding is that it works but it’s of course not very well testedm and you can find it at

Here is an example of creating a Wren VM and calling Wren code from Crystal and viceversa:

require "../src/"

vm = "myvm"

# We can just tell the VM to interpret (run) code
vm.interpret "main", "System.print(\"Hello World!\")"

# This defines a function in Wren
vm.interpret "main", %(
  var add = { |a,b|
    return a+b

# And we can call it from Crystal
puts"main", "add", "call", [1, 2])     # => 3.0
puts"main", "add", "call", ["1", "2"]) # => "12"

# This fails with a runtime error even when the equivalent Wren code works
# probably a bug somewhere
# puts"main", "add", "call", [[1, 2], [3, 4]]) # => [1,2,3,4]

# Register a Crystal proc to add floats into the Wren VM
  "main", "Math", "add",
  Wren::VM.wrap("myvm", ->(a : Float64, b : Float64) : Float64 {
    a + b

# Register a proc to add 3 floats. We can register the same proc more than
# once with the same name and different arity
  "main", "Math", "add",
  Wren::VM.wrap("myvm", ->(a : Float64, b : Float64, c : Float64) : Float64 {
    a + b + c

# We also need to declare it as "foreign" in Wren.
vm.interpret "main", %(
  class Math {
    foreign static add(a,b)
    foreign static add(a,b,c)

# And we can call it on Wren, which will use the Crystal code
vm.interpret "main", %(
  // We can pass a string as argument here because cr-wren will cast it to Float64
) # 2+3.5=5.5  ¨1"+2+3=6


Is the repository still private? I couldn’t access it.

I also wrote bindings but ran into memory issues that I never solved unfortunately.

Oops, my bad, fixed I never intended for it to be private :slight_smile:

I didn’t even try binding foreign classes, I am guessing that’s where you ran into the memory issues?

Just as a FYI, this is all it takes to give Crinja user-defined filters using Wren:

  vm = "vm"
  # Filters defined in Wren in template_extensions/filters/*.wren
  Dir.glob("template_extensions/filters/*.wren").each do |f|
    filter_name = Path[f].stem
    if !Env.filters.has_key? filter_name
      filter_code =
      vm.interpret filter_name, filter_code

      Env.filters[filter_name] = Crinja.filter() do
        args = [target.to_s] + arguments.to_h.keys.sort!.map { |k| arguments[k].to_s}
        p! args, arguments.kwargs
        r =, "filter", "call", args).to_s

And then the user can do things like

var filter = { |target, greeting, is_super|
  var result = ""
  if (is_super=="true") {
    result = "Super "
  return result + greeting + " " + target
1 Like