From 100cc90aeed291a3cad31d75d14210ca4d7c84fa Mon Sep 17 00:00:00 2001 From: Nicolas Abril Date: Fri, 17 May 2024 02:04:27 +0200 Subject: [PATCH] [sc-692] Add simple readback of tuples --- Cargo.lock | 12 ++-- src/fun/net_to_term.rs | 65 ++++++++++++++++--- tests/golden_tests/cli/tuple_readback.args | 4 ++ tests/golden_tests/cli/tuple_readback.bend | 9 +++ .../run_file/escape_sequences.bend | 7 +- tests/snapshots/cli__tuple_readback.bend.snap | 6 ++ .../run_file__escape_sequences.bend.snap | 2 +- .../snapshots/run_file__nested_str.bend.snap | 2 +- 8 files changed, 87 insertions(+), 20 deletions(-) create mode 100644 tests/golden_tests/cli/tuple_readback.args create mode 100644 tests/golden_tests/cli/tuple_readback.bend create mode 100644 tests/snapshots/cli__tuple_readback.bend.snap diff --git a/Cargo.lock b/Cargo.lock index 0cfe8628..799108cb 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -178,9 +178,9 @@ dependencies = [ [[package]] name = "either" -version = "1.11.0" +version = "1.12.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a47c1c47d2f5964e29c61246e81db715514cd532db6b5116a25ea3c03d6780a2" +checksum = "3dca9240753cf90908d7e4aac30f630662b02aebaa1b58a3cadabdb23385b58b" [[package]] name = "encode_unicode" @@ -278,9 +278,9 @@ checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646" [[package]] name = "libc" -version = "0.2.154" +version = "0.2.153" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ae743338b92ff9146ce83992f766a31066a91a8c84a45e0e9f21e7cf6de6d346" +checksum = "9c198f91728a82281a64e1f4f9eeb25d82cb32a5de251c6bd1b5154d63a8e7bd" [[package]] name = "linked-hash-map" @@ -423,9 +423,9 @@ checksum = "7da8b5736845d9f2fcb837ea5d9e2628564b3b043a70948a3f0b778838c5fb4f" [[package]] name = "syn" -version = "2.0.63" +version = "2.0.64" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bf5be731623ca1a1fb7d8be6f261a3be6d3e2337b8a1f97be944d020c8fcb704" +checksum = "7ad3dee41f36859875573074334c200d1add8e4a87bb37113ebd31d926b7b11f" dependencies = [ "proc-macro2", "quote", diff --git a/src/fun/net_to_term.rs b/src/fun/net_to_term.rs index fd15cd6a..f422ac7d 100644 --- a/src/fun/net_to_term.rs +++ b/src/fun/net_to_term.rs @@ -69,6 +69,7 @@ pub struct Reader<'a> { dup_paths: Option>>, /// Store for floating/unscoped terms, like dups and let tups. scope: Scope, + // To avoid reinserting things in the scope. seen_fans: Scope, seen: HashSet, errors: Vec, @@ -79,7 +80,7 @@ impl Reader<'_> { use CtrKind::*; maybe_grow(|| { - if self.dup_paths.is_none() && !self.seen.insert(next) { + if !self.seen.insert(next) && self.dup_paths.is_none() { self.error(ReadbackError::Cyclic); return Term::Var { nam: Name::new("...") }; } @@ -93,14 +94,22 @@ impl Reader<'_> { } // If we're visiting a con node... NodeKind::Ctr(CtrKind::Con(lab)) => match next.slot() { - // If we're visiting a port 0, then it is a lambda. + // If we're visiting a port 0, then it is a tuple or a lambda. 0 => { - let nam = self.namegen.decl_name(self.net, Port(node, 1)); - let bod = self.read_term(self.net.enter_port(Port(node, 2))); - Term::Lam { - tag: self.labels.con.to_tag(*lab), - pat: Box::new(Pattern::Var(nam)), - bod: Box::new(bod), + if self.is_tup(node) { + // A tuple + let lft = self.read_term(self.net.enter_port(Port(node, 1))); + let rgt = self.read_term(self.net.enter_port(Port(node, 2))); + Term::Fan { fan: FanKind::Tup, tag: self.labels.con.to_tag(*lab), els: vec![lft, rgt] } + } else { + // A lambda + let nam = self.namegen.decl_name(self.net, Port(node, 1)); + let bod = self.read_term(self.net.enter_port(Port(node, 2))); + Term::Lam { + tag: self.labels.con.to_tag(*lab), + pat: Box::new(Pattern::Var(nam)), + bod: Box::new(bod), + } } } // If we're visiting a port 1, then it is a variable. @@ -332,8 +341,8 @@ impl Reader<'_> { } } - /// Enters both ports 1 and 2 of a node, - /// Returning a Term if is possible to simplify the net, or the Terms on the two ports of the node. + /// Enters both ports 1 and 2 of a node. Returns a Term if it is + /// possible to simplify the net, or the Terms on the two ports of the node. /// The two possible outcomes are always equivalent. /// /// If: @@ -404,6 +413,42 @@ impl Reader<'_> { diagnostics.add_diagnostic(msg.as_str(), Severity::Warning, DiagnosticOrigin::Readback); } } + + /// Returns whether the given port represents a tuple or some other + /// term (usually a lambda). + /// + /// Used heuristic: a con node is a tuple if port 1 is a closed net and not an ERA. + fn is_tup(&self, node: NodeId) -> bool { + if !matches!(self.net.node(node).kind, NodeKind::Ctr(CtrKind::Con(_))) { + return false; + } + if self.net.node(self.net.enter_port(Port(node, 1)).node()).kind == NodeKind::Era { + return false; + } + let mut wires = HashSet::new(); + let mut to_check = vec![self.net.enter_port(Port(node, 1))]; + while let Some(port) = to_check.pop() { + match port.slot() { + 0 => { + let node = port.node(); + let lft = self.net.enter_port(Port(node, 1)); + let rgt = self.net.enter_port(Port(node, 2)); + to_check.push(lft); + to_check.push(rgt); + } + 1 | 2 => { + // Mark as a wire. If already present, mark as visited by removing it. + if !(wires.insert(port) && wires.insert(self.net.enter_port(port))) { + wires.remove(&port); + wires.remove(&self.net.enter_port(port)); + } + } + _ => unreachable!(), + } + } + // No hanging wires = a combinator = a tuple + wires.is_empty() + } } /// Argument for a Opr node diff --git a/tests/golden_tests/cli/tuple_readback.args b/tests/golden_tests/cli/tuple_readback.args new file mode 100644 index 00000000..cb99fc90 --- /dev/null +++ b/tests/golden_tests/cli/tuple_readback.args @@ -0,0 +1,4 @@ +run +tests/golden_tests/cli/tuple_readback.bend +-Ono-float-combinators +-Aall diff --git a/tests/golden_tests/cli/tuple_readback.bend b/tests/golden_tests/cli/tuple_readback.bend new file mode 100644 index 00000000..44c894cd --- /dev/null +++ b/tests/golden_tests/cli/tuple_readback.bend @@ -0,0 +1,9 @@ +# We probably will not be able to handle all these +main = ( + @a (1, a), + (1, 2), + (*, 2), + ($x, @$x *), + ((1, @$y $z), (2, @$z $y)), + ((@$a $b, @$b $c), (@$c $d, @$d $a)) +) \ No newline at end of file diff --git a/tests/golden_tests/run_file/escape_sequences.bend b/tests/golden_tests/run_file/escape_sequences.bend index 95db44da..f224a63e 100644 --- a/tests/golden_tests/run_file/escape_sequences.bend +++ b/tests/golden_tests/run_file/escape_sequences.bend @@ -7,6 +7,9 @@ String/from_list (List/Cons x xs) = (String/Cons x (String/from_list xs)) (Join List/Nil) = "" (Join (List/Cons x xs)) = (Concat x (Join xs)) +(Expand xs) = fold xs { String/Nil: xs; String/Cons: xs } + main = - ((String/from_list ['\n', '\r', '\t', '\0', '\"', '\'', '\u{AFE}', '\\']) - , (Join ["\n", "\r", "\t", "\0", "\"", "\'", "\u{AFE}", "\\"])) + let a = (String/from_list ['\n', '\r', '\t', '\0', '\"', '\'', '\u{AFE}', '\\']) + let b = (Join ["\n", "\r", "\t", "\0", "\"", "\'", "\u{AFE}", "\\"]) + (Expand (Concat a b)) diff --git a/tests/snapshots/cli__tuple_readback.bend.snap b/tests/snapshots/cli__tuple_readback.bend.snap new file mode 100644 index 00000000..c0b936b1 --- /dev/null +++ b/tests/snapshots/cli__tuple_readback.bend.snap @@ -0,0 +1,6 @@ +--- +source: tests/golden_tests.rs +input_file: tests/golden_tests/cli/tuple_readback.bend +--- +Warning: Running in strict mode without enabling the float_combinators pass can lead to some functions expanding infinitely. +Result: (λa (1, a), ((1, 2), (λ* 2, (λb λc *, (λd (2, λe $f), λg λh λi $j))))) diff --git a/tests/snapshots/run_file__escape_sequences.bend.snap b/tests/snapshots/run_file__escape_sequences.bend.snap index 19e2095a..bb08a938 100644 --- a/tests/snapshots/run_file__escape_sequences.bend.snap +++ b/tests/snapshots/run_file__escape_sequences.bend.snap @@ -2,4 +2,4 @@ source: tests/golden_tests.rs input_file: tests/golden_tests/run_file/escape_sequences.bend --- -λa (Join ["\n", "\r", "\t", "\0", "\"", "'", "\u{afe}", "\\"]) +"\n\r\t\0\"'\u{afe}\\\n\r\t\0\"'\u{afe}\\" diff --git a/tests/snapshots/run_file__nested_str.bend.snap b/tests/snapshots/run_file__nested_str.bend.snap index 2d096c0a..7db4d7e8 100644 --- a/tests/snapshots/run_file__nested_str.bend.snap +++ b/tests/snapshots/run_file__nested_str.bend.snap @@ -2,4 +2,4 @@ source: tests/golden_tests.rs input_file: tests/golden_tests/run_file/nested_str.bend --- -λa λb λc λd λ* (d "ab" λg λ* (g "cd" "")) +((String/Cons "a" ""), (λa λ* (a 97 λb λ* (b "bc" "")), (λe λ* (e "ab" "c"), λi λ* (i "ab" λl λ* (l "cd" "")))))