(define canonical-serialize :effects () (fn (val) (case (type-of val) "nil" "nil" "boolean" (if val "true" "false") "number" (canonical-number val) "string" (str "\"" (escape-string val) "\"") "symbol" (symbol-name val) "keyword" (str ":" (keyword-name val)) "list" (str "(" (join " " (map canonical-serialize val)) ")") "dict" (canonical-dict val) :else (str val)))) (define canonical-number :effects () (fn (n) (let ((s (str n))) (if (ends-with? s ".0") (slice s 0 (- (len s) 2)) (if (contains-char? s ".") (let ((trimmed (trim-right s "0"))) (if (ends-with? trimmed ".") (str trimmed "0") trimmed)) s))))) (define canonical-dict :effects () (fn (d) (let ((sorted-keys (sort (keys d)))) (str "{" (join " " (reduce (fn (acc key) (concat acc (list (str ":" key) (canonical-serialize (dict-get d key))))) (list) sorted-keys)) "}")))) (define content-id :effects () (fn (expr) (sha3-256 (canonical-serialize expr)))) (define content-id-short :effects () (fn (expr) (slice (content-id expr) 0 16))) (define make-bytecode-module :effects () (fn (version source-hash code) (list (quote sxbc) version source-hash code))) (define bytecode-module? :effects () (fn (expr) (and (list? expr) (>= (len expr) 4) (= (first expr) (quote sxbc))))) (define bytecode-module-version :effects () (fn (m) (nth m 1))) (define bytecode-module-source-hash :effects () (fn (m) (nth m 2))) (define bytecode-module-code :effects () (fn (m) (nth m 3))) (define make-code-object :effects () (fn (arity upvalue-count bytecode constants) (let ((parts (list (quote code)))) (when (> arity 0) (set! parts (concat parts (list :arity arity)))) (when (> upvalue-count 0) (set! parts (concat parts (list :upvalue-count upvalue-count)))) (concat parts (list :bytecode bytecode :constants constants))))) (define make-provenance :effects () (fn (source-cid bytecode-cid compiler-cid timestamp) (list (quote provenance) :source-cid source-cid :bytecode-cid bytecode-cid :compiler-cid compiler-cid :timestamp timestamp)))