[sc-692] Add simple readback of tuples

This commit is contained in:
Nicolas Abril 2024-05-17 02:04:27 +02:00
parent 163ea65a1b
commit 100cc90aee
8 changed files with 87 additions and 20 deletions

12
Cargo.lock generated
View File

@ -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",

View File

@ -69,6 +69,7 @@ pub struct Reader<'a> {
dup_paths: Option<HashMap<u16, Vec<SlotId>>>,
/// Store for floating/unscoped terms, like dups and let tups.
scope: Scope,
// To avoid reinserting things in the scope.
seen_fans: Scope,
seen: HashSet<Port>,
errors: Vec<ReadbackError>,
@ -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

View File

@ -0,0 +1,4 @@
run
tests/golden_tests/cli/tuple_readback.bend
-Ono-float-combinators
-Aall

View File

@ -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))
)

View File

@ -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))

View File

@ -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)))))

View File

@ -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}\\"

View File

@ -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" "")))))