Lower Typed Jerboa import-resolved modules to Rust
ober
cbaa5ec8b2655b9fb8ea8e190177d72085ce9627
--- a/docs/typed-jerboa.md +++ b/docs/typed-jerboa.md @@ -286,13 +286,16 @@ Highest-value next steps: IR through `*rust-ir-env*` in `typed-module->rust-string` and `typed-modules->rust-crate-string`. The wrapper generator still walks surface AST, which is fine for ABI-level shape information. -2. Resolve imports between typed modules. The parser now accepts an optional - `(import (module name) ...)` clause and the checker offers +2. Resolve imports between typed modules. The parser accepts an optional + `(import (module name) ...)` clause. The checker offers `check-typed-modules` / `check-and-elaborate-typed-modules`, which walk a topologically ordered module list and extend each module's type/call/variant envs with the previously listed modules' exported declarations. The Rust - emitter does not yet emit cross-module `use` declarations or split the - generated crate into per-module files. + emitter (`typed-modules->rust-crate-string` / + `typed-library-forms->rust-crate-string`) now uses the same multi-module + elaboration, so cross-module record/variant/def references compile into a + single Rust crate. The emitter still inlines all modules into one file and + does not yet emit cross-module `use` declarations. 3. Improve boundary semantics for Option/Result. They currently cross the FFI boundary as opaque handles; direct conversion to idiomatic Scheme result values is still open. --- a/lib/jerboa/typed/rust.ss +++ b/lib/jerboa/typed/rust.ss @@ -1292,11 +1292,22 @@ (typed-module->rust-string (parse-typed-library form))) (def (typed-modules->rust-crate-string modules) - (let ([ir-envs - (map (lambda (m) - (elaborate-module-or-error - m 'typed-modules->rust-crate-string)) - modules)]) + ;; Run import-aware elaboration so cross-module references type check. + (let* ([results (check-and-elaborate-typed-modules modules)] + [ir-envs + (map (lambda (entry) + (let ([modname (car entry)] + [errors (cadr entry)] + [defs (caddr entry)]) + (unless (null? errors) + (error 'typed-modules->rust-crate-string + "typed module has check errors" + (cons modname (map typed-check-error-kind errors)))) + (map (lambda (ed) + (cons (elaborated-def-name ed) + (elaborated-def-body-ir ed))) + defs))) + results)]) (with-rust-env modules (lambda () (emit-to-string --- a/tests/test-typed-rust.ss +++ b/tests/test-typed-rust.ss @@ -336,6 +336,35 @@ (substring? equality-rust "jt_return_bytes(token_debug(token).into_bytes(), out_ptr, out_len)")) #t) +(define import-provider-form + '(typed-library (rust import provider) + (export inc make-Pt Pt-x Pt-y) + (record Pt ((x : Nat) (y : Nat))) + (def (inc (x : Nat)) : Nat (+ x 1)))) + +(define import-consumer-form + '(typed-library (rust import consumer) + (export bump-pair-x) + (import (rust import provider)) + (def (bump-pair-x (p : Pt)) : Pt + (make-Pt (inc (Pt-x p)) (Pt-y p))))) + +(define import-crate-rust + (typed-library-forms->rust-crate-string + (list import-provider-form import-consumer-form))) + +(test "rust crate emits provider def" + (substring? import-crate-rust "pub fn inc(x: u64) -> u64") + #t) + +(test "rust crate emits consumer def calling provider" + (and (substring? import-crate-rust "pub fn bump_pair_x(p: Pt) -> Pt") + (substring? import-crate-rust "inc(") + (substring? import-crate-rust "Pt { x:") + (substring? import-crate-rust "(p).x") + (substring? import-crate-rust "(p).y")) + #t) + (printf "~%Typed Rust emitter: ~a passed, ~a failed~%" pass fail) (when (> fail 0) (exit 1))