diff --git a/cspell.json b/cspell.json index 235d09b1..543648db 100644 --- a/cspell.json +++ b/cspell.json @@ -85,6 +85,7 @@ "scopeless", "scrutinee", "snil", + "SOTA", "stdext", "struct", "subcmd", diff --git a/src/fun/transform/mod.rs b/src/fun/transform/mod.rs index eb5762c4..a698bb5a 100644 --- a/src/fun/transform/mod.rs +++ b/src/fun/transform/mod.rs @@ -16,4 +16,5 @@ pub mod float_combinators; pub mod linearize_matches; pub mod linearize_vars; pub mod resolve_refs; +pub mod resugar_string; pub mod unique_names; diff --git a/src/fun/transform/resugar_string.rs b/src/fun/transform/resugar_string.rs new file mode 100644 index 00000000..2d64fe39 --- /dev/null +++ b/src/fun/transform/resugar_string.rs @@ -0,0 +1,125 @@ +use crate::{ + fun::{builtins, Num, Pattern, Tag, Term}, + maybe_grow, +}; + +impl Term { + /// Converts lambda-encoded strings ending with String/nil to a string literals. + pub fn resugar_strings(&mut self) { + maybe_grow(|| { + // Search for a String/cons pattern in the term and try to build a string from that point on. + // If successful, replace the term with the string. + // If not, keep as-is. + match self { + // Nil: String/nil + Term::Ref { nam } if nam == builtins::SNIL => *self = Term::str(""), + // Cons: @a @* (a ) + Term::Lam { + tag: Tag::Static, + pat: box Pattern::Var(Some(nam_cons_lam)), + bod: + box Term::Lam { + tag: Tag::Static, + pat: box Pattern::Var(None), + bod: + box Term::App { + tag: Tag::Static, + fun: + box Term::App { + tag: Tag::Static, + fun: box Term::Var { nam: nam_cons_app }, + arg: box Term::Num { val: Num::U24(c) }, + }, + arg: nxt, + }, + }, + } if nam_cons_lam == nam_cons_app => { + let head = char::from_u32(*c).unwrap_or('.'); + if let Some(str) = build_string(nxt, head.to_string()) { + *self = Term::str(&str); + } else { + // Not a string term, keep as-is. + } + } + // Cons: (String/cons ) + Term::App { + tag: Tag::Static, + fun: + box Term::App { + tag: Tag::Static, + fun: box Term::Ref { nam }, + arg: box Term::Num { val: Num::U24(c) }, + }, + arg: nxt, + } if nam == builtins::SCONS => { + let head = char::from_u32(*c).unwrap_or('.'); + if let Some(str) = build_string(nxt, head.to_string()) { + *self = Term::str(&str); + } else { + // Not a string term, keep as-is. + } + } + _ => (), + } + + for child in self.children_mut() { + child.resugar_strings(); + } + }) + } +} + +fn build_string(term: &Term, mut s: String) -> Option { + maybe_grow(|| { + match term { + // Nil: String/nil + Term::Ref { nam } if nam == builtins::SNIL => Some(s), + // Cons: @a @* (a ) + Term::Lam { + tag: Tag::Static, + pat: box Pattern::Var(Some(nam_cons_lam)), + bod: + box Term::Lam { + tag: Tag::Static, + pat: box Pattern::Var(None), + bod: + box Term::App { + tag: Tag::Static, + fun: + box Term::App { + tag: Tag::Static, + fun: box Term::Var { nam: nam_cons_app }, + arg: box Term::Num { val: Num::U24(c) }, + }, + arg: nxt, + }, + }, + } if nam_cons_lam == nam_cons_app => { + // New string character, append and recurse + let head = char::from_u32(*c).unwrap_or('.'); + s.push(head); + build_string(nxt, s) + } + // Cons: (String/cons ) + Term::App { + tag: Tag::Static, + fun: + box Term::App { + tag: Tag::Static, + fun: box Term::Ref { nam }, + arg: box Term::Num { val: Num::U24(c) }, + }, + arg: nxt, + } if nam == builtins::SCONS => { + // New string character, append and recurse + let head = char::from_u32(*c).unwrap_or('.'); + s.push(head); + build_string(nxt, s) + } + _ => { + // Not a string term, stop + None + } + } + }) +} diff --git a/src/lib.rs b/src/lib.rs index 2002ff89..804db739 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -215,6 +215,7 @@ pub fn readback_hvm_net(net: &Net, book: &Book, labels: &Labels, linear: bool) - let net = hvmc_to_net(net); let mut term = net_to_term(&net, book, labels, linear, &mut diags); term.expand_generated(book); + term.resugar_strings(); (term, diags) } diff --git a/tests/snapshots/cli__run_pretty.bend.snap b/tests/snapshots/cli__run_pretty.bend.snap index e0c942df..ff7d1150 100644 --- a/tests/snapshots/cli__run_pretty.bend.snap +++ b/tests/snapshots/cli__run_pretty.bend.snap @@ -5,8 +5,8 @@ input_file: tests/golden_tests/cli/run_pretty.bend Result: λa switch a = a { 0: λa switch a { - 0: (String/cons 98 (String/cons 97 String/nil)); - _: λ* (String/cons 116 (String/cons 97 String/nil)); + 0: "ba"; + _: λ* "ta"; }; - _: λ* λb λ* (b 97 λc λ* (c 116 λd λ* (d 97 String/nil))); + _: λ* "ata"; } diff --git a/tests/snapshots/run_file__chars.bend.snap b/tests/snapshots/run_file__chars.bend.snap index 0f0fa8dc..6356c380 100644 --- a/tests/snapshots/run_file__chars.bend.snap +++ b/tests/snapshots/run_file__chars.bend.snap @@ -2,4 +2,4 @@ source: tests/golden_tests.rs input_file: tests/golden_tests/run_file/chars.bend --- -λa λ* (a 4660 λb λ* (b 33 λc λ* (c 55 String/nil))) +"ሴ!7" diff --git a/tests/snapshots/run_file__escape_sequences.bend.snap b/tests/snapshots/run_file__escape_sequences.bend.snap index 28e49d87..175c5d83 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 (List/cons (String/cons 10 String/nil) (List/cons (String/cons 13 String/nil) (List/cons (String/cons 9 String/nil) (List/cons (String/cons 0 String/nil) (List/cons (String/cons 34 String/nil) (List/cons (String/cons 39 String/nil) (List/cons (String/cons 2814 String/nil) (List/cons (String/cons 92 String/nil) List/nil))))))))) +λa (Join (List/cons "\n" (List/cons "\r" (List/cons "\t" (List/cons "\0" (List/cons "\"" (List/cons "'" (List/cons "\u{afe}" (List/cons "\\" List/nil))))))))) diff --git a/tests/snapshots/run_file__match_builtins.bend.snap b/tests/snapshots/run_file__match_builtins.bend.snap index 279d5c09..b36e8dfc 100644 --- a/tests/snapshots/run_file__match_builtins.bend.snap +++ b/tests/snapshots/run_file__match_builtins.bend.snap @@ -2,4 +2,4 @@ source: tests/golden_tests.rs input_file: tests/golden_tests/run_file/match_builtins.bend --- -{λa λ* (a 101 λb λ* (b 108 λc λ* (c 108 λd λ* (d 111 String/nil)))) λe λ* (e 119 λf λ* (f 111 λg λ* (g 114 λh λ* (h 108 λi λ* (i 100 String/nil)))))} +{"ello" "world"} diff --git a/tests/snapshots/run_file__match_num_adt_tup_parser.bend.snap b/tests/snapshots/run_file__match_num_adt_tup_parser.bend.snap index 9a9fcdc8..49122f76 100644 --- a/tests/snapshots/run_file__match_num_adt_tup_parser.bend.snap +++ b/tests/snapshots/run_file__match_num_adt_tup_parser.bend.snap @@ -2,4 +2,4 @@ source: tests/golden_tests.rs input_file: tests/golden_tests/run_file/match_num_adt_tup_parser.bend --- -λ* λa (a {λb λ* (b 40 λc λ* (c 43 String/nil)) *}) +λ* λa (a {"(+" *}) diff --git a/tests/snapshots/run_file__nested_list_and_string.bend.snap b/tests/snapshots/run_file__nested_list_and_string.bend.snap index 5b280e8e..6297b1c2 100644 --- a/tests/snapshots/run_file__nested_list_and_string.bend.snap +++ b/tests/snapshots/run_file__nested_list_and_string.bend.snap @@ -2,4 +2,4 @@ source: tests/golden_tests.rs input_file: tests/golden_tests/run_file/nested_list_and_string.bend --- -λa λb λ* (b a λc λ* (c λ* 2 λd λ* (d λe λ* (e λf λ* (f 7 λg λ* (g λh λ* (h 49 λi λ* (i 50 λj λ* (j 51 λk λ* (k 52 String/nil)))) λl λ* (l 9 List/nil))) λm λ* (m a (String/cons * (String/cons 52 (String/cons 50 String/nil))))) List/nil))) +λa λb λ* (b a λc λ* (c λ* 2 λd λ* (d λe λ* (e λf λ* (f 7 λg λ* (g "1234" λl λ* (l 9 List/nil))) λm λ* (m a (String/cons * "42"))) List/nil))) diff --git a/tests/snapshots/run_file__nested_str.bend.snap b/tests/snapshots/run_file__nested_str.bend.snap index 473dfc03..2d096c0a 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 λe λ* (e 97 λf λ* (f 98 String/nil)) λg λ* (g λh λ* (h 99 λi λ* (i 100 String/nil)) String/nil)) +λa λb λc λd λ* (d "ab" λg λ* (g "cd" "")) diff --git a/tests/snapshots/run_file__readback_list_other_ctr.bend.snap b/tests/snapshots/run_file__readback_list_other_ctr.bend.snap index 447dea5d..ac69caf3 100644 --- a/tests/snapshots/run_file__readback_list_other_ctr.bend.snap +++ b/tests/snapshots/run_file__readback_list_other_ctr.bend.snap @@ -2,4 +2,4 @@ source: tests/golden_tests.rs input_file: tests/golden_tests/run_file/readback_list_other_ctr.bend --- -λa λ* (a λb λ* (b 97 λc (c 98 λd λ* (d 99 String/nil))) λe λ* (e 1 λf (f 2 λg λ* (g 3 λh λ* (h 4 List/nil))))) +λa λ* (a λb λ* (b 97 λc (c 98 "c")) λe λ* (e 1 λf (f 2 λg λ* (g 3 λh λ* (h 4 List/nil))))) diff --git a/tests/snapshots/run_file__str_concat.bend.snap b/tests/snapshots/run_file__str_concat.bend.snap index 02648b2c..53c0a32b 100644 --- a/tests/snapshots/run_file__str_concat.bend.snap +++ b/tests/snapshots/run_file__str_concat.bend.snap @@ -2,4 +2,4 @@ source: tests/golden_tests.rs input_file: tests/golden_tests/run_file/str_concat.bend --- -λa λ* (a 104 λb λ* (b 101 λc λ* (c 108 λd λ* (d 108 λe λ* (e 111 λf λ* (f 32 λg λ* (g 119 λh λ* (h 111 λi λ* (i 114 λj λ* (j 108 λk λ* (k 100 String/nil))))))))))) +"hello world" diff --git a/tests/snapshots/run_file__tup_list_strings.bend.snap b/tests/snapshots/run_file__tup_list_strings.bend.snap index 3b66517c..c2137448 100644 --- a/tests/snapshots/run_file__tup_list_strings.bend.snap +++ b/tests/snapshots/run_file__tup_list_strings.bend.snap @@ -2,4 +2,4 @@ source: tests/golden_tests.rs input_file: tests/golden_tests/run_file/tup_list_strings.bend --- -{λa λ* (a {λb λ* (b 102 λc λ* (c 111 λd λ* (d 111 String/nil))) 0} λe λ* (e {λf λ* (f 102 λg λ* (g 111 λh λ* (h 111 String/nil))) 0} λi λ* (i {λj λ* (j 102 λk λ* (k 111 λl λ* (l 111 String/nil))) 1} List/nil))) 4} +{λa λ* (a {"foo" 0} λe λ* (e {"foo" 0} λi λ* (i {"foo" 1} List/nil))) 4} diff --git a/tests/snapshots/run_file__unaplied_str.bend.snap b/tests/snapshots/run_file__unaplied_str.bend.snap index dbeba4c9..581f33ea 100644 --- a/tests/snapshots/run_file__unaplied_str.bend.snap +++ b/tests/snapshots/run_file__unaplied_str.bend.snap @@ -2,4 +2,4 @@ source: tests/golden_tests.rs input_file: tests/golden_tests/run_file/unaplied_str.bend --- -λa λb λc λ* (c a λd λ* (d 98 λe λ* (e 99 λf λ* (f b String/nil)))) +λa λb λc λ* (c a λd λ* (d 98 λe λ* (e 99 λf λ* (f b "")))) diff --git a/tests/snapshots/run_file__world.bend.snap b/tests/snapshots/run_file__world.bend.snap index 1fd873de..48ddea6d 100644 --- a/tests/snapshots/run_file__world.bend.snap +++ b/tests/snapshots/run_file__world.bend.snap @@ -2,4 +2,4 @@ source: tests/golden_tests.rs input_file: tests/golden_tests/run_file/world.bend --- -λa λ* (a 127758 String/nil) +"🌎" diff --git a/tests/snapshots/run_file__wrong_string.bend.snap b/tests/snapshots/run_file__wrong_string.bend.snap index 77eea802..70b3903e 100644 --- a/tests/snapshots/run_file__wrong_string.bend.snap +++ b/tests/snapshots/run_file__wrong_string.bend.snap @@ -2,4 +2,4 @@ source: tests/golden_tests.rs input_file: tests/golden_tests/run_file/wrong_string.bend --- -λa λ* (a λ* 4 λb λ* (b * String/nil)) +λa λ* (a λ* 4 λb λ* (b * ""))