summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--README.md56
-rw-r--r--dhall/src/error/mod.rs2
-rw-r--r--dhall/src/phase/normalize.rs19
-rw-r--r--dhall/src/phase/typecheck.rs52
4 files changed, 114 insertions, 15 deletions
diff --git a/README.md b/README.md
index 66748dc..1fe59da 100644
--- a/README.md
+++ b/README.md
@@ -20,6 +20,62 @@ This is still quite unstable so use at your own risk. Documentation is severely
You can see what's missing from the commented out tests in `dhall/src/normalize.rs` and `dhall/src/typecheck.rs`.
+# Contributing
+
+This section will cover how we can get started on contributing this project.
+
+## Setting up the repository
+
+To get a copy of this repository we can run:
+
+```bash
+$ git clone https://github.com/Nadrieril/dhall-rust.git
+```
+
+But we also might note that it's better practice to fork the repository to your own workspace.
+There you can make changes and submit pull requests against this repository.
+
+After the repositry has been cloned we need to update the [git submodule](https://git-scm.com/book/en/v2/Git-Tools-Submodules)
+in the project, i.e. `dhall-lang`. We can do this by running:
+
+```bash
+$ git submodule update --init --recursive
+```
+
+## Building and Testing
+
+A preferred method among the Rust community for developing is to use [`rustup`](https://rustup.rs/).
+
+It can be installed by running:
+
+```bash
+$ curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh
+```
+
+or if [nix](https://nixos.org/) is your tool of choice:
+
+```bash
+$ nix-shell -p rustup
+```
+
+Once `rustup` is installed we can get it to manage our toolchain by running:
+
+```bash
+$ rustup toolchain install nightly
+```
+
+Then we can manage our building and testing with the [`cargo`](https://crates.io/) dependency manager:
+
+```bash
+$ cargo build
+```
+
+```bash
+$ cargo test
+```
+
+Now we can have fun and happy contributing!
+
## License
Licensed under the terms of the 2-Clause BSD License ([LICENSE](LICENSE) or
diff --git a/dhall/src/error/mod.rs b/dhall/src/error/mod.rs
index 2345348..bc5322a 100644
--- a/dhall/src/error/mod.rs
+++ b/dhall/src/error/mod.rs
@@ -80,8 +80,8 @@ pub(crate) enum TypeMessage {
MergeHandlerReturnTypeMustNotBeDependent,
ProjectionMustBeRecord,
ProjectionMissingEntry,
- RecordMismatch(Typed, Typed),
Sort,
+ RecordMismatch(Typed, Typed),
RecordTypeDuplicateField,
UnionTypeDuplicateField,
Unimplemented,
diff --git a/dhall/src/phase/normalize.rs b/dhall/src/phase/normalize.rs
index e3c5d68..7d86833 100644
--- a/dhall/src/phase/normalize.rs
+++ b/dhall/src/phase/normalize.rs
@@ -382,13 +382,13 @@ enum Ret<'a> {
/// * `fu` - Will convert the values of the second map
/// into the target value.
///
-/// * `ftu` - Will convert the key and values from both maps
+/// * `fktu` - Will convert the key and values from both maps
/// into the target type.
///
/// # Description
///
/// If the key is present in both maps then the final value for
-/// that key is computed via the `ftu` function. Otherwise, the
+/// that key is computed via the `fktu` function. Otherwise, the
/// final value will be calculated by either the `ft` or `fu` value
/// depending on which map the key is present in.
///
@@ -397,35 +397,36 @@ enum Ret<'a> {
pub(crate) fn outer_join<K, T, U, V>(
mut ft: impl FnMut(&T) -> V,
mut fu: impl FnMut(&U) -> V,
- mut ftu: impl FnMut(&K, &T, &U) -> V,
+ mut fktu: impl FnMut(&K, &T, &U) -> V,
map1: &HashMap<K, T>,
map2: &HashMap<K, U>,
) -> HashMap<K, V>
where
K: std::hash::Hash + Eq + Clone,
{
- let mut kus = HashMap::new();
+ let mut kvs = HashMap::new();
+
for (k1, t) in map1 {
let v = if let Some(u) = map2.get(k1) {
// The key exists in both maps
// so use all values for computation
- ftu(k1, t, u)
+ fktu(k1, t, u)
} else {
// Key only exists in map1
ft(t)
};
- kus.insert(k1.clone(), v);
+ kvs.insert(k1.clone(), v);
}
for (k1, u) in map2 {
// Insert if key was missing in map1
- kus.entry(k1.clone()).or_insert(fu(u));
+ kvs.entry(k1.clone()).or_insert(fu(u));
}
- kus
+ kvs
}
-fn merge_maps<K, V>(
+pub(crate) fn merge_maps<K, V>(
map1: &HashMap<K, V>,
map2: &HashMap<K, V>,
mut f: impl FnMut(&V, &V) -> V,
diff --git a/dhall/src/phase/typecheck.rs b/dhall/src/phase/typecheck.rs
index c927ae2..9bb0e32 100644
--- a/dhall/src/phase/typecheck.rs
+++ b/dhall/src/phase/typecheck.rs
@@ -598,6 +598,47 @@ fn type_last_layer(
}
Ok(RetTypeOnly(text_type))
}
+ BinOp(RightBiasedRecordMerge, l, r) => {
+ use crate::phase::normalize::merge_maps;
+
+ let l_type = l.get_type()?;
+ let l_kind = l_type.get_type()?;
+ let r_type = r.get_type()?;
+ let r_kind = r_type.get_type()?;
+
+ // Check the equality of kinds.
+ // This is to disallow expression such as:
+ // "{ x = Text } // { y = 1 }"
+ ensure_equal!(
+ l_kind,
+ r_kind,
+ mkerr(RecordMismatch(l.clone(), r.clone())),
+ );
+
+ // Extract the LHS record type
+ let kts_x = match l_type.to_value() {
+ Value::RecordType(kts) => kts,
+ _ => return Err(mkerr(MustCombineRecord(l.clone()))),
+ };
+
+ // Extract the RHS record type
+ let kts_y = match r_type.to_value() {
+ Value::RecordType(kts) => kts,
+ _ => return Err(mkerr(MustCombineRecord(r.clone()))),
+ };
+
+ // Union the two records, prefering
+ // the values found in the RHS.
+ let kts = merge_maps(&kts_x, &kts_y, |_, r_t| r_t.clone());
+
+ // Construct the final record type from the union
+ Ok(RetTypeOnly(tck_record_type(
+ ctx,
+ kts.iter()
+ .map(|(x, v)| Ok((x.clone(), v.to_type()))),
+ )?
+ .into_type()))
+ }
BinOp(RecursiveRecordMerge, l, r) => {
// A recursive function to dig down into
// records of records when merging.
@@ -687,6 +728,7 @@ fn type_last_layer(
NaturalTimes => Natural,
TextAppend => Text,
ListAppend => unreachable!(),
+ RightBiasedRecordMerge => unreachable!(),
RecursiveRecordMerge => unreachable!(),
_ => return Err(mkerr(Unimplemented)),
})?;
@@ -1201,11 +1243,11 @@ mod spec_tests {
// ti_success!(ti_success_unit_RecursiveRecordTypeMergeTwo, "unit/RecursiveRecordTypeMergeTwo");
// ti_success!(ti_success_unit_RecursiveRecordTypeMergeTwoKinds, "unit/RecursiveRecordTypeMergeTwoKinds");
// ti_success!(ti_success_unit_RecursiveRecordTypeMergeTwoTypes, "unit/RecursiveRecordTypeMergeTwoTypes");
- // ti_success!(ti_success_unit_RightBiasedRecordMergeRhsEmpty, "unit/RightBiasedRecordMergeRhsEmpty");
- // ti_success!(ti_success_unit_RightBiasedRecordMergeTwo, "unit/RightBiasedRecordMergeTwo");
- // ti_success!(ti_success_unit_RightBiasedRecordMergeTwoDifferent, "unit/RightBiasedRecordMergeTwoDifferent");
- // ti_success!(ti_success_unit_RightBiasedRecordMergeTwoKinds, "unit/RightBiasedRecordMergeTwoKinds");
- // ti_success!(ti_success_unit_RightBiasedRecordMergeTwoTypes, "unit/RightBiasedRecordMergeTwoTypes");
+ ti_success!(ti_success_unit_RightBiasedRecordMergeRhsEmpty, "unit/RightBiasedRecordMergeRhsEmpty");
+ ti_success!(ti_success_unit_RightBiasedRecordMergeTwo, "unit/RightBiasedRecordMergeTwo");
+ ti_success!(ti_success_unit_RightBiasedRecordMergeTwoDifferent, "unit/RightBiasedRecordMergeTwoDifferent");
+ ti_success!(ti_success_unit_RightBiasedRecordMergeTwoKinds, "unit/RightBiasedRecordMergeTwoKinds");
+ ti_success!(ti_success_unit_RightBiasedRecordMergeTwoTypes, "unit/RightBiasedRecordMergeTwoTypes");
ti_success!(ti_success_unit_SomeTrue, "unit/SomeTrue");
ti_success!(ti_success_unit_Text, "unit/Text");
ti_success!(ti_success_unit_TextLiteral, "unit/TextLiteral");