Repository: HigherOrderCO/Bend
File: src/term/net_to_term.rs (Rust)

Code before:

          (term, true)
        } else {
          (Term::Ref { def_id }, true)
        }
      }
      // If we're visiting a fan node...
      Dup { lab } => match next.slot() {
        // If we're visiting a port 0, then it is a pair.
        0 => {
          let stack = dup_scope.entry(lab).or_default();
          if let Some(slot) = stack.pop() {
            // Since we had a paired Dup in the path to this Sup,
            // we "decay" the superposition according to the original direction we came from the Dup.
            let chosen = net.enter_port(Port(node, slot));
            let (val, valid) = reader(net, chosen, namegen, dup_scope, tup_scope, book);
            dup_scope.get_mut(&lab).unwrap().push(slot);
            (val, valid)
          } else {
            // If no Dup with same label in the path, we can't resolve the Sup, so keep it as a term.
            let fst = net.enter_port(Port(node, 1));
            let snd = net.enter_port(Port(node, 2));
            let (fst, fst_valid) = reader(net, fst, namegen, dup_scope, tup_scope, book);
            let (snd, snd_valid) = reader(net, snd, namegen, dup_scope, tup_scope, book);
            let valid = fst_valid && snd_valid;
            (Term::Sup { tag: None, fst: Box::new(fst), snd: Box::new(snd) }, valid)
          }
        }
        // If we're visiting a port 1 or 2, then it is a variable.
        // Also, that means we found a dup, so we store it to read later.
        1 | 2 => {
          let body = net.enter_port(Port(node, 0));
          dup_scope.entry(lab).or_default().push(next.slot());
          let (body, valid) = reader(net, body, namegen, dup_scope, tup_scope, book);
          dup_scope.entry(lab).or_default().pop().unwrap();
          (body, valid)
        }
        _ => unreachable!(),
      },
      Num { val } => (Term::Num { val }, true),
      Op2 { opr } => match next.slot() {
        2 => {
          let op_port = net.enter_port(Port(node, 0));
          let (fst, fst_valid) = reader(net, op_port, namegen, dup_scope, tup_scope, book);
          let arg_port = net.enter_port(Port(node, 1));
          let (snd, snd_valid) = reader(net, arg_port, namegen, dup_scope, tup_scope, book);
          let valid = fst_valid && snd_valid;

          let term =
            Term::Opx { op: Op::from_hvmc_label(opr).unwrap(), fst: Box::new(fst), snd: Box::new(snd) };


Review comment (suggestion):
Readback of dup tag here. We can check that this label is one of the ones decided by the user and for automatically decided labels we can use the number as the name (since numbers are not valid user-given names).

Code after:
          term.fix_names(&mut namegen.id_counter, book);

          (term, true)
        } else {
          (Term::Ref { def_id }, true)
        }
      }
      // If we're visiting a fan node...
      Dup { lab } => match next.slot() {
        // If we're visiting a port 0, then it is a pair.
        0 => {
          let stack = dup_scope.entry(lab).or_default();
          if let Some(slot) = stack.pop() {
            // Since we had a paired Dup in the path to this Sup,
            // we "decay" the superposition according to the original direction we came from the Dup.
            let chosen = net.enter_port(Port(node, slot));
            let (val, valid) = reader(net, chosen, namegen, dup_scope, tup_scope, labels_to_tag, book);
            dup_scope.get_mut(&lab).unwrap().push(slot);
            (val, valid)
          } else {
            // If no Dup with same label in the path, we can't resolve the Sup, so keep it as a term.
            let fst = net.enter_port(Port(node, 1));
            let snd = net.enter_port(Port(node, 2));
            let (fst, fst_valid) = reader(net, fst, namegen, dup_scope, tup_scope, labels_to_tag, book);
            let (snd, snd_valid) = reader(net, snd, namegen, dup_scope, tup_scope, labels_to_tag, book);
            let valid = fst_valid && snd_valid;
            let tag = labels_to_tag.get(&lab).cloned().unwrap_or_else(|| Name::new("auto"));
            (Term::Sup { tag, fst: Box::new(fst), snd: Box::new(snd) }, valid)
          }
        }
        // If we're visiting a port 1 or 2, then it is a variable.
        // Also, that means we found a dup, so we store it to read later.
        1 | 2 => {
          let body = net.enter_port(Port(node, 0));
          dup_scope.entry(lab).or_default().push(next.slot());
          let (body, valid) = reader(net, body, namegen, dup_scope, tup_scope, labels_to_tag, book);
          dup_scope.entry(lab).or_default().pop().unwrap();
          (body, valid)
        }
        _ => unreachable!(),
      },
      Num { val } => (Term::Num { val }, true),
      Op2 { opr } => match next.slot() {
        2 => {
          let op_port = net.enter_port(Port(node, 0));
          let (fst, fst_valid) = reader(net, op_port, namegen, dup_scope, tup_scope, labels_to_tag, book);
          let arg_port = net.enter_port(Port(node, 1));
          let (snd, snd_valid) = reader(net, arg_port, namegen, dup_scope, tup_scope, labels_to_tag, book);
          let valid = fst_valid && snd_valid;

          let term =