;; Haskell runtime: constructor registry. ;; ;; A mutable dict keyed by constructor name (e.g. "Just", "[]") with ;; entries of shape {:arity N :type TYPE-NAME-STRING}. ;; Populated by ingesting `data` / `newtype` decls from parsed ASTs. ;; Pre-registers a small set of constructors tied to Haskell syntactic ;; forms (Bool, list, unit) — every nontrivial program depends on ;; these, and the parser/desugar pipeline emits them as (:var "True") ;; etc. without a corresponding `data` decl. (define hk-constructors (dict)) (define hk-register-con! (fn (cname arity type-name) (dict-set! hk-constructors cname {:arity arity :type type-name}))) (define hk-is-con? (fn (name) (has-key? hk-constructors name))) (define hk-con-arity (fn (name) (if (has-key? hk-constructors name) (get (get hk-constructors name) "arity") nil))) (define hk-con-type (fn (name) (if (has-key? hk-constructors name) (get (get hk-constructors name) "type") nil))) (define hk-con-names (fn () (keys hk-constructors))) ;; ── Registration from AST ──────────────────────────────────── ;; (:data NAME TVARS ((:con-def CNAME FIELDS) …)) (define hk-register-data! (fn (data-node) (let ((type-name (nth data-node 1)) (cons-list (nth data-node 3))) (for-each (fn (cd) (hk-register-con! (nth cd 1) (len (nth cd 2)) type-name)) cons-list)))) ;; (:newtype NAME TVARS CNAME FIELD) (define hk-register-newtype! (fn (nt-node) (hk-register-con! (nth nt-node 3) 1 (nth nt-node 1)))) ;; Walk a decls list, registering every `data` / `newtype` decl. (define hk-register-decls! (fn (decls) (for-each (fn (d) (cond ((and (list? d) (not (empty? d)) (= (first d) "data")) (hk-register-data! d)) ((and (list? d) (not (empty? d)) (= (first d) "newtype")) (hk-register-newtype! d)) (:else nil))) decls))) (define hk-register-program! (fn (ast) (cond ((nil? ast) nil) ((not (list? ast)) nil) ((empty? ast) nil) ((= (first ast) "program") (hk-register-decls! (nth ast 1))) ((= (first ast) "module") (hk-register-decls! (nth ast 4))) (:else nil)))) ;; Convenience: source → AST → desugar → register. (define hk-load-source! (fn (src) (hk-register-program! (hk-core src)))) ;; ── Built-in constructors pre-registered ───────────────────── ;; Bool — used implicitly by `if`, comparison operators. (hk-register-con! "True" 0 "Bool") (hk-register-con! "False" 0 "Bool") ;; List — used by list literals, range syntax, and cons operator. (hk-register-con! "[]" 0 "List") (hk-register-con! ":" 2 "List") ;; Unit — produced by empty parens `()`. (hk-register-con! "()" 0 "Unit") ;; Standard Prelude types — pre-registered so expression-level ;; programs can use them without a `data` decl. (hk-register-con! "Nothing" 0 "Maybe") (hk-register-con! "Just" 1 "Maybe") (hk-register-con! "Left" 1 "Either") (hk-register-con! "Right" 1 "Either") (hk-register-con! "LT" 0 "Ordering") (hk-register-con! "EQ" 0 "Ordering") (hk-register-con! "GT" 0 "Ordering") (define hk-str? (fn (v) (or (string? v) (and (dict? v) (has-key? v "hk-str"))))) (define hk-str-head (fn (v) (if (string? v) (char-code (char-at v 0)) (char-code (char-at (get v "hk-str") (get v "hk-off")))))) (define hk-str-tail (fn (v) (let ((buf (if (string? v) v (get v "hk-str"))) (off (if (string? v) 1 (+ (get v "hk-off") 1)))) (if (>= off (string-length buf)) (list "[]") {:hk-off off :hk-str buf})))) (define hk-str-null? (fn (v) (if (string? v) (= (string-length v) 0) (>= (get v "hk-off") (string-length (get v "hk-str")))))) (define hk-str-to-native (fn (v) (if (string? v) v (let ((buf (get v "hk-str")) (off (get v "hk-off"))) (reduce (fn (acc i) (str acc (char-at buf i))) "" (range off (string-length buf)))))))