The temporary and the reference to it come back together, so they cannot drift

This commit is contained in:
Joseph Ferano 2026-09-12 03:44:16 +07:00
parent f7009fcd34
commit 0b8564828b

View File

@ -375,6 +375,15 @@ and bindings f (items : Form.t list) : Ast.binding list =
(* ── Destructuring ─────────────────────────────────────────────────── *) (* ── Destructuring ─────────────────────────────────────────────────── *)
(* The temporary every pattern binds its value to before anything reads it, so
that the value is evaluated once however many names come out of it. Returning
the reference as well as the binding is what makes the two impossible to
separate by accident. *)
and temp (p : Form.t) (v : Ast.expr) : Ast.expr * Ast.binding =
let t = fresh_temp () in
({ Ast.e = Ast.Var t; loc = p.loc },
{ Ast.bname = t; bty = None; bval = v; bloc = p.loc })
(* Clojure's destructuring, desugared here into the bindings and field accesses (* Clojure's destructuring, desugared here into the bindings and field accesses
the language already has. [Ast.binding] carries a name and nothing else, and the language already has. [Ast.binding] carries a name and nothing else, and
deliberately so: nothing downstream not [Load]'s renaming, not [Check], not deliberately so: nothing downstream not [Load]'s renaming, not [Check], not
@ -393,12 +402,8 @@ and destructure (p : Form.t) (v : Ast.expr) : Ast.binding list =
(* The value goes into a temporary first, so it is evaluated once however (* The value goes into a temporary first, so it is evaluated once however
many names the pattern binds, and so that [(let [{:keys [p]} p] ...)] many names the pattern binds, and so that [(let [{:keys [p]} p] ...)]
reads the old [p] rather than the one it is in the middle of rebinding. *) reads the old [p] rather than the one it is in the middle of rebinding. *)
| Map items -> | Map items -> let t, bind = temp p v in bind :: dmap p t items
let t = fresh_temp () in | Vec items -> let t, bind = temp p v in bind :: dvec p t items
{ Ast.bname = t; bty = None; bval = v; bloc = p.loc } :: dmap p t items
| Vec items ->
let t = fresh_temp () in
{ Ast.bname = t; bty = None; bval = v; bloc = p.loc } :: dvec p t items
| _ -> | _ ->
fail p fail p
"expected a name or a destructuring pattern, found %s — a pattern is \ "expected a name or a destructuring pattern, found %s — a pattern is \
@ -410,9 +415,9 @@ and destructure (p : Form.t) (v : Ast.expr) : Ast.binding list =
the pair form is what nests, since a [:keys] entry is a name and never a the pair form is what nests, since a [:keys] entry is a name and never a
pattern. Everything else Clojure puts in this position [:as], [:or], pattern. Everything else Clojure puts in this position [:as], [:or],
[:strs], [:syms] is refused by name where it is written. *) [:strs], [:syms] is refused by name where it is written. *)
and dmap (p : Form.t) (t : string) (items : Form.t list) : Ast.binding list = and dmap (p : Form.t) (t : Ast.expr) (items : Form.t list) : Ast.binding list =
let ex loc e : Ast.expr = { Ast.e; loc } in let ex loc e : Ast.expr = { Ast.e; loc } in
let field loc name = ex loc (Ast.Field (ex loc (Ast.Var t), name)) in let field loc name = ex loc (Ast.Field (t, name)) in
let rec go = function let rec go = function
| [] -> [] | [] -> []
| { v = Kw "keys"; _ } :: names :: rest -> | { v = Kw "keys"; _ } :: names :: rest ->
@ -460,7 +465,7 @@ and dmap (p : Form.t) (t : string) (items : Form.t list) : Ast.binding list =
else go items else go items
(* [a b] and [a b & rest], over a fixed array. Not over a slice: see [Check]. *) (* [a b] and [a b & rest], over a fixed array. Not over a slice: see [Check]. *)
and dvec (p : Form.t) (t : string) (items : Form.t list) : Ast.binding list = and dvec (p : Form.t) (t : Ast.expr) (items : Form.t list) : Ast.binding list =
let ex loc e : Ast.expr = { Ast.e; loc } in let ex loc e : Ast.expr = { Ast.e; loc } in
let var loc n = ex loc (Ast.Var n) in let var loc n = ex loc (Ast.Var n) in
let rec split acc = function let rec split acc = function
@ -491,7 +496,7 @@ and dvec (p : Form.t) (t : string) (items : Form.t list) : Ast.binding list =
let nth i = let nth i =
ex p.loc ex p.loc
(Ast.Call (var p.loc "destructure~nth", (Ast.Call (var p.loc "destructure~nth",
[ var p.loc t; [ t;
ex p.loc (Ast.Int (Int64.of_int i)); ex p.loc (Ast.Int (Int64.of_int i));
ex p.loc (Ast.Int (Int64.of_int n)); ex p.loc (Ast.Int (Int64.of_int n));
ex p.loc (Ast.Int exact) ])) ex p.loc (Ast.Int exact) ]))
@ -518,10 +523,9 @@ and dvec (p : Form.t) (t : string) (items : Form.t list) : Ast.binding list =
bval = bval =
ex r.loc ex r.loc
(Ast.Call (var r.loc "slice", (Ast.Call (var r.loc "slice",
[ var r.loc t; [ t;
ex r.loc (Ast.Int (Int64.of_int n)); ex r.loc (Ast.Int (Int64.of_int n));
ex r.loc (Ast.Call (var r.loc "len", ex r.loc (Ast.Call (var r.loc "len", [ t ])) ])) } ]
[ var r.loc t ])) ])) } ]
in in
each 0 elems @ rest_binding each 0 elems @ rest_binding