Skip to content

Commit f1bc4f4

Browse files
Dale-Blackclaude
andcommitted
Add callable_overrides for intercepting struct __call__ during compilation
Enables external callers (e.g., Therapy.jl) to override how callable struct types compile. Maps DataType → (receiver_js, args_js) → JS string. Also adds captured_vars parameter to compile() for direct closure compilation. Used by Therapy to map SignalGetter/SignalSetter calls to JS variable ops without compiling the server-side reactive plumbing. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
1 parent 7d7ed24 commit f1bc4f4

2 files changed

Lines changed: 28 additions & 0 deletions

File tree

src/compiler/codegen.jl

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -767,6 +767,20 @@ function compile_invoke(ctx::JSCompilationContext, expr::Expr)
767767
func_name = string(meth.name)
768768
call_args = [compile_value(ctx, a) for a in expr.args[3:end]]
769769

770+
# Callable overrides: intercept calls on overridden struct types
771+
# Used by Therapy.jl to map signal getter/setter calls to JS variable ops
772+
if !isempty(ctx.callable_overrides)
773+
sig_params = mi.specTypes.parameters
774+
if length(sig_params) >= 1
775+
receiver_type = sig_params[1]
776+
if receiver_type isa DataType && haskey(ctx.callable_overrides, receiver_type)
777+
override_fn = ctx.callable_overrides[receiver_type]
778+
receiver_js = compile_value(ctx, expr.args[2])
779+
return override_fn(receiver_js, call_args)
780+
end
781+
end
782+
end
783+
770784
# Known function mappings
771785
math_fns = Dict(
772786
"sin" => "Math.sin", "cos" => "Math.cos", "tan" => "Math.tan",
@@ -1073,6 +1087,7 @@ function compile_closure_creation(ctx::JSCompilationContext, T::DataType, captur
10731087
closure_ctx = JSCompilationContext(ci, closure_arg_types, rt, "")
10741088
closure_ctx.arg_names = closure_arg_names
10751089
closure_ctx.captured_vars = captured_vals
1090+
closure_ctx.callable_overrides = ctx.callable_overrides
10761091

10771092
# Compile the closure body
10781093
js_body = compile_function(closure_ctx)
@@ -1413,11 +1428,22 @@ function compile(f, arg_types::Tuple;
14131428
sourcemap::Bool=false,
14141429
dts::Bool=true,
14151430
func_name::Union{String, Nothing}=nothing,
1431+
captured_vars::Dict{Symbol, String}=Dict{Symbol, String}(),
1432+
callable_overrides::Dict{DataType, Function}=Dict{DataType, Function}(),
14161433
)
14171434
code_info, return_type = get_typed_ir(f, arg_types; optimize=optimize)
14181435
name = sanitize_js_name(something(func_name, string(nameof(f))))
14191436
ctx = JSCompilationContext(code_info, arg_types, return_type, name)
14201437

1438+
# Apply caller-provided captured_vars and callable_overrides
1439+
# (used for compiling closures directly, e.g., island event handlers)
1440+
if !isempty(captured_vars)
1441+
merge!(ctx.captured_vars, captured_vars)
1442+
end
1443+
if !isempty(callable_overrides)
1444+
merge!(ctx.callable_overrides, callable_overrides)
1445+
end
1446+
14211447
# Register struct types from function arguments (including Union members)
14221448
for T in arg_types
14231449
register_struct_types!(ctx, T)

src/compiler/types.jl

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@ mutable struct JSCompilationContext
2828
abstract_ranges::Dict{Type, Tuple{Int,Int}} # Abstract type → (lo, hi) range
2929
type_id_counter::Int
3030
required_runtime::Set{Symbol} # Runtime helpers needed by compiled code
31+
callable_overrides::Dict{DataType, Function} # Callable struct type → (recv_js, args_js) → JS
3132
end
3233

3334
function JSCompilationContext(code_info::Core.CodeInfo, arg_types::Tuple, return_type::Type, func_name::String)
@@ -61,6 +62,7 @@ function JSCompilationContext(code_info::Core.CodeInfo, arg_types::Tuple, return
6162
Dict{Type, Tuple{Int,Int}}(),
6263
0,
6364
Set{Symbol}(),
65+
Dict{DataType, Function}(),
6466
)
6567
end
6668

0 commit comments

Comments
 (0)