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

Implement Labeled Tuples #1235

Draft
wants to merge 92 commits into
base: dev
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
92 commits
Select commit Hold shift + click to select a range
3d2a351
labeled tuple rewrite
WondAli Feb 23, 2024
6889f4f
Merge branch 'dev' into labeled-tuple-rewrite
WondAli Feb 23, 2024
c137ded
working dot operator + bug fixes to precedence
WondAli Mar 23, 2024
5af500f
may need to revert some tuplabel code since no longer consistent with…
WondAli Mar 31, 2024
9927605
allow for unmatched labels in one direction
WondAli Apr 13, 2024
55500e6
updated casting for labels
WondAli Apr 22, 2024
f08c114
left-associativity for dot operator
WondAli Apr 25, 2024
7ab1470
dot now treats labels as tuples of size 1
WondAli Apr 25, 2024
1cdeb3a
multiple bug fixes and implemented labels as function arguments. TODO…
WondAli Apr 28, 2024
0598c9c
code cleanup, quality improvement. Also fixes to casting (mostly)
WondAli Jun 7, 2024
b3e7c84
casting bug fix
WondAli Jun 7, 2024
dfdf051
merged with dev
WondAli Jun 7, 2024
07275db
minor changes to dot in statics and matching
WondAli Jun 25, 2024
44841b8
standalone labels as singleton tuples + shifting error handling for u…
WondAli Jun 28, 2024
56d9a50
fixed bug concerning rearranging function arguments
WondAli Jul 3, 2024
3d294dd
documentation in progress
WondAli Jul 30, 2024
cbe3125
merge complete
WondAli Jul 31, 2024
e0952df
renamed some variables to be more accurate
WondAli Aug 8, 2024
bf1137c
dot operator update
WondAli Aug 12, 2024
9ab0f49
dot operator static fixes
WondAli Aug 16, 2024
db194f8
Creation of Label term, bug fixes, documentation updates
WondAli Aug 23, 2024
c20706a
fixes to labeled expressions as singleton tuples
WondAli Aug 24, 2024
fe24986
minor test_elaboration update
WondAli Aug 24, 2024
773fa9b
singleton tuple fixes
WondAli Aug 27, 2024
e76f5e2
fix statics to check for mismatched labels
WondAli Aug 27, 2024
a802eb7
fix to let elaboration so that dot operators operate on annotated typ…
WondAli Aug 28, 2024
65eec8e
merge (not working)
WondAli Sep 12, 2024
4753f3f
fix to precedence and cast ground_caes_of
WondAli Sep 13, 2024
cae4bb5
elaborator fixes
WondAli Sep 13, 2024
bc22754
updated parser for dot operator
WondAli Sep 13, 2024
e810400
debug
7h3kk1d Sep 20, 2024
840f06f
Temp commit
7h3kk1d Sep 21, 2024
58fc12c
Add rearrange2
7h3kk1d Sep 21, 2024
2b1eda8
I got some version of elaboration working
7h3kk1d Sep 21, 2024
2be5a46
Fix formatting
7h3kk1d Sep 21, 2024
f7a2666
Cleanup
7h3kk1d Sep 23, 2024
a2c34df
Revert makefile changes
7h3kk1d Sep 23, 2024
50536fe
Cleanup debugging code
7h3kk1d Sep 23, 2024
4226bb4
More cleanup
7h3kk1d Sep 23, 2024
8eef13c
Got a version of evaluation to work
7h3kk1d Sep 23, 2024
998caeb
Stop elaborating labels in Dot
7h3kk1d Sep 27, 2024
000b853
updates to elaboration, label extraction, ap in progress
WondAli Sep 27, 2024
76247f0
merged with labeled-tuple-rewrite
WondAli Sep 27, 2024
8379dec
Missing labeled tuple labels elboration (#1399)
WondAli Sep 27, 2024
d5dfa8f
cleaned LabeledTuple util file
WondAli Sep 27, 2024
7d707c9
Rearranging does not occur past elaboration. Functions reworked to al…
WondAli Sep 29, 2024
20c51f9
Add support for fast_equal on TupLabel expressions
7h3kk1d Oct 2, 2024
49c11d9
Add test for elaboration adding labels to labeled tuples
7h3kk1d Oct 2, 2024
38b10c1
Inline expectation
7h3kk1d Oct 2, 2024
c315caa
Fix typos
7h3kk1d Oct 2, 2024
5707718
Add test for rearranging labels during elaboration
7h3kk1d Oct 2, 2024
e4fb061
Merge remote-tracking branch 'origin/dev' into labeled-tuple-rewrite
7h3kk1d Oct 2, 2024
8d6528e
Add test for labeled tuple projection evaluation
7h3kk1d Oct 2, 2024
a5c83bc
Add statics test for labeled parameter in function
7h3kk1d Oct 2, 2024
f4d778e
Added tests to assure that types are inconsistent when unlabeled vari…
7h3kk1d Oct 4, 2024
32173ea
removed function implicit labelling and rearranging in type consisten…
WondAli Oct 4, 2024
318cfb3
Add basic elaboration tests for singleton tuples
7h3kk1d Oct 11, 2024
c8ef191
Modify singleton labeled tuple elaboration
7h3kk1d Oct 11, 2024
22cd8d6
Add parser tests for singleton tuples
7h3kk1d Oct 11, 2024
f04c976
Wrap all tuplabels in tuples in parser
7h3kk1d Oct 11, 2024
78e817c
Remove is_contained logic
7h3kk1d Oct 11, 2024
7008809
More tests
7h3kk1d Oct 13, 2024
59ff548
Add assertions that there's no static errors in static tests
7h3kk1d Oct 13, 2024
158a62d
Merge branch 'dev' into labeled-tuple-rewrite
7h3kk1d Oct 13, 2024
0669d9c
Ensure more tests are fully consistent
7h3kk1d Oct 13, 2024
c27642b
Stop recalculating statics in tests
7h3kk1d Oct 13, 2024
bcd9fe2
Add support for displaying TupLabel with label and type in view_ty fu…
7h3kk1d Oct 13, 2024
926c5c7
Add labeled tuples doc page
7h3kk1d Oct 14, 2024
5f790cb
revert scratch file
7h3kk1d Oct 14, 2024
39cbba1
Revert init.ml
7h3kk1d Oct 14, 2024
b242321
Add sdocumentation page for labeled tuples
7h3kk1d Oct 14, 2024
de85c69
Tests for multiple labels
7h3kk1d Oct 14, 2024
3c36566
Update Makefile to include dev profile in watch-test
7h3kk1d Oct 14, 2024
72b4cac
Add test case for singleton labeled tuple adding label
7h3kk1d Oct 14, 2024
828da51
Make labeled tuple not need parens in display
7h3kk1d Oct 14, 2024
7688a2b
Add test case for let statement that adds labels during elaboration
7h3kk1d Oct 14, 2024
c86e5f0
Add support for lifting single values into a singleton labeled tuple …
7h3kk1d Oct 14, 2024
dac5119
Refmt
7h3kk1d Oct 14, 2024
3420d2c
Additional test for singleton labels
7h3kk1d Oct 14, 2024
1fa320c
SIngleton labels kind of work
7h3kk1d Oct 14, 2024
c87048d
Remove singleton product from type view
7h3kk1d Oct 14, 2024
01f84c5
Fix the duplicate singleton label statics
7h3kk1d Oct 15, 2024
e018126
Fix stack overflow
7h3kk1d Oct 15, 2024
11804a2
Fix warning in test statics
7h3kk1d Oct 15, 2024
523177e
First attempt singleton labeled tuple elaboration
7h3kk1d Oct 15, 2024
c4db0d0
Remove debug comment
7h3kk1d Oct 16, 2024
03208ff
Fix test
7h3kk1d Oct 16, 2024
0f8521a
More singleton label elaborator fixes
7h3kk1d Oct 16, 2024
1bee9bb
Update init
7h3kk1d Oct 18, 2024
e66dd80
Add tests for singleton labeled argument function application
7h3kk1d Oct 18, 2024
b42c613
Progress on elaborating singleton tuples with mismatched labels
7h3kk1d Oct 21, 2024
9a918ef
Fix warnings
7h3kk1d Oct 21, 2024
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 Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -64,7 +64,7 @@ test:
node $(TEST_DIR)/haz3ltest.bc.js

watch-test:
dune build @fmt @runtest --auto-promote --watch
dune build @fmt @runtest @default --profile dev --auto-promote --watch

clean:
dune clean
290 changes: 290 additions & 0 deletions src/haz3lcore/LabeledTuple.re
Original file line number Diff line number Diff line change
@@ -0,0 +1,290 @@
open Util;

exception Exception;

[@deriving (show({with_path: false}), sexp, yojson)]
type label = string;

let equal: (option((label, 'a)), option((label, 'b))) => bool =
(left, right) => {
switch (left, right) {
| (Some((s1, _)), Some((s2, _))) => String.equal(s1, s2)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Personal note: It would be great if we had map2 from https://ocaml.janestreet.com/ocaml-core/109.20.00/doc/core/Option.html

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This exists in OptUtil

| (_, _) => false
};
};

let length = String.length;

let compare = String.compare;

let find_opt: ('a => bool, list('a)) => option('a) = List.find_opt;

// returns a pair containing a list of option(t) and a list of 'a
// if 'a is a tuplabel, separates the label from the element held by it.
let separate_labels:
('a => option((label, 'a)), list('a)) =>
(list(option(label)), list('a)) =
(get_label, es) => {
let results =
List.fold_left(
((ls, ns), e) =>
switch (get_label(e)) {
| Some((s1, e)) => (ls @ [Some(s1)], ns @ [e])
| None => (ls @ [None], ns @ [e])
},
([], []),
es,
);
results;
};

// returns a pair containing a list of option(t) and a list of 'a
// if 'a is a tuplabel, extracts the label but keeps the tuplabel together
let separate_and_keep_labels:
('a => option((label, 'a)), list('a)) =>
(list(option(label)), list('a)) =
(get_label, es) => {
let results =
List.fold_left(
((ls, ns), e) =>
switch (get_label(e)) {
| Some((s1, _)) => (ls @ [Some(s1)], ns @ [e])
| None => (ls @ [None], ns @ [e])
},
([], []),
es,
);
results;
};

// returns ordered list of (Some(string), TupLabel)
// and another of (None, not-TupLabel)
// TODO: Actually validate uniqueness in statics
// TODO: Make more efficient
// let validate_uniqueness:
// 'a.
// ('a => option((t, 'a)), list('a)) =>
// (bool, list((option(t), 'a)), list('a))
// =
// (get_label, es) => {
// let results =
// List.fold_left(
// ((b, ls, ns), e) =>
// switch (get_label(e)) {
// | Some((s1, _))
// when
// b
// && List.fold_left(
// (v, l) =>
// switch (l) {
// | (Some(s2), _) when v => compare(s1, s2) != 0
// | _ => false
// },
// true,
// ls,
// ) => (
// b,
// ls @ [(Some(s1), e)],
// ns,
// )
// | None => (b, ls, ns @ [e])
// | _ => (false, ls, ns)
// },
// (true, [], []),
// es,
// );
// results;
// };

// TODO consider adding a t = (option(label), 'a)

let separate_labeled = (xs: list((option(label), 'a))) => {
List.partition_map(
((l, a)) =>
switch (l) {
| None => Right(a)
| Some(l) => Left((l, a))
},
xs,
);
};

// TODO Performance
let intersect = (xs, ys) => {
List.filter_map(x => List.find_opt((==)(x), ys), xs);
};

// Assumes all labels are unique
// Rearranges all the labels in l2 to match the order of the labels in l1. Labels are optional and should me reordered for all present labels first and then unlabled fields matched up pairwise. So labeled fields can be reordered and unlabeled ones can't. Also add labels to the unlabeled.
// TODO Handle the unequal length case and extra labels case
let rec rearrange_base:
'b.
(
~show_b: 'b => string=?,
list(option(label)),
list((option(label), 'b))
) =>
list((option(label), 'b))
=
(~show_b=?, l1: list(option(label)), l2: list((option(label), 'b))) => {
let l1_labels = List.filter_map(Fun.id, l1);
let l2_labels = List.filter_map(fst, l2);
let common_labels = intersect(l1_labels, l2_labels);

switch (l1, l2) {
| ([], _) => l2
| (_, []) => []
| ([Some(expected_label), ...remaining_expectations], remaining) =>
let maybe_found = List.assoc_opt(Some(expected_label), remaining);

switch (maybe_found) {
| Some(found) =>
[(Some(expected_label), found)]
@ rearrange_base(
~show_b?,
remaining_expectations,
List.remove_assoc(Some(expected_label), remaining),
)
| None =>
let (
pre: list((option(label), 'b)),
current: option((option(label), 'b)),
post: list((option(label), 'b)),
) =
ListUtil.split(remaining, ((label: option(label), _)) => {
switch (label) {
| Some(label) => !List.mem(label, common_labels)
| None => true
}
});

switch (current) {
| Some((_existing_label, b)) =>
[(Some(expected_label), b)]
@ rearrange_base(~show_b?, remaining_expectations, pre @ post)
| None => remaining
};
};
| ([None, ...remaining_expectations], remaining) =>
// Pick the first one that's not in common labels and then keep the rest in remaining
let (
pre: list((option(label), 'b)),
current: option((option(label), 'b)),
post: list((option(label), 'b)),
) =
ListUtil.split(remaining, ((label: option(label), _)) => {
switch (label) {
| Some(label) => !List.mem(label, common_labels)
| None => true
}
});
switch (current) {
| Some((_existing_label, b)) =>
[(None, b)]
@ rearrange_base(~show_b?, remaining_expectations, pre @ post)
| None => remaining
};
};
};

// Basically another way to call rearrange_base using the raw lists, functions to extract labels from TupLabels, and constructor for new TupLabels.
// Maintains the same ids if possible
// TODO: clean up more
let rearrange:
'a 'b.
(
'a => option((label, 'a)),
'b => option((label, 'b)),
list('a),
list('b),
(label, 'b) => 'b
) =>
list('b)
=
(get_label1, get_label2, l1, l2, constructor) => {
// TODO: Error handling in case of bad arguments
let l1' = fst(separate_and_keep_labels(get_label1, l1));
let (l2_labels, l2_vals) = separate_and_keep_labels(get_label2, l2);
let l2' = List.combine(l2_labels, l2_vals);
let l2_reordered = rearrange_base(l1', l2');
List.map(
((optional_label, b)) =>
switch (optional_label) {
| Some(label) =>
// TODO: probably can keep the same ids in a cleaner way
switch (get_label2(b)) {
| Some(_) => b
| None => constructor(label, b)
}
| None => b
},
l2_reordered,
);
};

// rearrange two other lists to match the first list of labels.
// TODO: Ensure that the two lists match up with each other
// TODO: This function currently exists only to make the elaborator code cleaner. Probably can make more efficient
let rearrange2:
'a 'b.
(
list(option(label)),
'a => option((label, 'a)),
'b => option((label, 'b)),
list('a),
list('b),
(label, 'a) => 'a,
(label, 'b) => 'b
) =>
(list('a), list('b))
=
(labels, get_label1, get_label2, l1, l2, constructor1, constructor2) => {
let (l1_labels, l1_vals) = separate_and_keep_labels(get_label1, l1);
let l1' = List.combine(l1_labels, l1_vals);
let l1_reordered = rearrange_base(labels, l1');
let l1_rearranged =
List.map(
((optional_label, b)) =>
switch (optional_label) {
| Some(label) =>
// TODO: probably can keep the same ids in a cleaner way
switch (get_label1(b)) {
| Some(_) => b
| None => constructor1(label, b)
}
| None => b
},
l1_reordered,
);
let (l2_labels, l2_vals) = separate_and_keep_labels(get_label2, l2);
let l2' = List.combine(l2_labels, l2_vals);
let l2_reordered = rearrange_base(labels, l2');
let l2_rearranged =
List.map(
((optional_label, b)) =>
switch (optional_label) {
| Some(label) =>
// TODO: probably can keep the same ids in a cleaner way
switch (get_label2(b)) {
| Some(_) => b
| None => constructor2(label, b)
}
| None => b
},
l2_reordered,
);
(l1_rearranged, l2_rearranged);
};

let find_label: ('a => option((label, 'a)), list('a), label) => option('a) =
(filt, es, label) => {
find_opt(
e => {
switch (filt(e)) {
| Some((s, _)) => compare(s, label) == 0
| None => false
}
},
es,
);
};
6 changes: 6 additions & 0 deletions src/haz3lcore/dynamics/Casts.re
Original file line number Diff line number Diff line change
Expand Up @@ -58,8 +58,10 @@ let rec ground_cases_of = (ty: Typ.t): ground_cases => {
| Int
| Float
| String
| Label(_)
| Var(_)
| Rec(_)
| TupLabel(_, {term: Unknown(_), _})
| Forall(_, {term: Unknown(_), _})
| Arrow({term: Unknown(_), _}, {term: Unknown(_), _})
| List({term: Unknown(_), _}) => Ground
Expand All @@ -81,6 +83,10 @@ let rec ground_cases_of = (ty: Typ.t): ground_cases => {
| Arrow(_, _) => grounded_Arrow
| Forall(_) => grounded_Forall
| List(_) => grounded_List
| TupLabel(label, _) =>
NotGroundOrHole(
TupLabel(label, Unknown(Internal) |> Typ.temp) |> Typ.temp,
)
| Ap(_) => failwith("type application in dynamics")
};
};
Expand Down
4 changes: 4 additions & 0 deletions src/haz3lcore/dynamics/Constraint.re
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ type t =
| Or(t, t)
| InjL(t)
| InjR(t)
| TupLabel(t, t)
| Pair(t, t);

let rec dual = (c: t): t =>
Expand All @@ -32,6 +33,7 @@ let rec dual = (c: t): t =>
| Or(c1, c2) => And(dual(c1), dual(c2))
| InjL(c1) => Or(InjL(dual(c1)), InjR(Truth))
| InjR(c2) => Or(InjR(dual(c2)), InjL(Truth))
| TupLabel(c1, c2) => TupLabel(dual(c1), dual(c2))
| Pair(c1, c2) =>
Or(
Pair(c1, dual(c2)),
Expand All @@ -55,6 +57,7 @@ let rec truify = (c: t): t =>
| Or(c1, c2) => Or(truify(c1), truify(c2))
| InjL(c) => InjL(truify(c))
| InjR(c) => InjR(truify(c))
| TupLabel(c1, c2) => TupLabel(truify(c1), truify(c2))
| Pair(c1, c2) => Pair(truify(c1), truify(c2))
};

Expand All @@ -74,6 +77,7 @@ let rec falsify = (c: t): t =>
| Or(c1, c2) => Or(falsify(c1), falsify(c2))
| InjL(c) => InjL(falsify(c))
| InjR(c) => InjR(falsify(c))
| TupLabel(c1, c2) => TupLabel(falsify(c1), falsify(c2))
| Pair(c1, c2) => Pair(falsify(c1), falsify(c2))
};

Expand Down
6 changes: 6 additions & 0 deletions src/haz3lcore/dynamics/DHExp.re
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,8 @@ let rec strip_casts =
switch (term_of(exp)) {
/* Leave non-casts unchanged */
| Tuple(_)
| TupLabel(_)
| Dot(_)
| Cons(_)
| ListConcat(_)
| ListLit(_)
Expand All @@ -71,6 +73,7 @@ let rec strip_casts =
| Int(_)
| Float(_)
| String(_)
| Label(_)
| Constructor(_)
| DynamicErrorHole(_)
| Closure(_)
Expand Down Expand Up @@ -126,6 +129,8 @@ let ty_subst = (s: Typ.t, tpat: TPat.t, exp: t): t => {
| Cons(_)
| ListConcat(_)
| Tuple(_)
| TupLabel(_)
| Dot(_)
| Match(_)
| DynamicErrorHole(_)
| Filter(_)
Expand All @@ -139,6 +144,7 @@ let ty_subst = (s: Typ.t, tpat: TPat.t, exp: t): t => {
| Int(_)
| Float(_)
| String(_)
| Label(_)
| FailedCast(_, _, _)
| MultiHole(_)
| Deferral(_)
Expand Down
Loading
Loading