Continuum.AstCheck (continuum v0.5.0)

Copy Markdown View Source

Compile-time AST scanner that rejects calls known to be non-deterministic inside workflow code.

The scanner is invoked from Continuum.Workflow (and Continuum.Pure) at module compile time. Each forbidden call produces a CompileError with a remediation hint pointing at the deterministic equivalent.

See the :forbidden_calls/0 and :trusted_stdlib/0 functions for the curated denylist and allowlist. Users can extend the allowlist via:

config :continuum, trusted_modules: [Decimal, Money]

Calls from workflow code into helper modules that are not stdlib-trusted, allowlisted, or marked with use Continuum.Pure emit warnings by default. Use config :continuum, untrusted_call_severity: :error to make those diagnostics fail compilation. Error mode raises on the first untrusted helper module found in the current definition.

Summary

Types

A {module, function} pair.

An untrusted external helper call found during AST scan.

A violation found during AST scan.

Functions

Emit or raise diagnostics for external helper modules that are not trusted.

The full denylist as a map of {mod, fun} => hint.

Format a list of violations into a single human-readable string suitable for CompileError.

Scan an AST. Returns :ok or {:error, [violation]}.

Stdlib modules considered pure-by-construction.

Types

call()

@type call() :: {module(), atom()}

A {module, function} pair.

helper_call()

@type helper_call() :: %{
  module: module(),
  function: atom(),
  arity: non_neg_integer(),
  line: pos_integer() | nil,
  file: String.t() | nil
}

An untrusted external helper call found during AST scan.

violation()

@type violation() :: %{
  mfa: call(),
  line: pos_integer() | nil,
  file: String.t() | nil,
  hint: String.t()
}

A violation found during AST scan.

Functions

check_helper_calls(ast, env, caller_fun, caller_arity)

@spec check_helper_calls(Macro.t(), Macro.Env.t(), atom(), non_neg_integer()) :: :ok

Emit or raise diagnostics for external helper modules that are not trusted.

Activity calls are skipped because their side effects are deliberately routed through the DSL and journal. Same-module calls are also skipped; their bodies are scanned by the workflow compiler hook.

forbidden_calls()

The full denylist as a map of {mod, fun} => hint.

format(violations)

@spec format([violation()]) :: String.t()

Format a list of violations into a single human-readable string suitable for CompileError.

scan(ast, file \\ nil)

@spec scan(Macro.t(), String.t() | nil) :: :ok | {:error, [violation()]}

Scan an AST. Returns :ok or {:error, [violation]}.

Pass the originating file so diagnostics include it.

trusted_stdlib()

Stdlib modules considered pure-by-construction.