Lower Typed Jerboa option results to Rust
ober
9c3d4900f482ba163f23682967b689551f0654a2
--- a/docs/jerboa-to-rust.md +++ b/docs/jerboa-to-rust.md @@ -154,10 +154,9 @@ Initial type mapping: | Record | `struct` | | Variant | `enum` | -Current landing: the checker types explicit Option/Result constructors: -`option-some`, `option-none`, `result-ok`, and `result-err`. The Rust backend -already maps Option/Result types, but constructor expression lowering is still -future work. +Current landing: the checker types explicit Option/Result constructors and the +Rust backend lowers them: `option-some` -> `Some(...)`, `option-none` -> `None`, +`result-ok` -> `Ok(...)`, and `result-err` -> `Err(...)`. Boundary-facing values should use ABI-safe wrappers instead of raw Rust layout. --- a/docs/typed-jerboa.md +++ b/docs/typed-jerboa.md @@ -212,7 +212,8 @@ Current landing: - `Option` and `Result` type expressions now have explicit checked constructors in the front end: `(option-some expr)`, `(option-none Type)`, `(result-ok expr ErrorType)`, and `(result-err ValueType expr)`. Rust - lowering for these constructors is still future work. + lowering maps them to `Some`, `None`, `Ok`, and `Err` without treating type + operands as runtime values. - The current Rust lowering uses a conservative Clone-only ownership model: generated constructors, ordinary calls, and recursive match rebinding clone owned values so recursive branch code can pass the same child value to more --- a/lib/jerboa/typed/rust.ss +++ b/lib/jerboa/typed/rust.ss @@ -911,6 +911,26 @@ (emit-expression (car args)) ").len() as u64")) + (def (emit-option-some args) + (unless (= (length args) 1) + (error 'typed-rust "option-some expects one operand" args)) + (string-append "Some(" (emit-argument-expression (car args)) ")")) + + (def (emit-option-none args) + (unless (= (length args) 1) + (error 'typed-rust "option-none expects one type operand" args)) + "None") + + (def (emit-result-ok args) + (unless (= (length args) 2) + (error 'typed-rust "result-ok expects value and error type operands" args)) + (string-append "Ok(" (emit-argument-expression (car args)) ")")) + + (def (emit-result-err args) + (unless (= (length args) 2) + (error 'typed-rust "result-err expects value type and error operands" args)) + (string-append "Err(" (emit-argument-expression (cadr args)) ")")) + (def (emit-call name args) (let ([record-constructor (lookup-record-constructor name)] [record-accessor (lookup-record-accessor name)] @@ -932,6 +952,14 @@ (emit-string-append args)] [(eq? name 'bytevector-length) (emit-bytevector-length args)] + [(eq? name 'option-some) + (emit-option-some args)] + [(eq? name 'option-none) + (emit-option-none args)] + [(eq? name 'result-ok) + (emit-result-ok args)] + [(eq? name 'result-err) + (emit-result-err args)] [else (string-append (rust-symbol-name name) --- a/tests/test-typed-rust.ss +++ b/tests/test-typed-rust.ss @@ -169,6 +169,21 @@ (define handle-rust (typed-library-form->rust-string handle-form)) +(define option-result-form + '(typed-library (sample typed option-result) + (export maybe-value none-text ok-value err-value) + (def (maybe-value (x : Nat)) : (Option Nat) + (option-some x)) + (def (none-text) : (Option String) + (option-none String)) + (def (ok-value (x : Nat)) : (Result Nat String) + (result-ok x String)) + (def (err-value (message : String)) : (Result Nat String) + (result-err Nat message)))) + +(define option-result-rust + (typed-library-form->rust-string option-result-form)) + (printf "--- Typed Jerboa Rust emitter tests ---~%") (test "rust symbol sanitizes" @@ -264,6 +279,17 @@ (substring? handle-rust "let token = jt_clone_handle::<Token>(token_handle).unwrap_or_else(|| panic!(\"invalid typed handle\"));")) #t) +(test "rust lowers option and result constructors" + (and (substring? option-result-rust "pub fn maybe_value(x: u64) -> Option<u64>") + (substring? option-result-rust "Some((x).clone())") + (substring? option-result-rust "pub fn none_text() -> Option<String>") + (substring? option-result-rust "None") + (substring? option-result-rust "pub fn ok_value(x: u64) -> Result<u64, String>") + (substring? option-result-rust "Ok((x).clone())") + (substring? option-result-rust "pub fn err_value(message: String) -> Result<u64, String>") + (substring? option-result-rust "Err((message).clone())")) + #t) + (printf "~%Typed Rust emitter: ~a passed, ~a failed~%" pass fail) (when (> fail 0) (exit 1))