WASM: implement string-from-static, intern-symbol, and static data replacement

ober

a453273505b0d2c8ea028a7fd86dd7da4be9772b

diff --git a/lib/jerboa/wasm/scheme-runtime.sls b/lib/jerboa/wasm/scheme-runtime.sls
index d7050fe..0374767 100644
--- a/lib/jerboa/wasm/scheme-runtime.sls
+++ b/lib/jerboa/wasm/scheme-runtime.sls
@@ -266,6 +266,19 @@
             (string-byte-set! s i (i32.load8_u (+ offset i)))
             (set! i (+ i 1)))
           s))
+
+      ;; Load a string from the static data segment.
+      ;; The data segment stores strings as: [4-byte LE length][UTF-8 bytes].
+      ;; offset is the raw i32 address of the length prefix.
+      (define (string-from-static offset)
+        (let ([len (i32.load offset)])
+          (string-from-memory (+ offset 4) len)))
+
+      ;; Intern a symbol by wrapping a string pointer.
+      ;; Simple MVP: symbol identity is by string equality (not pointer equality).
+      ;; Full symbol table interning can be added later.
+      (define (intern-symbol str-ptr)
+        (alloc-symbol str-ptr))
       ))
 
   ;; ================================================================
diff --git a/lib/std/secure/wasm-target.sls b/lib/std/secure/wasm-target.sls
index de7bb37..60da54f 100644
--- a/lib/std/secure/wasm-target.sls
+++ b/lib/std/secure/wasm-target.sls
@@ -948,7 +948,9 @@
            [lifted (lambda-lift lowered)]
            ;; Collect static string data for data segments
            [static-strings (collect-static-strings lifted)]
-           [string-data-forms (generate-string-data static-strings)])
+           [string-data-forms (generate-string-data static-strings)]
+           ;; Replace (string-from-static #vu8(...)) with (string-from-static offset)
+           [lifted (replace-static-strings lifted static-strings)])
 
       ;; Assemble the complete program
       (append
@@ -1013,6 +1015,26 @@
              `(define-data ,offset ,data)))
          string-table))
 
+  ;; Replace (string-from-static #vu8(...)) with (string-from-static offset)
+  ;; using the offset table produced by collect-static-strings.
+  ;; This converts bytevector literals to raw memory addresses so the
+  ;; generated WASM calls the runtime string-from-static with an i32.
+  (define (replace-static-strings forms string-table)
+    (define (replace expr)
+      (cond
+        [(pair? expr)
+         (if (and (eq? (car expr) 'string-from-static)
+                  (bytevector? (cadr expr)))
+           ;; Replace with the assigned integer offset
+           (let ([entry (assoc (cadr expr) string-table)])
+             (if entry
+               `(string-from-static ,(cdr entry))
+               expr))  ;; shouldn't happen if collect was complete
+           ;; Otherwise recurse into subforms
+           (map replace expr))]
+        [else expr]))
+    (map replace forms))
+
   ;; Check if any form references closures
   (define (has-closures? forms)
     (let ([found #f])