Module: Jade::Runtime

Extended by:
Interop::Runtime, Runtime
Included in:
Runtime
Defined in:
lib/jade/runtime.rb

Constant Summary collapse

INTRINSICS =
{}
IMPLEMENTATIONS =
{}
IMPL_CACHE =
{}
RECORD_CLASSES =
{}

Instance Method Summary collapse

Methods included from Interop::Runtime

task_call

Instance Method Details

#boot!Object



77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
# File 'lib/jade/runtime.rb', line 77

def boot!
  return if @booted
  @booted = true

  require "jade/stdlib/basics"
  require "jade/stdlib/string"
  require "jade/stdlib/list"
  require "jade/stdlib/tuple"
  require "jade/stdlib/task"
  require "jade/stdlib/decode"
  require "jade/stdlib/encode"
  require "jade/stdlib/bytes"
  require "jade/stdlib/dict"
  require "jade/stdlib/set"
end

#curry(fn, arity) ⇒ Object

Hand-rolled currying for generated constructors. Ruby’s Method#curry corrupts the heap under GC compaction (the GC marks a T_NONE object while a curried call is in flight) when a curried proc is built once and called repeatedly — which is exactly the decoder applicative path (Decode.succeed(Ctor.curry(n)) threaded through Decode.and_map). Plain procs accumulating into an Array are GC-safe.



104
105
106
107
108
109
110
111
112
113
114
115
# File 'lib/jade/runtime.rb', line 104

def curry(fn, arity)
  return fn if arity <= 1

  build = ->(acc) {
    ->(*xs) {
      (acc + xs).then do |args|
        args.length >= arity ? fn.call(*args) : build.call(args)
      end
    }
  }
  build.call([])
end

#impl_for(interface_name, value) ⇒ Object

Cached per [interface_name, value.class]; ‘register_impl` invalidates.



135
136
137
138
139
140
141
142
143
144
# File 'lib/jade/runtime.rb', line 135

def impl_for(interface_name, value)
  boot!
  key = [interface_name, value.class]
  IMPL_CACHE[key] ||= begin
    raw = IMPLEMENTATIONS[key] || fail("No implementation of #{interface_name} for #{value.class}")
    raw.any? { |_, v| v.is_a?(::String) } \
      ? raw.transform_values { |v| v.is_a?(::String) ? intr(v) : v }
      : raw
  end
end

#intr(name) ⇒ Object



93
94
95
96
# File 'lib/jade/runtime.rb', line 93

def intr(name)
  boot!
  INTRINSICS[name] || fail("Intrinsic #{name} does not exist")
end

#record(*keys) ⇒ Object

Memoized class for anonymous record literals. Without this, every ‘1, b: 2` expression evaluated in a hot loop would call `Data.define(:a, :b)` and allocate a fresh anonymous class, defeating YJIT’s inline cache on every subsequent property access.



125
126
127
# File 'lib/jade/runtime.rb', line 125

def record(*keys)
  RECORD_CLASSES[keys] ||= Data.define(*keys)
end

#register(name, &block) ⇒ Object



117
118
119
# File 'lib/jade/runtime.rb', line 117

def register(name, &block)
  INTRINSICS[name] = block
end

#register_impl(interface_name, ruby_class, functions) ⇒ Object



129
130
131
132
# File 'lib/jade/runtime.rb', line 129

def register_impl(interface_name, ruby_class, functions)
  IMPLEMENTATIONS[[interface_name, ruby_class]] = functions
  IMPL_CACHE.clear
end