;; Evaluation rules — machine-readable SX semantics reference.
;;
;; Each rule describes one dispatch case in the CEK evaluator.
;; Rules are data — queried by tools (sx_explain), validated against behavior.
;; Examples are strings to avoid evaluation: "expr → result"

(define eval-rules
  (list

    {:name "number" :category "literal"
     :pattern "42"
     :rule "Numbers evaluate to themselves."
     :effects ()
     :examples "42 → 42, -3.14 → -3.14"}

    {:name "string" :category "literal"
     :pattern "\"hello\""
     :rule "Strings evaluate to themselves."
     :effects ()
     :examples "\"hello\" → \"hello\""}

    {:name "boolean" :category "literal"
     :pattern "true | false"
     :rule "Booleans evaluate to themselves."
     :effects ()
     :examples "true → true, false → false"}

    {:name "nil" :category "literal"
     :pattern "nil"
     :rule "Nil evaluates to itself. Nil is falsy."
     :effects ()
     :examples "nil → nil"}

    {:name "keyword" :category "literal"
     :pattern ":name"
     :rule "Keywords evaluate to their string name."
     :effects ()
     :examples ":foo → \"foo\", :class → \"class\""}

    {:name "dict" :category "literal"
     :pattern "{:key1 val1 :key2 val2 ...}"
     :rule "Create a dictionary. Keys are keywords (evaluated to strings). Values are evaluated."
     :effects ()
     :examples "{:x 1 :y 2} → {\"x\" 1 \"y\" 2}"}

    {:name "symbol" :category "lookup"
     :pattern "name"
     :rule "Look up in: (1) environment chain, (2) primitives, (3) true/false/nil literals. Error if not found."
     :effects ()
     :examples "+ → <native:+>, undefined → ERROR"}

    {:name "if" :category "special-form"
     :pattern "(if test then else?)"
     :rule "Evaluate test. If truthy (not false, not nil), evaluate then. Otherwise evaluate else (or nil if absent). Both branches are in tail position."
     :effects ()
     :examples "(if true 1 2) → 1, (if false 1 2) → 2, (if nil 1) → nil"}

    {:name "when" :category "special-form"
     :pattern "(when test body ...)"
     :rule "Evaluate test. If truthy, evaluate body forms in sequence, return last. If falsy, return nil. Last body form is in tail position."
     :effects ()
     :examples "(when true 1 2 3) → 3, (when false 1) → nil"}

    {:name "cond" :category "special-form"
     :pattern "(cond test1 expr1 test2 expr2 ... :else default)"
     :rule "Evaluate tests in order. First truthy test: evaluate and return its expr. :else always matches. If no match, return nil."
     :effects ()
     :examples "(cond false 1 true 2) → 2, (cond false 1 :else 3) → 3"}

    {:name "case" :category "special-form"
     :pattern "(case expr val1 result1 val2 result2 ... :else default)"
     :rule "Evaluate expr once. Compare against each val (by equality). Return the matched result. :else is the fallback."
     :effects ()
     :examples "(case 2 1 \"one\" 2 \"two\") → \"two\""}

    {:name "and" :category "special-form"
     :pattern "(and expr ...)"
     :rule "Evaluate left to right. Return first falsy value, or last value if all truthy. Short-circuits."
     :effects ()
     :examples "(and 1 2 3) → 3, (and 1 false 3) → false"}

    {:name "or" :category "special-form"
     :pattern "(or expr ...)"
     :rule "Evaluate left to right. Return first truthy value, or last value if all falsy. Short-circuits."
     :effects ()
     :examples "(or false 2 3) → 2, (or false nil) → nil"}

    {:name "let" :category "special-form"
     :pattern "(let ((name val) ...) body ...)"
     :rule "Create new scope. Evaluate each val sequentially, bind name. Then evaluate body forms, return last. Values see only earlier bindings. Last body form is in tail position."
     :effects ()
     :examples "(let ((x 1) (y 2)) (+ x y)) → 3"}

    {:name "letrec" :category "special-form"
     :pattern "(letrec ((name val) ...) body ...)"
     :rule "Like let, but all bindings are visible to all vals (mutual recursion). Bindings exist before vals are evaluated."
     :effects ()
     :examples "(letrec ((f (fn (n) (if (= n 0) 1 (* n (f (- n 1))))))) (f 5)) → 120"}

    {:name "lambda" :category "special-form"
     :pattern "(fn (params ...) body ...) | (lambda (params ...) body ...)"
     :rule "Create a closure capturing the current environment. Parameters support: positional, &key (keyword args), &rest (variadic), (:as type) annotations. Last body form is in tail position."
     :effects ()
     :examples "(fn (x) (+ x 1)) → <lambda>"}

    {:name "define" :category "special-form"
     :pattern "(define name value) | (define name :effects (e ...) value)"
     :rule "Evaluate value, bind name in the current environment. Optional :effects annotation declares side effects. Returns the value."
     :effects ()
     :examples "(define x 42) → 42"}

    {:name "set!" :category "special-form"
     :pattern "(set! name value)"
     :rule "Evaluate value, mutate existing binding of name. Walks the scope chain to find the binding. Error if name is not bound."
     :effects "mutation"
     :examples "(let ((x 1)) (set! x 2) x) → 2"}

    {:name "begin" :category "special-form"
     :pattern "(begin expr ...) | (do expr ...)"
     :rule "Evaluate expressions in sequence, return last. Last form is in tail position."
     :effects ()
     :examples "(begin 1 2 3) → 3"}

    {:name "quote" :category "special-form"
     :pattern "(quote expr)"
     :rule "Return expr unevaluated."
     :effects ()
     :examples "(quote (+ 1 2)) → (+ 1 2)"}

    {:name "quasiquote" :category "special-form"
     :pattern "`expr with ,x and ,@xs"
     :rule "Like quote, but (unquote x) evaluates x, and (splice-unquote x) splices a list."
     :effects ()
     :examples "(let ((x 1)) `(a ,x b)) → (a 1 b)"}

    {:name "thread-first" :category "special-form"
     :pattern "(-> val (fn1 args...) (fn2 args...) ...)"
     :rule "Thread val through forms. Each form receives the previous result as its first argument. (-> x (f a)) becomes (f x a)."
     :effects ()
     :examples "(-> 1 (+ 2) (* 3)) → 9"}

    {:name "defcomp" :category "definition"
     :pattern "(defcomp ~name (params ...) body ...)"
     :rule "Define a component. Keyword args via &key, variadic via &rest. Body evaluated in merged env (closure + caller-env + params)."
     :effects ()
     :examples "(defcomp ~card (&key title) (div (h2 title)))"}

    {:name "defisland" :category "definition"
     :pattern "(defisland ~name (params ...) body ...)"
     :rule "Define an island — a component that hydrates on the client. Server renders a placeholder; client evaluates the body with reactive capabilities."
     :effects ()
     :examples "(defisland ~counter () (let ((n (signal 0))) (button :on-click (fn (e) (swap! n inc)) (deref n))))"}

    {:name "defmacro" :category "definition"
     :pattern "(defmacro name (params ...) body ...)"
     :rule "Define a macro. At call time, args are passed unevaluated. Body produces a new expression which is then evaluated."
     :effects ()
     :examples "(defmacro unless (test body) `(if (not ,test) ,body))"}

    {:name "map" :category "higher-order"
     :pattern "(map fn coll) | (map coll fn)"
     :rule "Apply fn to each element of coll, return new list. Argument order is flexible."
     :effects ()
     :examples "(map (fn (x) (* x 2)) (list 1 2 3)) → (2 4 6)"}

    {:name "filter" :category "higher-order"
     :pattern "(filter fn coll) | (filter coll fn)"
     :rule "Return elements of coll where fn returns truthy. Flexible argument order."
     :effects ()
     :examples "(filter (fn (x) (> x 2)) (list 1 2 3 4)) → (3 4)"}

    {:name "reduce" :category "higher-order"
     :pattern "(reduce fn init coll)"
     :rule "Fold coll from left. Call (fn acc item) for each element, starting with init."
     :effects ()
     :examples "(reduce + 0 (list 1 2 3)) → 6"}

    {:name "some" :category "higher-order"
     :pattern "(some fn coll)"
     :rule "Return first truthy result of (fn item), or false if none."
     :effects ()
     :examples "(some (fn (x) (> x 2)) (list 1 2 3)) → true"}

    {:name "every?" :category "higher-order"
     :pattern "(every? fn coll)"
     :rule "Return true if (fn item) is truthy for all items."
     :effects ()
     :examples "(every? (fn (x) (> x 0)) (list 1 2 3)) → true"}

    {:name "for-each" :category "higher-order"
     :pattern "(for-each fn coll)"
     :rule "Call (fn item) for each element. Returns nil. Used for side effects."
     :effects "mutation"
     :examples "(for-each print (list 1 2 3)) → nil (prints 1, 2, 3)"}

    {:name "scope" :category "scope"
     :pattern "(scope name body ...)"
     :rule "Create a named dynamic scope. The unified primitive beneath provide, collect!, and spreads."
     :effects "mutation"
     :examples "(scope \"my-scope\" (emit! \"my-scope\" 42) (emitted \"my-scope\")) → (42)"}

    {:name "provide" :category "scope"
     :pattern "(provide name value body ...)"
     :rule "Make value available to descendants via (context name)."
     :effects "mutation"
     :examples "(provide \"theme\" \"dark\" (context \"theme\")) → \"dark\""}

    {:name "context" :category "scope"
     :pattern "(context name)"
     :rule "Retrieve the value from the nearest enclosing (provide name value ...)."
     :effects ()
     :examples "(provide \"x\" 42 (context \"x\")) → 42"}

    {:name "emit!" :category "scope"
     :pattern "(emit! name value)"
     :rule "Emit a value upward into a named scope."
     :effects "mutation"
     :examples "see scope example"}

    {:name "emitted" :category "scope"
     :pattern "(emitted name)"
     :rule "Collect all values emitted into the named scope."
     :effects ()
     :examples "see scope example"}

    {:name "reset" :category "continuation"
     :pattern "(reset body ...)"
     :rule "Delimit a continuation. shift inside body captures up to this point."
     :effects ()
     :examples "(reset (+ 1 (shift k (k 10)))) → 11"}

    {:name "shift" :category "continuation"
     :pattern "(shift k body ...)"
     :rule "Capture the continuation up to the nearest reset. k is a function that resumes the captured computation."
     :effects ()
     :examples "(reset (+ 1 (shift k (k (k 10))))) → 12"}

    {:name "deref" :category "reactive"
     :pattern "(deref signal)"
     :rule "Read the current value of a reactive signal. In a reactive context, establishes a dependency."
     :effects ()
     :examples "(let ((s (signal 42))) (deref s)) → 42"}

    {:name "function-call" :category "call"
     :pattern "(f arg1 arg2 ...)"
     :rule "Evaluate f and all args left to right. Then: native → apply, lambda → bind params + TCO, component → parse kwargs + bind params + TCO, macro → expand unevaluated args + re-eval."
     :effects ()
     :examples "(+ 1 2) → 3, (list 1 2 3) → (1 2 3)"}
  ))

;; Lookup helpers

(define find-rule
  (fn (name)
    (some (fn (rule)
      (when (= (get rule "name") name) rule))
      eval-rules)))

(define rules-by-category
  (fn (category)
    (filter (fn (rule) (= (get rule "category") category))
      eval-rules)))

(define rule-categories
  (fn ()
    (let ((seen (dict)) (result (list)))
      (for-each (fn (rule)
        (let ((cat (get rule "category")))
          (when (not (has-key? seen cat))
            (dict-set! seen cat true)
            (append! result cat))))
        eval-rules)
      result)))
