This commit is contained in:
jess 2026-05-30 16:39:53 -07:00
parent 6c3066fa1d
commit c18ee2c226
1 changed files with 72 additions and 5 deletions

View File

@ -182,9 +182,13 @@ fn emit_stmt(out: &mut String, stmt: &Stmt, depth: usize, deps: &mut Vec<Depende
indent(out, depth, &format!("{} = {};", ident(name), rhs)); indent(out, depth, &format!("{} = {};", ident(name), rhs));
} }
Stmt::PathAssign(lhs, expr) => { Stmt::PathAssign(lhs, expr) => {
let lhs_s = emit_expr(lhs, hook)?; let mut steps = Vec::new();
let root = collect_lvalue_path(lhs, &mut steps, hook)?;
let rhs = emit_expr(expr, hook)?; let rhs = emit_expr(expr, hook)?;
indent(out, depth, &format!("v_path_assign(&mut {}, &{});", lhs_s, rhs)); indent(out, depth, &format!(
"v_assign_path(&mut {}, &[{}], {});",
root, steps.join(", "), rhs
));
} }
Stmt::Return(expr) => { Stmt::Return(expr) => {
let rhs = emit_expr(expr, hook)?; let rhs = emit_expr(expr, hook)?;
@ -277,6 +281,25 @@ fn emit_stmt(out: &mut String, stmt: &Stmt, depth: usize, deps: &mut Vec<Depende
Ok(()) Ok(())
} }
/// walks a Field/Index lvalue chain into a root identifier plus emitted Step nodes.
fn collect_lvalue_path(expr: &Expr, steps: &mut Vec<String>, hook: &dyn DecomposeHook) -> Result<String, String> {
match expr {
Expr::Ident(name) => Ok(ident(name)),
Expr::Field(inner, field) => {
let root = collect_lvalue_path(inner, steps, hook)?;
steps.push(format!("Step::Field({:?}.into())", field));
Ok(root)
}
Expr::Index(inner, idx) => {
let root = collect_lvalue_path(inner, steps, hook)?;
let i = emit_expr(idx, hook)?;
steps.push(format!("Step::Index(v_num(&{}) as i64)", i));
Ok(root)
}
_ => Err("assignment target must root at a variable".into()),
}
}
fn emit_expr(expr: &Expr, hook: &dyn DecomposeHook) -> Result<String, String> { fn emit_expr(expr: &Expr, hook: &dyn DecomposeHook) -> Result<String, String> {
if let Some(custom) = hook.expr(expr) { if let Some(custom) = hook.expr(expr) {
return Ok(custom); return Ok(custom);
@ -543,8 +566,31 @@ fn v_field(base: &V, name: &str) -> V {
} }
} }
fn v_field_set(base: &mut V, _val: &V) { enum Step { Field(String), Index(i64) }
let _ = base; // path assignment placeholder
fn v_assign_path(root: &mut V, steps: &[Step], val: V) {
let mut cur = root;
for (i, step) in steps.iter().enumerate() {
let last = i + 1 == steps.len();
match step {
Step::Field(k) => match cur {
V::Struct(m) => {
if last { m.insert(k.clone(), val); return; }
cur = m.entry(k.clone()).or_insert(V::Void);
}
_ => return,
},
Step::Index(idx) => match cur {
V::Array(a) => {
let n = if *idx < 0 { (a.len() as i64 + idx) as usize } else { *idx as usize };
if n >= a.len() { return; }
if last { a[n] = val; return; }
cur = &mut a[n];
}
_ => return,
},
}
}
} }
fn v_iter(val: &V) -> Vec<V> { fn v_iter(val: &V) -> Vec<V> {
@ -555,7 +601,6 @@ fn v_iter(val: &V) -> Vec<V> {
} }
} }
fn v_path_assign(target: &mut V, val: &V) { *target = val.clone(); }
fn v_cell_get(_table: &str, _col: u32, _row: u32) -> V { V::Void } fn v_cell_get(_table: &str, _col: u32, _row: u32) -> V { V::Void }
fn v_cell_range(_table: &str, _c1: u32, _r1: u32, _c2: u32, _r2: u32) -> V { V::Array(Vec::new()) } fn v_cell_range(_table: &str, _c1: u32, _r1: u32, _c2: u32, _r2: u32) -> V { V::Array(Vec::new()) }
fn v_cell_table(_table: &str) -> V { V::Array(Vec::new()) } fn v_cell_table(_table: &str) -> V { V::Array(Vec::new()) }
@ -729,8 +774,17 @@ impl Vec2 {
let a = Vec2::new(1, 2) let a = Vec2::new(1, 2)
let b = Vec2::new(3, 4) let b = Vec2::new(3, 4)
let c = a + b let c = a + b
let p = {x: 1, y: 2}
p.x = 10
let arr = [1, 2, 3]
arr[1] = 20
let node = {pose: {pos: {x: 0}}}
node.pose.pos.x = 5
"; ";
let mut code = dec(src); let mut code = dec(src);
assert!(code.contains("v_assign_path(&mut p"));
assert!(code.contains("v_assign_path(&mut arr"));
assert!(code.contains("v_assign_path(&mut node"));
code.push_str(r#" code.push_str(r#"
fn main() { fn main() {
let a = Vec2__new(V::Num(1.0), V::Num(2.0)); let a = Vec2__new(V::Num(1.0), V::Num(2.0));
@ -740,6 +794,19 @@ fn main() {
assert_eq!(v_field(&c, "y"), V::Num(6.0)); assert_eq!(v_field(&c, "y"), V::Num(6.0));
let l = v_method_call(&a, "len2", &[]); let l = v_method_call(&a, "len2", &[]);
assert_eq!(l, V::Num(5.0)); assert_eq!(l, V::Num(5.0));
let mut p = V::Struct([("x".to_string(), V::Num(1.0))].into_iter().collect());
v_assign_path(&mut p, &[Step::Field("x".into())], V::Num(10.0));
assert_eq!(v_field(&p, "x"), V::Num(10.0));
let mut arr = V::Array(vec![V::Num(1.0), V::Num(2.0), V::Num(3.0)]);
v_assign_path(&mut arr, &[Step::Index(1)], V::Num(20.0));
assert_eq!(v_index(&arr, &V::Num(1.0)), V::Num(20.0));
let mut node = V::Struct([("pose".to_string(), V::Struct([("pos".to_string(), V::Struct([("x".to_string(), V::Num(0.0))].into_iter().collect()))].into_iter().collect()))].into_iter().collect());
v_assign_path(&mut node, &[Step::Field("pose".into()), Step::Field("pos".into()), Step::Field("x".into())], V::Num(5.0));
assert_eq!(v_field(&v_field(&v_field(&node, "pose"), "pos"), "x"), V::Num(5.0));
let _ = run(); let _ = run();
println!("OK"); println!("OK");
} }