Skip to content

API Reference

Model Definition

StanBlocks.@slic Macro

Defines SlicModels (see test/slic.jl for usage examples).

The defining module is captured automatically via __module__, so that @deffun functions defined in the same module (e.g. a package extension) are found during symbol resolution.

A leading string literal inside the begin ... end block is captured as the model docstring and rendered as a // ... comment header in the generated Stan code.

source
StanBlocks.@deffun Macro
julia
@deffun function_definition

Define a Stan-compatible function with type inference and Stan code generation.

Parses a Julia-style function definition (with type-annotated arguments and return type), generates the corresponding Stan function, and registers type-inference signatures so the transpiler can propagate types through calls to this function. Definitions are Stan-only by default. Add @juliacompat to an eligible bodyful bare-symbol definition to install one callable Julia method from the original user-facing definition as well. Signature-only/type- token glue, qualified or pre-existing function extensions, and definitions whose own name is in the probability/RNG/ODE/reduce_sum family (*_lpdf, *_lpmf, *_lcdf, *_lccdf, *_cdf, *_rng, the elementwise *_lpdfs/*_lpmfs/… companions, and ode_*) remain Stan-only even when annotated.

The opt-in Julia target is a bounded deterministic compatibility layer: supported signatures, symbolic dimension checks, typed locals, control flow/mutation, nested deterministic calls, higher-order arguments, and varargs. In a @juliacompat definition, a direct probability/RNG/ODE/reduce_sum primitive call errors at expansion time. Remove the annotation when the definition is intentionally Stan-only. A probability-family definition is outside the layer by construction and gets no Julia method.

For functions ending in _lpdf/_lpmf/_lcdf/_lccdf, the return type is automatically set to real and companion _lpdfs/_rng stubs are generated for use in generated_quantities.

UDF bodies must not contain ~ sampling statements or target += increments — UDFs cannot introduce parameters or directly manipulate the log density. The macro errors at expansion time if either is found.

Standard Julia macros inside the body are expanded against the calling module before tracing, so @views, @., @inbounds, and user-defined macros work transparently.

Inlining

Annotating with @inline (or giving the function a Julia-convention trailing ! in its name) causes every call to be expanded at the call site instead of producing a Stan function:

julia
@deffun @inline scale(x::vector[n], s::real)::vector[n] = x * s
@deffun set_first!(buf::vector[n])::vector[n] = (buf[1] = 42.; buf)

Inline UDFs do not appear in Stan's functions {} block. Multi-statement bodies, vararg parameters, and higher-order function arguments are all supported. Locals are renamed per call site, and pre-statements hoist into the enclosing block.

@inline cannot be combined with @lhs / @lpxf.

Example

julia
@deffun garch11_lpdf(y::vector[T], mu::real, alpha0::real, alpha1::real, beta1::real)::real = begin
    sigma2 = alpha0
    rv = 0.
    for t in 1:T
        rv += normal_lpdf(y[t], mu, sqrt(sigma2))
        sigma2 = alpha0 + alpha1 * square(y[t] - mu) + beta1 * sigma2
    end
    return rv
end

See src/slic_stan/builtin.jl for many more examples.

source
StanBlocks.@juliacompat Macro
julia
@juliacompat definition

Opt an eligible bodyful @deffun definition into the bounded deterministic Julia compatibility target while retaining the same SLIC/Stan lowering:

julia
@deffun @juliacompat affine(x::real, a::real)::real = a * x + 1.0

It may wrap one definition or a begin ... end group inside @deffun. Signature-only/type-token glue, qualified or pre-existing function extensions, and probability/RNG/ODE/reduce_sum-family definitions remain Stan-only. Within a @juliacompat begin ... end group, a nested @stanonly definition explicitly opts that member back out.

source
StanBlocks.@stanonly Macro
julia
@stanonly definition

Explicitly mark a @deffun definition as Stan-only. This is the default, so the annotation is normally optional; it remains useful as documentation and to opt one member out of a surrounding @juliacompat begin ... end group:

julia
@deffun @stanonly foo_rng(x::real)::real = stan_rng_primitive(x)

It may wrap one definition or a begin ... end group inside @deffun.

source
StanBlocks.@defsig Macro

Utility macro to define function signatures (see src/slic_stan/builtin.jl for usage examples).

Note:

This macro is mainly useful for bulk built-in function signature definitions. StanBlocks.jl users should generally prefer using @deffun.

source
StanBlocks.@usertype Macro
julia
@usertype struct RaggedVector
    mem  :: vector
    ends :: int[]
end

Declare a custom Stan-renderable record type. Lowers to a real Julia struct whose abstract supertype is StanBlocks.stan.types.usertype (added automatically); field type annotations are SLIC types and are kept only for documentation — fields are stored as Any so plain Julia construction works for data plumbing. Method dispatch on the type tag (Base.length(r::RaggedVector)) works via standard Julia. Stan-side, values render as positional tuples; field access (r.mem) reuses the existing ntup machinery.

source

Sampling-form Dispatch

StanBlocks.@lpxf Macro
julia
@lpxf foo_lpdf
@lpxf begin foo_lpdf; bar_lpmf end

Register the three SLIC dispatch hooks (lpxf_expr, rng_expr, likelihood_expr) for one or more user-defined log-probability functions.

The argument(s) must be bare symbols ending in _lpdf, _lpmf, _lcdf, or _lccdf. For each foo_lpdf (or _lpmf/etc.), the macro emits the registrations:

julia
StanBlocks.lpxf_expr(::typeof(foo))       = foo_lpdf
StanBlocks.rng_expr(::typeof(foo))        = foo_rng
StanBlocks.likelihood_expr(::typeof(foo)) = foo_lpdfs

The companion foo_rng and foo_lpdfs (resp. _lpmfs/_lcdfs/_lccdfs) names must already exist when the registrations execute. This macro does not parse function bodies and does not wrap @deffun.

source
StanBlocks.@lhs Macro
julia
@lhs foo_lpdf(y::T, args...) = body

Inside a @deffun block, opt this method into base-level LHS inference. Without @lhs, only the _lpdf-keyed tracetype is registered (so the method dispatches when called explicitly), but lhs ~ foo(args...) cannot trace because the base foo has no tracetype keyed on its argument signature. @lhs registers tracetype(::CanonicalExpr{<:typeof(foo), <:Tuple{lhs_type[2:end]...}}) so the sampling form works.

Compose with @lpxf (any order — @lhs @lpxf … or @lpxf @lhs …) to also register the dispatch hooks for foo/foo_rng/foo_lpdfs.

Standalone @lhs (outside @deffun) is not supported and errors immediately.

source

Runtime Assertions

StanBlocks.@stan_assert Macro
julia
@stan_assert cond
@stan_assert cond message

Stan-compatible runtime assertion. Expands to if !cond; reject(msg); end, where Stan's reject aborts the current MCMC proposal with the message. Without an explicit message, a default "assertion failed: <cond>" is used.

Use inside @deffun bodies (control flow is not allowed in @slic model bodies — wrap the check in a helper if needed at the model level).

Example

julia
@deffun safe_log(x::real)::real = begin
    @stan_assert x > 0 "safe_log: argument must be positive"
    return log(x)
end
source

Model Inspection and Compilation

StanBlocks.return_type_of Function
julia
return_type_of(f, args...) -> StanType

Infer the Stan return type and shape of a SLIC-callable function for the given representative Julia arguments. The result is the same StanType used by the transpiler and prints as Stan syntax, for example real, vector[3], or matrix[2, 4].

Inside an @deffun body, return_type_of(f, args...) is a transpile-time type token and may be used in a computed type annotation:

julia
@deffun element_type(x::real)::real = x
@deffun copy_like(x::vector[n]) = begin
    out::return_type_of(element_type, x[1])[n]
    for i in 1:n
        out[i] = x[i]
    end
    out
end

The query is intentionally bounded to non-inline @deffun functions and @defsig-registered SLIC callables whose result is a scalar or sized Stan container. Inline functions, closures, sub-models, arbitrary Julia functions, and tuple/user-defined-type results require a full call-site trace and are not queryable through this API. Inside a UDF, spell symbolic output dimensions explicitly (return_type_of(f, x)[n]) when they are already bound by the surrounding signature.

source
StanBlocks.compile_slic_bundle Function
julia
compile_slic_bundle(data, definitions, body;
    udf_definitions=(), anonymous_submodels=(), name=nothing)

Compile an ordered collection of @deffun UDF definitions, named SLIC sub-model definitions, anonymous sub-model dependencies, and one parent SLIC model body. Each udf_definitions value is either an expression accepted by @deffun or a named tuple with a required definition expression plus optional markers and assertions. definitions contains expressions shaped like f(args...) = begin ... end (without an outer @slic macro call); anonymous_submodels contains name => body_or_value pairs, where name is the Symbol used by the parent and the value is either an anonymous SLIC body expression (without an outer @slic) or an existing SlicModel; and body is the parent model expression. UDFs are installed first in their supplied order, then named SLIC definitions, then anonymous dependencies, in a fresh module. The parent is traced exactly once in that same module.

Structured UDF metadata is the macro-free spelling of trusted compiler-owned annotations. markers accepts one Symbol or a tuple/vector drawn from :stanonly, :juliacompat, :lhs, :lpxf, and :inline; :inline cannot be combined with :lhs or :lpxf. assertions is a tuple/vector of named tuples with a condition AST and optional string message. Assertions are prepended to one bodyful definition with the semantics of @stan_assert. Unknown fields, markers, duplicates, and malformed assertions fail before evaluation.

Each UDF or SLIC definition, and the parent body, may be written as either a bare expression or source_part => expression, where source_part is a Symbol or string. Labeled parts preserve that identity in diagnostic results. Bare expressions retain the legacy source-location behavior, with slic_bundle used when the expression has no source file.

Each anonymous dependency is either name => body_or_value or source_part => (name => body_or_value). A body expression is expanded by @slic inside the owned workspace, so it sees the bundle's earlier definitions without caller-side Core.eval. An existing SlicModel keeps its original defining module. In both forms the parent refers to the dependency by name, and repeated calls keep ordinary anonymous-submodel kwarg binding and hygienic LHS namespaces.

The result is a named tuple with:

This is an integration boundary for already-parsed, trusted SLIC expressions. It does not parse or sandbox source, and it deliberately preserves @slic's macro-expansion semantics: macros inside a supplied expression can execute Julia code during expansion. Validate untrusted source before calling this function and isolate its execution when it comes from an anonymous user.

Example

julia
definitions = [:(latent(scale) = begin
    z ~ normal(shift_zero(0.0), scale)
    return z
end)]
anonymous_submodels = ["local-prior" => (:local_prior => quote
    z ~ normal(location, scale)
    return z
end)]
udf_definitions = ["shift-zero" => :(shift_zero(x::real)::real = begin
    x + 0.25
end), "safe-log" => (;
    definition=:(safe_log(x::real)::real = begin
        log(x)
    end),
    markers=:stanonly,
    assertions=((;
        condition=:(x > 0),
        message="safe_log: x must be positive",
    ),),
)]
body = "parent" => quote
    mu ~ latent(1.0)
    offset ~ local_prior(; location=0.0, scale=1.0)
    y ~ normal(mu + offset, 1.0)
end

result = compile_slic_bundle((; y=[0.1, -0.2]), definitions, body;
    udf_definitions, anonymous_submodels, name=:hierarchical)
result.code
result.descriptor.inputs
source
StanBlocks.stan_code Function
julia
stan_code(model) -> String

Return the generated Stan source for model (a SlicModel or StanModel) as a plain String. This is the intentional source-inspection API: ordinary terminal, Markdown, and HTML display shows a semantic model summary and never calls this function automatically.

For a SlicModel, tracing runs first via stan_model; for an already-traced StanModel, only the rendering pass runs. Output covers the full Stan program — data, transformed_data, parameters, transformed_parameters, model, and generated_quantities blocks — with automatic block placement applied.

Pair with transpiles for boolean smoke tests and stan_instantiate to compile the generated code via BridgeStan.

source
StanBlocks.stan_model Function
julia
stan_model(slic::SlicModel) -> StanModel

Trace slic end-to-end (forward / backward / distribute passes), returning the inferred StanModel — a fully resolved representation of the Stan blocks plus the data dictionary.

Tracing is the expensive step. A StanModel is cheap to re-data: call model(; new_kwargs...) to swap the data dict without re-tracing. Use this in preference to repeatedly calling stan_instantiate on the original SlicModel.

Errors during tracing are wrapped in a StanBlocksError tagged with phase = :transpile.

source
StanBlocks.stan_instantiate Function
julia
stan_instantiate(model; kwargs...) -> StanProblem

Exported alias for StanBlocks.instantiate. Compiles model (a SlicModel or StanModel) via BridgeStan and returns a StanLogDensityProblems.StanProblem implementing the LogDensityProblems interface. See instantiate for the full kwarg list.

source
StanBlocks.instantiate Function
julia
instantiate(model; nan_on_error=true, make_args=["STAN_THREADS=true"], warn=false, path=…) -> StanProblem
stan_instantiate(model; ...) -> StanProblem

Compile model (a SlicModel or StanModel) via BridgeStan and return a StanLogDensityProblems.StanProblem. The returned value implements the LogDensityProblems interface — call LogDensityProblems.dimension, logdensity, and logdensity_and_gradient on it.

stan_instantiate is an exported alias for instantiate.

Keyword arguments

  • path::AbstractString — where to write the .stan file. Defaults to "tmp/<hash>.stan", so identical generated code is cached on disk.

  • nan_on_error::Bool = true — make BridgeStan return NaN instead of throwing on evaluation failures.

  • make_args::Vector{String} = ["STAN_THREADS=true"] — extra arguments forwarded to Stan's make.

  • warn::Bool = false — forwarded to BridgeStan.

Errors during compilation are wrapped in a StanBlocksError tagged with phase = :compile.

source

Model Descriptors

StanBlocks.stan_descriptor Function
julia
stan_descriptor(model; name=nothing) -> ModelDescriptor

Reflect model (a SlicModel or an already-traced StanModel) as one descriptor-bearing, executable declaration: stable identity, inputs, outputs with their generative semantics, included Stan definitions, and the operations DERIVED from them.

A SlicModel is traced first (via stan_model); prefer passing a StanModel when reflecting the same model repeatedly, since tracing is the expensive step.

name overrides the model's own (gensym'd, for an anonymous @slic begin … end) name. It is informational — id is derived from the generated Stan source, not from the name.

Derived operations

Nothing here is a hand-maintained list; each operation appears exactly when the traced model supports it.

operationoffered when
:transpilealways
:instantiatealways (fails loudly at run time if a required input is unbound)
:fitthe model has ≥1 parameter and ≥1 likelihood term — i.e. a non-held-out observation reaches the model block. A pure prior-predictive model, or one whose every observation is cv-held-out, offers no :fit
:predict≥1 output with generative == :draw
:pointwise_loglik≥1 output with generative == :pointwise_loglik

Ask for one with stan_operation and run it with stan_execute; both fail closed on an operation the model does not offer.

Example

julia
m = @slic begin
    sigma ~ exponential(1.)
    mu ~ normal(0., 10.)
    y ~ normal(mu, sigma)
end (; y)

d = stan_descriptor(m; name=:simple)
d.id                                        # "…" — stable, content-derived
required_inputs(d)                          # (:y,) — not the derived size `y_n`
[i.name for i in d.inputs if i.observed]    # [:y]
[o.name for o in d.outputs if o.generative == :draw]   # [:y_gen]
[f.name for f in d.definitions]             # emitted `functions` inventory
[op.name for op in d.operations]            # [:transpile, :instantiate, :fit, :predict, :pointwise_loglik]

stan_execute(d, :transpile)                 # the Stan source
prob = stan_execute(d, :fit)                # a BridgeStan-backed StanProblem
stan_execute(d, :predict; problem=prob, draws=theta_unc, seed=1)   # (; y_gen = […])

See also stan_operation, stan_execute, stan_definition, stan_definition_closure, required_inputs.

source
StanBlocks.required_inputs Function
julia
required_inputs(d::ModelDescriptor) -> Tuple{Vararg{Symbol}}

The input names a consumer must actually supply — every input that is neither inlined (folded into the generated source; it never reaches the data JSON) nor derived (another input's declared size, re-derived when that container is re-bound). This is the set a generated form should collect, and it is what each operation's inputs field reports.

The data block itself is wider than this: d.inputs also carries the derived sizes, so a consumer that wants the full JSON payload can still see them.

source
StanBlocks.stan_definition Function
julia
stan_definition(d::ModelDescriptor, name; signature=nothing) -> ModelDefinition

Look up one included Stan definition by its exact emitted name (a Symbol or string). The lookup fails closed when the name is absent. If valid Stan overloads make the emitted name ambiguous, it also fails closed and lists the available signatures; pass one back via signature= to select exactly.

source
StanBlocks.stan_definition_closure Function
julia
stan_definition_closure(d::ModelDescriptor, selected...) -> Tuple{Vararg{ModelDefinition}}

Select one or more emitted definition names (or ModelDefinition values) and return them with their complete transitive included-definition dependencies. The result preserves d.definitions' authoritative functions-block order. Name selection uses stan_definition, so an absent or overloaded-ambiguous name fails closed rather than returning a non-executable fragment.

source
StanBlocks.stan_operation Function
julia
stan_operation(d::ModelDescriptor, name::Symbol) -> ModelOperation

The operation name of descriptor d, or a loud error naming the operations d actually offers.

Fails closed by design: which operations exist is DERIVED from the model (see stan_descriptor), so asking for one the model does not support is a statement about the model — a prior-predictive model has no :fit, a model with no _gen twin has no :predict — and silently returning nothing would push that discovery into the consumer.

source
StanBlocks.stan_execute Function
julia
stan_execute(d::ModelDescriptor, name::Symbol; kwargs...)

Run operation name of descriptor d. Errors loudly if d does not offer it (see stan_operation).

Per-operation contract

  • :transpileString. Takes no keyword arguments.

  • :instantiate, :fit → a StanLogDensityProblems.StanProblem implementing the LogDensityProblems interface. Data keyword arguments re-bind inputs before compiling (stan_execute(d, :fit; y=newy)); reserved instantiate keywords (path, nan_on_error, make_args, warn) are forwarded to it. Refuses, naming them, if any required input is still unbound.

  • :predict, :pointwise_loglik → a NamedTuple mapping each of the operation's outputs to its drawn values. Required keyword arguments:

    • draws — one unconstrained parameter vector (Vector{Float64}), or a Matrix whose COLUMNS are such vectors, or a vector of them.

    • seed::Int — seeds BridgeStan's RNG for the generated-quantities draw.

    Optional: problem — a StanProblem from a previous :fit / :instantiate, to skip recompilation. Any other keyword argument is forwarded to the compilation step exactly as for :fit. For a single draw each entry is a Vector{Float64} (length 1 for a scalar output); for several, a Matrix with one column per draw.

source
StanBlocks.ModelDescriptor Type
julia
ModelDescriptor

The reflectable, executable declaration of one Stan model — the value returned by stan_descriptor.

Fields

  • id::String — stable identity, derived from the generated Stan source (the same key instantiate caches the compiled artifact under). Two models with byte-identical Stan share an id; changing the model changes it. Independent of the process, of tracing order, and of the gensym'd name.

  • name::Symbol — the model's name. Informational only — @slic begin … end produces a gensym; pass name= to stan_descriptor to set it.

  • docstring::String — the model's leading docstring, if any.

  • model::StanModel — the traced model the descriptor reflects.

  • inputs::Tuple{Vararg{ModelInput}}

  • outputs::Tuple{Vararg{ModelOutput}}

  • definitions::Tuple{Vararg{ModelDefinition}} — included Stan definitions in the exact order used by the functions block emitter.

  • operations::Tuple{Vararg{ModelOperation}}

source
StanBlocks.ModelInput Type
julia
ModelInput

One entry of a descriptor's data block — see stan_descriptor.

Fields

  • name::Symbol — the Stan data variable name.

  • type::Symbol — the declared Stan center type (:real, :int, :vector, :matrix, :simplex, …).

  • size::Tuple — the declared size expressions, outermost first. Entries are emitted expressions: a literal, a Symbol naming another input, or a larger expression. Resolve a symbolic entry against the other inputs' value.

  • constraints::NamedTuple — the lower/upper/offset/multiplier subset actually spelled on the declaration. Empty does not mean unconstrained: a natively constrained center (simplex, cholesky_factor_corr, …) carries its support in type.

  • value — the bound Julia value. Always present: a symbol with no value never reaches the data block (an unresolvable one fails at tracing time, not here).

  • inlined::Booltrue for a value the emitter folds into the generated source rather than passing as data (functions, closures, 0-dim type tokens).

  • derived::Booltrue when this input is another input's declared size (y_n for vector[y_n] y). Re-binding the container re-derives it, so a consumer must never ask for it separately. Neither an inlined nor a derived input is part of required_inputs, and neither belongs in a generated form.

  • observed::Bool — this variable appears on the left of a ~ (it is data the model conditions on), as opposed to a covariate or a size.

  • held_out::Bool — the cross-validation flag: this variable's likelihood contribution is dropped and it re-draws in generated quantities. Contagion- aware, not a record of what you marked — cv propagates through every expression it reaches, so marking one input via StanBlocks.stan.maybecv can make several inputs report held_out.

source
StanBlocks.ModelOutput Type
julia
ModelOutput

One quantity the model produces — see stan_descriptor.

Fields

  • name::Symbol — the Stan variable name (matches BridgeStan's param_names prefix; a container appears there as name.1, name.2, …).

  • kind::Symbol — which Stan block declares it: :parameter, :transformed_parameter, or :generated_quantity.

  • type::Symbol, size::Tuple, constraints::NamedTuple — as for ModelInput.

  • generative::Symbol — what the quantity MEANS:

    • :posterior — a sampled parameter or a deterministic function of one.

    • :draw — a predictive draw of an observation (the compiler-owned <obs>_gen twin). source names the observation.

    • :pointwise_loglik — the per-element log-likelihood of an observation (the compiler-owned <obs>_likelihood companion). source names it.

    • :derived — any other generated quantity: a prior-only sample, a cv-flipped re-draw of a latent, a model return value.

  • source::Union{Symbol,Nothing} — the observation a :draw / :pointwise_loglik derives from; nothing otherwise.

  • segments::Union{Nothing,Vector{Int}} — group boundaries when this quantity is either the twin of a ragged observation or the emitted flat-memory carrier of a ragged plate result/member; nothing for every dense quantity. The entries are the carrier's own inclusive 1-based end indices, so group g of a flat carrier or :draw occupies segments[g-1]+1 : segments[g] (with segments[0] ≡ 0), while group g of a :pointwise_loglik is element g. Each ragged plate member reports its own layout; members may have different axes, so consumers must not copy segments from a sibling or an input. Publishing the layout here lets consumers restore groups without reaching into compiler-owned names or carrier tuples.

source
StanBlocks.ModelDefinition Type
julia
ModelDefinition

One included definition in a model's emitted Stan functions block — see stan_descriptor, stan_definition, and stan_definition_closure.

The descriptor is projected from the traced functions dictionary that the emitter itself prints. It is not reconstructed by parsing generated Stan.

Fields

  • name::Symbol — the exact emitted Stan callable name. This is the stable public lookup key and preserves leading underscores.

  • binding::Union{Symbol,Nothing} — the author-side Julia binding when there is one. It can differ from name when StanBlocks specialises or renames a helper; compiler-lifted closures have no author binding and report nothing.

  • kind::Symbol:function or :closure.

  • signature::String — the exact emitted return/name/argument signature, normalized onto one line. It distinguishes valid Stan overloads that share one name.

  • source::String — the complete emitted definition, without the surrounding functions {} block.

  • span::UnitRange{Int} — the string-index range of source in stan_code(descriptor.model), so SubString(code, first(span), last(span)) == source.

  • dependencies::Tuple{Vararg{Symbol}} — direct included-definition names in first-use order.

  • dependency_signatures::Tuple{Vararg{String}} — exact dependency links, aligned with dependencies; these remain unambiguous when Stan overloads share a name.

source
StanBlocks.ModelOperation Type
julia
ModelOperation

One executable operation DERIVED from a model declaration — never a consumer-maintained entry. See stan_descriptor for the derivation rules and stan_execute to run one.

Fields

  • name::Symbol:transpile, :instantiate, :fit, :predict, or :pointwise_loglik.

  • title::String — a human label a UI can render without a lookup table.

  • inputs::Tuple{Vararg{Symbol}} — descriptor input names this operation consumes (empty for :transpile, which needs no data).

  • outputs::Tuple{Vararg{Symbol}} — descriptor output names it produces.

  • run — the executor, called as run(descriptor; kwargs...).

source

Smoke Tests

StanBlocks.transpiles Function
julia
transpiles(model; re=true) -> Bool

Return true if model (a SlicModel or StanModel) successfully transpiles to Stan source via stan_code, false otherwise.

This is the fast smoke-test for a model — it exercises the full SLIC tracing pipeline but stops short of invoking stanc / BridgeStan.

Set re=false to swallow the transpilation error and just return false (useful for batch regression dashboards); the default re=true rethrows so failures surface with their normal StanBlocksError trace.

source
StanBlocks.compiles Function
julia
compiles(model; re=true) -> Bool

Return true if model (a SlicModel or StanModel) successfully transpiles and compiles via BridgeStan (i.e. stan_instantiate succeeds), false otherwise.

Strictly stronger than transpiles: a model that transpiles can still fail to compile if stanc rejects the generated Stan or the C++ build fails.

Set re=false to swallow the error and just return false; the default re=true rethrows.

source
StanBlocks.stanc_check Function
julia
stanc_check(stan_code::AbstractString; warn_pedantic=true) -> (ok::Bool, output::String)

Run the stanc compiler on stan_code (written to a temporary file) and return whether it accepted the code plus any compiler output (warnings, errors). Binary discovery: $STANC_PATH env var → BridgeStan's bin/stanc. Errors if neither is available.

source

Types

StanBlocks.SlicModel Type

The AST and the data, pre-tracing. Can be instantiated via stan_instantiate.

The mod field stores the defining module (set automatically by @slic), used for symbol resolution during tracing — functions defined via @deffun in package extensions are found by checking mod before falling back to Main.

Warning:

Repeatedly instantiating SlicModels is inefficient, as the tracing is redone for every instantiation. Instead, get the StanModel first (via model = stan_model(slic_model)) and update its data (via new_model = model(;x=new_x)).

source
StanBlocks.StanModel Type

The inferred Stan model, post-tracing. Can be instantiated via stan_instantiate.

source

Errors

StanBlocks.StanBlocksError Type
julia
StanBlocksError <: Exception

Wraps errors that occur during transpilation, compilation, or evaluation of Stan models.

Fields

  • phase::Symbol: the pipeline stage where the error occurred (:transpile, :compile, or :evaluate)

  • context::String: a description of what was being processed (e.g. "model: eight_schools")

  • cause::Any: the underlying error, typically an (exception, backtrace) tuple

source
StanBlocks.StanBlocksDiagnostic Type
julia
StanBlocksDiagnostic

Machine-readable location and classification for a SLIC failure.

source_part identifies the caller-supplied source/editor part. line and column are one-based when known and nothing when the compiler has no span at that granularity. code is a stable, coarse failure class; message is a concise user-facing description of the immediate cause.

source
StanBlocks.diagnostic Function
julia
diagnostic(error; source_part=nothing, line_offset=0)

Return a StanBlocksDiagnostic for a StanBlocksError or Julia Meta.ParseError, and nothing for unsupported exceptions. source_part can label a parser error (or supply a fallback label); line_offset maps a synthetic parser wrapper back to the caller's source, e.g. -1 for a leading begin line.

Stable SLIC codes are :slic_parse_error, :slic_trace_error, and :slic_lowering_error.

source
You are viewing the dev branch. This branch may include code written with Claude Code with less human supervision. Only human-approved code is merged into main.