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

Code before:
    // core: & cond ~  (zero succ) ret
    Term::Match { cond, zero, succ } => {
      let if_ = inet.new_node(Mat);

      let cond = encode_term(inet, cond, Port(if_, 0), scope, vars, global_vars, dups, tag_storage);
      link_local(inet, Port(if_, 0), cond);

      let sel = inet.new_node(Con);
      inet.link(Port(sel, 0), Port(if_, 1));

      let zero = encode_term(inet, zero, Port(sel, 1), scope, vars, global_vars, dups, tag_storage);
      link_local(inet, Port(sel, 1), zero);

      let succ = encode_term(inet, succ, Port(sel, 2), scope, vars, global_vars, dups, tag_storage);
      link_local(inet, Port(sel, 2), succ);

      Some(Port(if_, 2))
    }
    // A dup becomes a dup node too. Ports:
    // - 0: points to the value projected.
    // - 1: points to the occurrence of the first variable.
    // - 2: points to the occurrence of the second variable.
    // core: & val ~ {lab fst snd} (val not necessarily main port)
    Term::Dup { fst, snd, val, nxt, tag } => {
      let dup: u32;
      if let Some(tag) = tag {
        dup = tagged_dup(tag_storage, tag.clone(), inet);
      } else {
        dup = inet.new_node(Dup { lab: *dups });
        *dups += 1;
      };

      let val = encode_term(inet, val, Port(dup, 0), scope, vars, global_vars, dups, tag_storage);
      link_local(inet, Port(dup, 0), val);

      push_scope(fst, Port(dup, 1), scope, vars);
      push_scope(snd, Port(dup, 2), scope, vars);
      let nxt = encode_term(inet, nxt, up, scope, vars, global_vars, dups, tag_storage);
      pop_scope(snd, Port(dup, 2), inet, scope);
      pop_scope(fst, Port(dup, 1), inet, scope);

      nxt
    }
    Term::Var { nam } => {
      // We assume this variable to be valid, bound and correctly scoped.
      // This pass must be done before.
      debug_assert!(
        scope.contains_key(nam),
        "Unbound variable {nam}. Expected this check to be already done"
      );
      let var_stack = scope.get(nam).unwrap();

Review comment (suggestion):
I think it would be better to have this part only return the label.
If explicitly tagged and new tag, give a new label.
If explicitly tagged and repeated tag, use the label we decided on before.
If implicitly tagged, use the implicit label counter.

Then we create the dup node and insert it into the inet

Code after:
      let if_ = inet.new_node(Mat);

      let cond = encode_term(inet, cond, Port(if_, 0), scope, vars, global_vars, label_generator);
      link_local(inet, Port(if_, 0), cond);

      let sel = inet.new_node(Con);
      inet.link(Port(sel, 0), Port(if_, 1));

      let zero = encode_term(inet, zero, Port(sel, 1), scope, vars, global_vars, label_generator);
      link_local(inet, Port(sel, 1), zero);

      let succ = encode_term(inet, succ, Port(sel, 2), scope, vars, global_vars, label_generator);
      link_local(inet, Port(sel, 2), succ);

      Some(Port(if_, 2))
    }
    // A dup becomes a dup node too. Ports:
    // - 0: points to the value projected.
    // - 1: points to the occurrence of the first variable.
    // - 2: points to the occurrence of the second variable.
    // core: & val ~ {lab fst snd} (val not necessarily main port)
    Term::Dup { fst, snd, val, nxt, tag } => {
      let lab = label_generator.generate(tag);
      let dup = inet.new_node(Dup { lab });

      let val = encode_term(inet, val, Port(dup, 0), scope, vars, global_vars, label_generator);
      link_local(inet, Port(dup, 0), val);

      push_scope(fst, Port(dup, 1), scope, vars);
      push_scope(snd, Port(dup, 2), scope, vars);
      let nxt = encode_term(inet, nxt, up, scope, vars, global_vars, label_generator);
      pop_scope(snd, Port(dup, 2), inet, scope);
      pop_scope(fst, Port(dup, 1), inet, scope);

      nxt
    }
    Term::Var { nam } => {
      // We assume this variable to be valid, bound and correctly scoped.
      // This pass must be done before.
      debug_assert!(
        scope.contains_key(nam),
        "Unbound variable {nam}. Expected this check to be already done"
      );
      let var_stack = scope.get(nam).unwrap();
      let crnt_var = *var_stack.last().unwrap();
      let (declare_port, use_port) = vars.get_mut(crnt_var).unwrap();
      debug_assert!(use_port.is_none(), "Variable {nam} used more than once");
      inet.link(up, *declare_port);
      *use_port = Some(up);
      Some(*declare_port)
    }