The temporary and the reference to it come back together, so they cannot drift
This commit is contained in:
parent
f7009fcd34
commit
0b8564828b
30
lib/parse.ml
30
lib/parse.ml
@ -375,6 +375,15 @@ and bindings f (items : Form.t list) : Ast.binding list =
|
||||
|
||||
(* ── 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
|
||||
the language already has. [Ast.binding] carries a name and nothing else, and
|
||||
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
|
||||
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. *)
|
||||
| Map items ->
|
||||
let t = fresh_temp () in
|
||||
{ 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
|
||||
| Map items -> let t, bind = temp p v in bind :: dmap p t items
|
||||
| Vec items -> let t, bind = temp p v in bind :: dvec p t items
|
||||
| _ ->
|
||||
fail p
|
||||
"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
|
||||
pattern. Everything else Clojure puts in this position — [:as], [:or],
|
||||
[: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 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
|
||||
| [] -> []
|
||||
| { 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
|
||||
|
||||
(* [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 var loc n = ex loc (Ast.Var n) in
|
||||
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 =
|
||||
ex p.loc
|
||||
(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 n));
|
||||
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 =
|
||||
ex r.loc
|
||||
(Ast.Call (var r.loc "slice",
|
||||
[ var r.loc t;
|
||||
[ t;
|
||||
ex r.loc (Ast.Int (Int64.of_int n));
|
||||
ex r.loc (Ast.Call (var r.loc "len",
|
||||
[ var r.loc t ])) ])) } ]
|
||||
ex r.loc (Ast.Call (var r.loc "len", [ t ])) ])) } ]
|
||||
in
|
||||
each 0 elems @ rest_binding
|
||||
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user