Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

#512 Put constructor tags behind a reference in num scott adt encoding #518

Merged
Show file tree
Hide file tree
Changes from 3 commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
name = "bend-lang"
description = "A high-level, massively parallel programming language"
license = "Apache-2.0"
version = "0.2.24"
version = "0.2.25"
edition = "2021"
rust-version = "1.74"
exclude = ["tests/snapshots/"]
Expand Down
4 changes: 4 additions & 0 deletions src/fun/builtins.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,8 @@ pub const LIST: &str = "List";
pub const LCONS: &str = "List/Cons";
pub const LNIL: &str = "List/Nil";
pub const LCONS_TAG: u32 = 1;
pub const LNIL_TAG_REF: &str = "List/Nil/tag";
pub const LCONS_TAG_REF: &str = "List/Cons/tag";

pub const HEAD: &str = "head";
pub const TAIL: &str = "tail";
Expand All @@ -15,6 +17,8 @@ pub const STRING: &str = "String";
pub const SCONS: &str = "String/Cons";
pub const SNIL: &str = "String/Nil";
pub const SCONS_TAG: u32 = 1;
pub const SNIL_TAG_REF: &str = "String/Nil/tag";
pub const SCONS_TAG_REF: &str = "String/Cons/tag";

pub const NAT: &str = "Nat";
pub const NAT_SUCC: &str = "Nat/Succ";
Expand Down
35 changes: 28 additions & 7 deletions src/fun/transform/encode_adts.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,13 +7,31 @@ impl Book {
/// Defines a function for each constructor in each ADT in the book.
pub fn encode_adts(&mut self, adt_encoding: AdtEncoding) {
let mut defs = vec![];
for adt in self.adts.values() {
let mut tags = vec![];

for (adt_name, adt) in self.adts.iter() {
for (ctr_idx, (ctr_name, fields)) in adt.ctrs.iter().enumerate() {
let ctrs: Vec<_> = adt.ctrs.keys().cloned().collect();

let body = match adt_encoding {
AdtEncoding::Scott => encode_ctr_scott(fields.iter().map(|f| &f.nam), ctrs, ctr_name),
AdtEncoding::NumScott => encode_ctr_num_scott(fields.iter().map(|f| &f.nam), ctr_idx),
AdtEncoding::NumScott => {
let is_object = adt_name == ctr_name;
if is_object {
let tag = Name::new(format!("{ctr_name}/tag"));
let body = encode_ctr_num_scott(fields.iter().map(|f| &f.nam), &tag);
let tag_def = make_tag_def(ctr_idx, &tag, adt);
tags.push((tag, tag_def));
body
} else {
let (typ, ctr) = ctr_name.rsplit_once('/').expect("To split at '/'");
let tag = Name::new(format!("{typ}/{ctr}/tag"));
let body = encode_ctr_num_scott(fields.iter().map(|f| &f.nam), &tag);
let tag_def = make_tag_def(ctr_idx, &tag, adt);
tags.push((tag, tag_def));
body
}
}
};

let rules = vec![Rule { pats: vec![], body }];
Expand All @@ -22,6 +40,7 @@ impl Book {
}
}
self.defs.extend(defs);
self.defs.extend(tags);
}
}

Expand All @@ -36,16 +55,18 @@ fn encode_ctr_scott<'a>(
ctr_args.cloned().rfold(lam, |acc, arg| Term::lam(Pattern::Var(Some(arg)), acc))
}

fn encode_ctr_num_scott<'a>(
ctr_args: impl DoubleEndedIterator<Item = &'a Name> + Clone,
ctr_idx: usize,
) -> Term {
fn encode_ctr_num_scott<'a>(ctr_args: impl DoubleEndedIterator<Item = &'a Name> + Clone, tag: &str) -> Term {
let nam = Name::new("%x");
// λa1 .. λan λx (x TAG a1 .. an)
let term = Term::Var { nam: nam.clone() };
let tag = Term::Num { val: Num::U24(ctr_idx as u32) };
let tag = Term::r#ref(tag);
let term = Term::app(term, tag);
let term = Term::call(term, ctr_args.clone().cloned().map(|nam| Term::Var { nam }));
let term = Term::lam(Pattern::Var(Some(nam)), term);
Term::rfold_lams(term, ctr_args.cloned().map(Some))
}

fn make_tag_def(ctr_idx: usize, tag: &Name, adt: &crate::fun::Adt) -> Definition {
let tag_rule = vec![Rule { pats: vec![], body: Term::Num { val: Num::U24(ctr_idx as u32) } }];
Definition { name: tag.clone(), rules: tag_rule, builtin: adt.builtin }
}
11 changes: 5 additions & 6 deletions src/fun/transform/resugar_list.rs
Original file line number Diff line number Diff line change
@@ -1,8 +1,7 @@
use crate::{
fun::{builtins, Num, Pattern, Tag, Term},
fun::{builtins, Pattern, Tag, Term},
maybe_grow, AdtEncoding,
};
use builtins::LCONS_TAG;

impl Term {
/// Converts lambda-encoded lists ending with List/Nil to list literals.
Expand Down Expand Up @@ -33,8 +32,8 @@ impl Term {
if let Term::App { tag: Tag::Static, fun, arg: head } = fun.as_mut() {
if let Term::App { tag: Tag::Static, fun, arg } = fun.as_mut() {
if let Term::Var { nam: var_app } = fun.as_mut() {
if let Term::Num { val: Num::U24(LCONS_TAG) } = arg.as_mut() {
if var_lam == var_app {
if let Term::Ref { nam } = arg.as_mut() {
if var_lam == var_app && nam == builtins::LCONS_TAG_REF {
let l = build_list_num_scott(tail.as_mut(), vec![std::mem::take(head)]);
match l {
Ok(l) => *self = Term::List { els: l.into_iter().map(|x| *x).collect() },
Expand Down Expand Up @@ -160,8 +159,8 @@ fn build_list_num_scott(term: &mut Term, mut l: Vec<Box<Term>>) -> Result<Vec<Bo
if let Term::App { tag: Tag::Static, fun, arg: head } = fun.as_mut() {
if let Term::App { tag: Tag::Static, fun, arg } = fun.as_mut() {
if let Term::Var { nam: var_app } = fun.as_mut() {
if let Term::Num { val: Num::U24(LCONS_TAG) } = arg.as_mut() {
if var_lam == var_app {
if let Term::Ref { nam } = arg.as_mut() {
if var_lam == var_app && nam == builtins::LCONS_TAG_REF {
// New list element, append and recurse
l.push(std::mem::take(head));
let l = build_list_num_scott(tail, l);
Expand Down
12 changes: 5 additions & 7 deletions src/fun/transform/resugar_string.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,5 @@
use builtins::SCONS_TAG;

use crate::{
fun::{builtins, Num, Pattern, Tag, Term},
fun::{builtins, Name, Num, Pattern, Tag, Term},
maybe_grow, AdtEncoding,
};

Expand Down Expand Up @@ -34,9 +32,9 @@ impl Term {
if let Term::App { tag: Tag::Static, fun, arg: head } = fun.as_mut() {
if let Term::App { tag: Tag::Static, fun, arg } = fun.as_mut() {
if let Term::Var { nam: var_app } = fun.as_mut() {
if let Term::Num { val: Num::U24(SCONS_TAG) } = arg.as_mut() {
if let Term::Ref { nam: Name(nam) } = arg.as_mut() {
if let Term::Num { val: Num::U24(head) } = head.as_mut() {
if var_lam == var_app {
if var_lam == var_app && nam == builtins::SCONS_TAG_REF {
let head = char::from_u32(*head).unwrap_or(char::REPLACEMENT_CHARACTER);
if let Some(str) = build_string_num_scott(tail, head.to_string()) {
*self = Term::str(&str);
Expand Down Expand Up @@ -154,9 +152,9 @@ fn build_string_num_scott(term: &Term, mut s: String) -> Option<String> {
if let Term::App { tag: Tag::Static, fun, arg: head } = fun.as_ref() {
if let Term::App { tag: Tag::Static, fun, arg } = fun.as_ref() {
if let Term::Var { nam: var_app } = fun.as_ref() {
if let Term::Num { val: Num::U24(SCONS_TAG) } = arg.as_ref() {
if let Term::Ref { nam } = arg.as_ref() {
if let Term::Num { val: Num::U24(head) } = head.as_ref() {
if var_lam == var_app {
if var_lam == var_app && nam == builtins::SCONS_TAG_REF {
// New string character, append and recurse
let head = char::from_u32(*head).unwrap_or(char::REPLACEMENT_CHARACTER);
s.push(head);
Expand Down
8 changes: 6 additions & 2 deletions tests/snapshots/cli__compile_strict_loop.bend.snap
Original file line number Diff line number Diff line change
Expand Up @@ -5,9 +5,13 @@ input_file: tests/golden_tests/cli/compile_strict_loop.bend
@A = (((?((0 (* (* (a b)))) c) c) d) d)
& @A ~ (a b)

@List/Cons = (a (b ((1 (a (b c))) c)))
@List/Cons = (a (b ((@List/Cons/tag (a (b c))) c)))

@List/Nil = ((0 a) a)
@List/Cons/tag = 1

@List/Nil = ((@List/Nil/tag a) a)

@List/Nil/tag = 0

@main = c
& @A ~ (b c)
Expand Down
24 changes: 18 additions & 6 deletions tests/snapshots/cli__no_check_net_size.bend.snap
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,17 @@
source: tests/golden_tests.rs
input_file: tests/golden_tests/cli/no_check_net_size.bend
---
@Arr/Leaf = (a ((1 (a b)) b))
@Arr/Leaf = (a ((@Arr/Leaf/tag (a b)) b))

@Arr/Node = (a (b ((2 (a (b c))) c)))
@Arr/Leaf/tag = 1

@Arr/Null = ((0 a) a)
@Arr/Node = (a (b ((@Arr/Node/tag (a (b c))) c)))

@Arr/Node/tag = 2

@Arr/Null = ((@Arr/Null/tag a) a)

@Arr/Null/tag = 0

@Gen = (a b)
& @Gen.go ~ (a (0 b))
Expand All @@ -30,11 +36,17 @@ input_file: tests/golden_tests/cli/no_check_net_size.bend
@Main__C2 = a
& @Sort ~ (@Main__C1 a)

@Map_/Both = (a (b ((2 (a (b c))) c)))
@Map_/Both = (a (b ((@Map_/Both/tag (a (b c))) c)))

@Map_/Both/tag = 2

@Map_/Free = ((@Map_/Free/tag a) a)

@Map_/Free/tag = 0

@Map_/Free = ((0 a) a)
@Map_/Used = ((@Map_/Used/tag a) a)

@Map_/Used = ((1 a) a)
@Map_/Used/tag = 1

@Merge = ((@Merge__C13 a) a)

Expand Down
8 changes: 6 additions & 2 deletions tests/snapshots/compile_file__huge_tree.bend.snap
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,13 @@
source: tests/golden_tests.rs
input_file: tests/golden_tests/compile_file/huge_tree.bend
---
@Tree/Leaf = (a ((1 (a b)) b))
@Tree/Leaf = (a ((@Tree/Leaf/tag (a b)) b))

@Tree/Node = (a (b (c (d ((0 (a (b (c (d e))))) e)))))
@Tree/Leaf/tag = 1

@Tree/Node = (a (b (c (d ((@Tree/Node/tag (a (b (c (d e))))) e)))))

@Tree/Node/tag = 0

@main = e
& @Tree/Node ~ (a (b (c (d e))))
Expand Down
16 changes: 12 additions & 4 deletions tests/snapshots/compile_file__redex_order_recursive.bend.snap
Original file line number Diff line number Diff line change
Expand Up @@ -77,9 +77,13 @@ input_file: tests/golden_tests/compile_file/redex_order_recursive.bend

@List.sum__C1 = (?(((a a) @List.sum__C0) b) b)

@List/Cons = (a (b ((1 (a (b c))) c)))
@List/Cons = (a (b ((@List/Cons/tag (a (b c))) c)))

@List/Nil = ((0 a) a)
@List/Cons/tag = 1

@List/Nil = ((@List/Nil/tag a) a)

@List/Nil/tag = 0

@Tree.flip = ((@Tree.flip__C2 a) a)

Expand Down Expand Up @@ -132,9 +136,13 @@ input_file: tests/golden_tests/compile_file/redex_order_recursive.bend

@Tree.nodes__C1 = (?((@Tree.nodes__C0 (* (* 0))) a) a)

@Tree/leaf = (a ((1 (a b)) b))
@Tree/leaf = (a ((@Tree/leaf/tag (a b)) b))

@Tree/leaf/tag = 1

@Tree/node = (a (b ((@Tree/node/tag (a (b c))) c)))

@Tree/node = (a (b ((0 (a (b c))) c)))
@Tree/node/tag = 0

@add = ((@add__C0 ((a a) b)) b)

Expand Down
16 changes: 12 additions & 4 deletions tests/snapshots/desugar_file__bind_syntax.bend.snap
Original file line number Diff line number Diff line change
Expand Up @@ -10,13 +10,21 @@ input_file: tests/golden_tests/desugar_file/bind_syntax.bend

(Main) = (Result/bind Main__C1 Main__C0)

(String/Nil) = λa (a 0)
(String/Nil) = λa (a String/Nil/tag)

(String/Cons) = λa λb λc (c 1 a b)
(String/Cons) = λa λb λc (c String/Cons/tag a b)

(Result/Ok) = λa λb (b 0 a)
(Result/Ok) = λa λb (b Result/Ok/tag a)

(Result/Err) = λa λb (b 1 a)
(Result/Err) = λa λb (b Result/Err/tag a)

(String/Nil/tag) = 0

(String/Cons/tag) = 1

(Result/Ok/tag) = 0

(Result/Err/tag) = 1

(Main__C0) = λa (Result/bind (safe_rem a 0) λb b)

Expand Down
8 changes: 6 additions & 2 deletions tests/snapshots/desugar_file__combinators.bend.snap
Original file line number Diff line number Diff line change
Expand Up @@ -24,9 +24,13 @@ input_file: tests/golden_tests/desugar_file/combinators.bend

(Main) = list

(List/Nil) = λa (a 0)
(List/Nil) = λa (a List/Nil/tag)

(List/Cons) = λa λb λc (c 1 a b)
(List/Cons) = λa λb λc (c List/Cons/tag a b)

(List/Nil/tag) = 0

(List/Cons/tag) = 1

(A__C0) = let {a b} = A; λc (a b c)

Expand Down
8 changes: 6 additions & 2 deletions tests/snapshots/desugar_file__deref_loop.bend.snap
Original file line number Diff line number Diff line change
Expand Up @@ -8,9 +8,13 @@ input_file: tests/golden_tests/desugar_file/deref_loop.bend

(main) = (foo 0)

(nat/succ) = λa λb (b 0 a)
(nat/succ) = λa λb (b nat/succ/tag a)

(nat/zero) = λa (a 1)
(nat/zero) = λa (a nat/zero/tag)

(nat/succ/tag) = 0

(nat/zero/tag) = 1

(foo__C0) = λ* (bar 0)

Expand Down
4 changes: 3 additions & 1 deletion tests/snapshots/encode_pattern_match__adt_tup_era.bend.snap
Original file line number Diff line number Diff line change
Expand Up @@ -14,4 +14,6 @@ NumScott

(Main) = (Foo (Tuple/Pair 1 5))

(Tuple/Pair) = λa λb λc (c 0 a b)
(Tuple/Pair) = λa λb λc (c Tuple/Pair/tag a b)

(Tuple/Pair/tag) = 0
8 changes: 6 additions & 2 deletions tests/snapshots/encode_pattern_match__and3.bend.snap
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,10 @@ NumScott

(main) = (And (Bool/F, Bool/T, Bool/F))

(Bool/T) = λa (a 0)
(Bool/T) = λa (a Bool/T/tag)

(Bool/F) = λa (a 1)
(Bool/F) = λa (a Bool/F/tag)

(Bool/T/tag) = 0

(Bool/F/tag) = 1
8 changes: 6 additions & 2 deletions tests/snapshots/encode_pattern_match__bool.bend.snap
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,10 @@ NumScott

(and4) = λa (a λb switch b { 0: λc (c λd switch d { 0: bool/true; _: λ* bool/false; }); _: λ* λ* bool/false; })

(bool/true) = λa (a 0)
(bool/true) = λa (a bool/true/tag)

(bool/false) = λa (a 1)
(bool/false) = λa (a bool/false/tag)

(bool/true/tag) = 0

(bool/false/tag) = 1
8 changes: 6 additions & 2 deletions tests/snapshots/encode_pattern_match__bool_tup.bend.snap
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,10 @@ NumScott

(main) = (foo (Bool/F, Bool/T))

(Bool/T) = λa (a 0)
(Bool/T) = λa (a Bool/T/tag)

(Bool/F) = λa (a 1)
(Bool/F) = λa (a Bool/F/tag)

(Bool/T/tag) = 0

(Bool/F/tag) = 1
4 changes: 3 additions & 1 deletion tests/snapshots/encode_pattern_match__box.bend.snap
Original file line number Diff line number Diff line change
Expand Up @@ -10,4 +10,6 @@ Scott
NumScott
(unbox) = λa (a λb switch b { 0: λc c; _: *; })

(box/new) = λa λb (b 0 a)
(box/new) = λa λb (b box/new/tag a)

(box/new/tag) = 0
Loading
Loading