Module: Jade::Runtime
Constant Summary collapse
- INTRINSICS =
{}
- IMPLEMENTATIONS =
{}
- IMPL_CACHE =
{}
- RECORD_CLASSES =
{}
Instance Method Summary collapse
- #boot! ⇒ Object
-
#curry(fn, arity) ⇒ Object
Hand-rolled currying for generated constructors.
-
#impl_for(interface_name, value) ⇒ Object
Cached per [interface_name, value.class]; ‘register_impl` invalidates.
- #intr(name) ⇒ Object
-
#record(*keys) ⇒ Object
Memoized class for anonymous record literals.
- #register(name, &block) ⇒ Object
- #register_impl(interface_name, ruby_class, functions) ⇒ Object
Methods included from Interop::Runtime
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 |