@@ -635,6 +635,31 @@ def validate_dsl(func):
635635 - ``dsl_source`` (str | None): extracted DSL source when valid
636636 - ``input_names`` (list[str] | None): input signature names when valid
637637 - ``error`` (str | None): user-facing error message when invalid
638+
639+ Examples
640+ --------
641+ >>> import blosc2
642+ >>> @blosc2.dsl_kernel
643+ ... def k(a, b):
644+ ... return a * a + b * b
645+ >>> info = blosc2.validate_dsl(k)
646+ >>> info["valid"]
647+ True
648+ >>> info["input_names"]
649+ ['a', 'b']
650+
651+ An unsupported construct is reported instead of raising:
652+
653+ >>> @blosc2.dsl_kernel
654+ ... def bad(a):
655+ ... return 1 if a > 0 else 0
656+ >>> blosc2.validate_dsl(bad)["valid"]
657+ False
658+
659+ See Also
660+ --------
661+ validate_dsl_jit : Additionally probe whether the kernel JIT-compiles (vs falls
662+ back to the interpreter) for given operand/output dtypes.
638663 """
639664
640665 kernel = func if isinstance (func , DSLKernel ) else DSLKernel (func )
@@ -647,6 +672,115 @@ def validate_dsl(func):
647672 }
648673
649674
675+ def validate_dsl_jit (func , operands , out_dtype , * , shape = (64 ,), chunks = None , blocks = None ):
676+ """Report whether a DSL kernel JIT-compiles (vs. interpreter fallback).
677+
678+ Compiles a tiny probe of the kernel for the given operand/output dtypes and
679+ queries miniexpr for whether it produced a runtime JIT kernel. The kernel is
680+ *not* run on real data, but compilation is dtype-specialized, so the operand and
681+ output dtypes must be supplied.
682+
683+ Parameters
684+ ----------
685+ func
686+ A Python callable or :class:`DSLKernel`.
687+ operands
688+ One spec per kernel input. A NumPy dtype (e.g. ``np.float64``, ``"f8"``)
689+ marks an *array* operand; a Python ``int``/``float``/``bool`` marks a *scalar*
690+ parameter inlined as a constant (as happens at run time). Either a dict
691+ mapping input name -> spec, or a sequence matched positionally to the inputs.
692+ out_dtype
693+ Output dtype to specialize the codegen for.
694+ shape
695+ Probe shape; ``len(shape)`` sets the kernel dimensionality (kernels using
696+ ``_i1`` etc. need a matching ndim). Defaults to ``(64,)``.
697+
698+ Returns
699+ -------
700+ dict
701+ - ``valid`` (bool): DSL syntax is valid
702+ - ``jit`` (bool): a runtime JIT kernel was produced (vs interpreter fallback)
703+ - ``compiled`` (bool): miniexpr accepted the kernel
704+ - ``status`` (str | None): miniexpr compile-status name
705+ - ``error`` (str | None): syntax error message when ``valid`` is False
706+
707+ Examples
708+ --------
709+ >>> import blosc2
710+ >>> import numpy as np
711+ >>> @blosc2.dsl_kernel
712+ ... def k(a, b):
713+ ... return a * a + b * b
714+ >>> status = blosc2.validate_dsl_jit(k, [np.float64, np.float64], np.float64)
715+ >>> status["jit"]
716+ True
717+ >>> status["status"]
718+ 'ME_COMPILE_SUCCESS'
719+
720+ Pass array operands as dtypes and scalar parameters as values (the scalar is
721+ inlined as a constant, as at run time):
722+
723+ >>> @blosc2.dsl_kernel
724+ ... def scaled(a, n):
725+ ... return a * float(n)
726+ >>> blosc2.validate_dsl_jit(scaled, {"a": np.float64, "n": 3}, np.float64)["jit"]
727+ True
728+
729+ See Also
730+ --------
731+ validate_dsl : Static DSL-syntax check only (no compilation; no dtypes needed).
732+ """
733+ import numpy as np
734+
735+ import blosc2
736+
737+ kernel = func if isinstance (func , DSLKernel ) else DSLKernel (func )
738+ if kernel .dsl_error is not None :
739+ return {
740+ "valid" : False ,
741+ "jit" : False ,
742+ "compiled" : False ,
743+ "status" : None ,
744+ "error" : str (kernel .dsl_error ),
745+ }
746+
747+ names = list (kernel .input_names or [])
748+ if isinstance (operands , dict ):
749+ specs = dict (operands )
750+ else :
751+ operands = list (operands )
752+ if len (operands ) != len (names ):
753+ raise ValueError (f"expected { len (names )} operand specs for inputs { names } , got { len (operands )} " )
754+ specs = dict (zip (names , operands , strict = True ))
755+
756+ scalars : dict = {}
757+ arrays : dict = {}
758+ for name in names :
759+ if name not in specs :
760+ raise ValueError (f"missing operand spec for input '{ name } '" )
761+ spec = specs [name ]
762+ if isinstance (spec , bool | int | float ):
763+ scalars [name ] = spec
764+ else :
765+ arrays [name ] = np .dtype (spec )
766+
767+ source = kernel .dsl_source
768+ if scalars :
769+ source , _ = specialize_miniexpr_inputs (source , scalars )
770+ if not arrays :
771+ raise ValueError (
772+ "validate_dsl_jit needs at least one array operand (pass a dtype spec); "
773+ "all-scalar probes are not supported"
774+ )
775+
776+ out = blosc2 .empty (shape , dtype = np .dtype (out_dtype ), chunks = chunks , blocks = blocks )
777+ probe_inputs = {name : np .empty (1 , dtype = dt ) for name , dt in arrays .items ()}
778+ status = out ._dsl_jit_status (source , probe_inputs )
779+ status ["valid" ] = True
780+ status ["error" ] = None
781+ return status
782+
783+
650784def kernel_from_source (source : str , name : str | None = None ) -> DSLKernel :
651785 """Reconstruct a :class:`DSLKernel` from its stored source text.
652786
0 commit comments