#lang racket/base

;; In-compiler capability cheatsheet — the single source of truth for "what
;; beagle can do". Every entry carries a RUNNABLE example, and
;; beagle-test/tests/cheatsheet.rkt parses + type-checks every one, so this
;; file physically CANNOT claim a capability that doesn't work. That is the
;; anti-rot guarantee: unlike hand-written reference (which drifted — an agent
;; once concluded beagle had no refinement types while `defscalar :where` had
;; shipped for weeks), a stale entry fails the build.
;;
;; It is generated/verified, not prose — consistent with beagle's "no static
;; reference; the compiler is the source of truth" rule. Render it with
;; `bin/beagle-cheatsheet`.
;;
;; Examples omit the file preamble for brevity. Every beagle file begins with:
;;   #lang beagle
;;   (ns my.module)
;;   (define-mode strict)
;;   (define-target clj | js | nix | odin)
;; The test prepends that preamble before checking each example.

(require racket/string)

(provide (struct-out cheat)
         CHEATSHEET
         cheat-categories
         render-cheatsheet)

;; form     : the surface form / capability name
;; category : grouping for display
;; summary  : one line — what it does and the gotcha worth knowing
;; example  : a runnable snippet (preamble-free) that MUST parse + type-check
(struct cheat (form category summary example) #:transparent)

(define CHEATSHEET
  (list
   ;; --- types ---------------------------------------------------------------
   (cheat "defrecord" "Types"
          "Product type with typed fields; generates a constructor and accessors."
          "(defrecord Point [x :- Int y :- Int])")

   (cheat "defunion + match" "Types"
          "Sum type over records. `match` is checked EXHAUSTIVELY — a missing constructor is a compile error (and the repair loop can auto-fill the clauses)."
          (string-append
           "(defrecord Circle [r :- Int])\n"
           "(defrecord Square [side :- Int])\n"
           "(defunion Shape Circle Square)\n"
           "(defn area [s :- Shape] :- Int\n"
           "  (match s [(Circle r) r] [(Square side) side]))"))

   (cheat "defscalar :where" "Types / contracts"
          "Refinement contract: a base type narrowed by predicates. Literal violations are caught statically; non-literal values get a runtime guard emitted per target (nix `assert`, clj `:pre`, js `throw`)."
          (string-append
           "(defscalar Percentage Int :where (>= 0) (<= 100))\n"
           "(def half :- Percentage (->Percentage 50))"))

   (cheat "defenum" "Types"
          "Enumeration of named constants."
          "(defenum Color Red Green Blue)")

   (cheat "inline :- annotations" "Types"
          "Types attach inline with `:-` on params, returns, defs, and let bindings. (`(name : T)` pairs also parse.)"
          "(defn clamp [n :- Int] :- Int (if (> n 100) 100 n))")

   ;; --- bindings & functions ------------------------------------------------
   (cheat "def / defonce" "Bindings"
          "Typed top-level binding."
          "(def answer :- Int 42)")

   (cheat "defn" "Functions"
          "Function with typed params and return. Params are a bracket vector."
          "(defn add [x :- Int y :- Int] :- Int (+ x y))")

   (cheat "let / loop / recur / cond" "Control flow"
          "Standard control flow; bindings use bracket vectors."
          (string-append
           "(defn sum-to [n :- Int] :- Int\n"
           "  (loop [i 0 acc 0]\n"
           "    (cond [(> i n) acc]\n"
           "          [:else (recur (+ i 1) (+ acc i))])))"))

   ;; --- macros & interop ----------------------------------------------------
   (cheat "defmacro + quasiquote" "Macros"
          "Hygienic macros. Quasiquote `` ` ``, unquote `~`, splice `~@`. Free references resolve at the macro's definition site (mode-2 hygiene)."
          "(defmacro twice [x] `(do ~x ~x))")

   (cheat "declare-extern" "Interop"
          "Declare a host function/value with a type so typed code can call into the target runtime."
          "(declare-extern host/now [-> Int])")))

(define (cheat-categories)
  ;; preserve first-appearance order
  (let loop ([cs CHEATSHEET] [seen '()] [acc '()])
    (cond
      [(null? cs) (reverse acc)]
      [(member (cheat-category (car cs)) seen) (loop (cdr cs) seen acc)]
      [else (loop (cdr cs)
                  (cons (cheat-category (car cs)) seen)
                  (cons (cheat-category (car cs)) acc))])))

(define (render-cheatsheet)
  (define out (open-output-string))
  (fprintf out "# beagle cheatsheet\n\n")
  (fprintf out "What the language can do, with verified examples. Generated by\n")
  (fprintf out "`bin/beagle-cheatsheet` from beagle-lib/private/cheatsheet.rkt; every\n")
  (fprintf out "example is parse+type-checked by the test suite, so nothing here is stale.\n\n")
  (fprintf out "Files begin with `#lang beagle`, then `(ns ...)`, `(define-mode strict)`,\n")
  (fprintf out "and `(define-target clj | js | nix | odin)`. For signatures, fields,\n")
  (fprintf out "and the full form set, query the compiler (`bin/beagle sig|fields|syntax`,\n")
  (fprintf out "or `bin/beagle` for all commands).\n")
  (for ([cat (in-list (cheat-categories))])
    (fprintf out "\n## ~a\n\n" cat)
    (for ([c (in-list CHEATSHEET)]
          #:when (string=? (cheat-category c) cat))
      (fprintf out "### ~a\n~a\n\n```clojure\n~a\n```\n\n"
               (cheat-form c) (cheat-summary c) (cheat-example c))))
  (get-output-string out))

(module+ main
  (display (render-cheatsheet)))
