(ns com.tailrecursion.blacktide
"Blacktide's loophole macro adds mutable lexical locals and statement jumps
to a bounded subset of Clojure, compiled through typed nanopasses."
(:require [com.tailrecursion.blacktide.compiler.errors :as errors]
[com.tailrecursion.blacktide.compiler :as compiler]))
(defmacro label
"Mark a position in the outer statement sequence of a loophole region."
[& _]
(errors/fail :outside-region "label is only valid inside loophole" {}
(errors/site {:form &form :file *file* :line nil :column nil} &form)))
(defmacro goto
"Jump from a statement to an explicit outer label."
[& _]
(errors/fail :outside-region "goto is only valid inside loophole" {}
(errors/site {:form &form :file *file* :line nil :column nil} &form)))
(defmacro setq
"Assign symbol/value pairs sequentially; return the last value, or nil."
[& _]
(errors/fail :outside-region "setq is only valid inside loophole" {}
(errors/site {:form &form :file *file* :line nil :column nil} &form)))
(defmacro psetq
"Evaluate symbol/value pairs before assigning their targets; return nil."
[& _]
(errors/fail :outside-region "psetq is only valid inside loophole" {}
(errors/site {:form &form :file *file* :line nil :column nil} &form)))
(defmacro loophole
"Initialize simple-symbol bindings sequentially; make them mutable through
setq/psetq. Return the last body value, or nil. Labels belong to the outer
statement sequence; goto is forbidden within operands and initializers.
Supports let, loop/recur, case, calls, collections, Java interop and macros
expanding into these forms. Functions, try, native set! and nested regions
must be outside the macro. See doc/language.md for the complete contract."
[bindings & body]
(compiler/compile-form (or &env {})
{#'loophole :loophole #'label :label #'goto :goto #'setq :setq #'psetq :psetq}
&form))