feat: add Ref cells for mutable state (Ref.new, Ref.get, Ref.set, Ref.update)

Implements WISH-013 mutable state primitives. Ref<T> is a mutable container
using existing module call syntax. Supported across interpreter, JS, and C backends.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
2026-02-20 20:01:29 -05:00
parent 78879ca94e
commit 694e4ec999
7 changed files with 247 additions and 3 deletions

View File

@@ -1242,6 +1242,9 @@ impl JsBackend {
if module_name.name == "Map" {
return self.emit_map_operation(&field.name, args);
}
if module_name.name == "Ref" {
return self.emit_ref_operation(&field.name, args);
}
}
}
@@ -1388,6 +1391,11 @@ impl JsBackend {
return self.emit_map_operation(&operation.name, args);
}
// Special case: Ref module operations (not an effect)
if effect.name == "Ref" {
return self.emit_ref_operation(&operation.name, args);
}
// Special case: Html module operations (not an effect)
if effect.name == "Html" {
return self.emit_html_operation(&operation.name, args);
@@ -2486,6 +2494,37 @@ impl JsBackend {
}
}
fn emit_ref_operation(
&mut self,
operation: &str,
args: &[Expr],
) -> Result<String, JsGenError> {
match operation {
"new" => {
let val = self.emit_expr(&args[0])?;
Ok(format!("({{value: {}}})", val))
}
"get" => {
let r = self.emit_expr(&args[0])?;
Ok(format!("({}.value)", r))
}
"set" => {
let r = self.emit_expr(&args[0])?;
let val = self.emit_expr(&args[1])?;
Ok(format!("({}.value = {}, undefined)", r, val))
}
"update" => {
let r = self.emit_expr(&args[0])?;
let f = self.emit_expr(&args[1])?;
Ok(format!("({0}.value = {1}({0}.value), undefined)", r, f))
}
_ => Err(JsGenError {
message: format!("Unknown Ref operation: {}", operation),
span: None,
}),
}
}
/// Emit Html module operations for type-safe HTML construction
fn emit_html_operation(
&mut self,