;; Step 15: Bytecode + continuation serialization ;; Round-trip compiled code and suspended CEK state through strings. ;; ── Bytecode serialization ──────────────────────────────────────── (defsuite "bytecode-serialize-basic" (deftest "compile and serialize round-trips" (let ((code (compile "(+ 1 2)"))) (assert (not (nil? code))) (let ((serialized (bytecode-serialize code))) (assert (string? serialized)) (assert (> (string-length serialized) 0))))) (deftest "serialized format has sxbc header" (let ((code (compile "(+ 1 2)"))) (let ((serialized (bytecode-serialize code))) (assert (starts-with? serialized "(sxbc 2"))))) (deftest "deserialized code has same structure" (let ((code (compile "(+ 1 2)"))) (let ((serialized (bytecode-serialize code)) (restored (bytecode-deserialize serialized))) (assert (not (nil? restored))) (assert (dict? restored))))) (deftest "deserialized bytecode array matches" (let ((code (compile "(+ 1 2)"))) (let ((serialized (bytecode-serialize code)) (restored (bytecode-deserialize serialized))) (assert= (get restored "bytecode") (get code "bytecode"))))) (deftest "deserialized constants match" (let ((code (compile "(str \"hello\" \" \" \"world\")"))) (let ((serialized (bytecode-serialize code)) (restored (bytecode-deserialize serialized))) (assert= (get restored "constants") (get code "constants")))))) (defsuite "bytecode-serialize-types" (deftest "number bytecodes round-trip" (let ((code (compile "(+ 42 3)"))) (let ((restored (bytecode-deserialize (bytecode-serialize code)))) (assert= (get restored "bytecode") (get code "bytecode"))))) (deftest "multiple expressions round-trip" (let ((code (compile "(define x 1)"))) (let ((restored (bytecode-deserialize (bytecode-serialize code)))) (assert= (get restored "bytecode") (get code "bytecode")) (assert= (get restored "constants") (get code "constants"))))) (deftest "dict expression round-trips" (let ((code (compile "(dict :a 1 :b 2)"))) (let ((restored (bytecode-deserialize (bytecode-serialize code)))) (assert= (get restored "constants") (get code "constants"))))) (deftest "lambda expression round-trips" (let ((code (compile "(fn (x) (+ x 1))"))) (let ((restored (bytecode-deserialize (bytecode-serialize code)))) (assert= (get restored "bytecode") (get code "bytecode"))))) (deftest "invalid format raises error" (let ((raised false)) (guard (e (true (set! raised true))) (bytecode-deserialize "not valid")) (assert raised "should raise for invalid format")))) ;; ── CEK state serialization ─────────────────────────────────────── (defsuite "cek-serialize-basic" (deftest "suspended state serializes" (let ((state (make-cek-suspended {:op "test"} (dict) (list)))) (let ((serialized (cek-serialize state))) (assert (string? serialized)) (assert (starts-with? serialized "(cek-state 1"))))) (deftest "deserialized state preserves phase" (let ((state (make-cek-suspended {:op "test"} (dict) (list)))) (let ((restored (cek-deserialize (cek-serialize state)))) (assert (cek-suspended? restored))))) (deftest "deserialized state preserves request" (let ((state (make-cek-suspended {:url "/api" :op "fetch"} (dict) (list)))) (let ((restored (cek-deserialize (cek-serialize state)))) (let ((req (cek-io-request restored))) (assert= (get req :op) "fetch") (assert= (get req :url) "/api")))))) (defsuite "cek-serialize-values" (deftest "request with nested data round-trips" (let ((req {:params {:ids (list 1 2 3) :name "test"} :op "query"}) (state (make-cek-suspended req (dict) (list)))) (let ((restored (cek-deserialize (cek-serialize state)))) (let ((rreq (cek-io-request restored))) (assert= (get rreq :op) "query") (assert= (get (get rreq :params) :name) "test") (assert= (get (get rreq :params) :ids) (list 1 2 3)))))) (deftest "string with special chars round-trips" (let ((req {:op "test" :data "line1\nline2\ttab"}) (state (make-cek-suspended req (dict) (list)))) (let ((restored (cek-deserialize (cek-serialize state)))) (assert= (get (cek-io-request restored) :data) "line1\nline2\ttab")))) (deftest "invalid cek format raises error" (let ((raised false)) (guard (e (true (set! raised true))) (cek-deserialize "garbage")) (assert raised "should raise for invalid format"))))